Ich teste verschiedene Klassifikatoren in einem Datensatz, in dem es 5 Klassen gibt und jede Instanz zu einer oder mehreren dieser Klassen gehören kann. Daher verwende ich speziell die Multi-Label-Klassifikatoren von scikit-learn sklearn.multiclass.OneVsRestClassifier
. Jetzt möchte ich eine Kreuzvalidierung mit der durchführen sklearn.cross_validation.StratifiedKFold
. Dies erzeugt den folgenden Fehler:
Traceback (most recent call last):
File "mlfromcsv.py", line 93, in <module>
main()
File "mlfromcsv.py", line 77, in main
test_classifier_multilabel(svm.LinearSVC(), X, Y, 'Linear Support Vector Machine')
File "mlfromcsv.py", line 44, in test_classifier_multilabel
scores = cross_validation.cross_val_score(clf_ml, X, Y_list, cv=cv, score_func=metrics.precision_recall_fscore_support, n_jobs=jobs)
File "/usr/lib/pymodules/python2.7/sklearn/cross_validation.py", line 1046, in cross_val_score
X, y = check_arrays(X, y, sparse_format='csr')
File "/usr/lib/pymodules/python2.7/sklearn/utils/validation.py", line 144, in check_arrays
size, n_samples))
ValueError: Found array with dim 5. Expected 98816
Beachten Sie, dass das Training des Multi-Label-Klassifikators nicht zum Absturz führt, die Kreuzvalidierung jedoch. Wie muss ich eine Kreuzvalidierung für diesen Multi-Label-Klassifikator durchführen?
Ich habe auch eine zweite Version geschrieben, die das Problem in Training und Kreuzvalidierung von 5 verschiedenen Klassifikatoren aufteilt. Das funktioniert gut.
Hier ist mein Code. Die Funktion test_classifier_multilabel
ist diejenige, die Probleme gibt. test_classifier
ist mein anderer Versuch (das Problem in 5 Klassifikatoren und 5 Kreuzvalidierungen aufteilen).
import numpy as np
from sklearn import *
from sklearn.multiclass import OneVsRestClassifier
from sklearn.neighbors import KNeighborsClassifier
import time
def test_classifier(clf, X, Y, description, jobs=1):
print '=== Testing classifier {0} ==='.format(description)
for class_idx in xrange(Y.shape[1]):
print ' > Cross-validating for class {:d}'.format(class_idx)
n_samples = X.shape[0]
cv = cross_validation.StratifiedKFold(Y[:,class_idx], 3)
t_start = time.clock()
scores = cross_validation.cross_val_score(clf, X, Y[:,class_idx], cv=cv, score_func=metrics.precision_recall_fscore_support, n_jobs=jobs)
t_end = time.clock();
print 'Cross validation time: {:0.3f}s.'.format(t_end-t_start)
str_tbl_fmt = '{:>15s}{:>15s}{:>15s}{:>15s}{:>15s}'
str_tbl_entry_fmt = '{:0.2f} +/- {:0.2f}'
print str_tbl_fmt.format('', 'Precision', 'Recall', 'F1 score', 'Support')
for (score_class, lbl) in [(0, 'Negative'), (1, 'Positive')]:
mean_precision = scores[:,0,score_class].mean()
std_precision = scores[:,0,score_class].std()
mean_recall = scores[:,1,score_class].mean()
std_recall = scores[:,1,score_class].std()
mean_f1_score = scores[:,2,score_class].mean()
std_f1_score = scores[:,2,score_class].std()
support = scores[:,3,score_class].mean()
print str_tbl_fmt.format(
lbl,
str_tbl_entry_fmt.format(mean_precision, std_precision),
str_tbl_entry_fmt.format(mean_recall, std_recall),
str_tbl_entry_fmt.format(mean_f1_score, std_f1_score),
'{:0.2f}'.format(support))
def test_classifier_multilabel(clf, X, Y, description, jobs=1):
print '=== Testing multi-label classifier {0} ==='.format(description)
n_samples = X.shape[0]
Y_list = [value for value in Y.T]
print 'Y_list[0].shape:', Y_list[0].shape, 'len(Y_list):', len(Y_list)
cv = cross_validation.StratifiedKFold(Y_list, 3)
clf_ml = OneVsRestClassifier(clf)
accuracy = (clf_ml.fit(X, Y).predict(X) != Y).sum()
print 'Accuracy: {:0.2f}'.format(accuracy)
scores = cross_validation.cross_val_score(clf_ml, X, Y_list, cv=cv, score_func=metrics.precision_recall_fscore_support, n_jobs=jobs)
str_tbl_fmt = '{:>15s}{:>15s}{:>15s}{:>15s}{:>15s}'
str_tbl_entry_fmt = '{:0.2f} +/- {:0.2f}'
print str_tbl_fmt.format('', 'Precision', 'Recall', 'F1 score', 'Support')
for (score_class, lbl) in [(0, 'Negative'), (1, 'Positive')]:
mean_precision = scores[:,0,score_class].mean()
std_precision = scores[:,0,score_class].std()
mean_recall = scores[:,1,score_class].mean()
std_recall = scores[:,1,score_class].std()
mean_f1_score = scores[:,2,score_class].mean()
std_f1_score = scores[:,2,score_class].std()
support = scores[:,3,score_class].mean()
print str_tbl_fmt.format(
lbl,
str_tbl_entry_fmt.format(mean_precision, std_precision),
str_tbl_entry_fmt.format(mean_recall, std_recall),
str_tbl_entry_fmt.format(mean_f1_score, std_f1_score),
'{:0.2f}'.format(support))
def main():
nfeatures = 13
nclasses = 5
ncolumns = nfeatures + nclasses
data = np.loadtxt('./feature_db.csv', delimiter=',', usecols=range(ncolumns))
print data, data.shape
X = np.hstack((data[:,0:3], data[:,(nfeatures-1):nfeatures]))
print 'X.shape:', X.shape
Y = data[:,nfeatures:ncolumns]
print 'Y.shape:', Y.shape
test_classifier(svm.LinearSVC(), X, Y, 'Linear Support Vector Machine', jobs=-1)
test_classifier_multilabel(svm.LinearSVC(), X, Y, 'Linear Support Vector Machine')
if __name__ =='__main__':
main()
Ich benutze Ubuntu 13.04 und scikit-learn 0.12. Meine Daten liegen in Form von zwei Arrays (X und Y) mit den Formen (98816, 4) und (98816, 5) vor, dh 4 Features pro Instanz und 5 Klassenbeschriftungen. Die Bezeichnungen sind entweder 1 oder 0, um die Zugehörigkeit zu dieser Klasse anzuzeigen. Verwende ich das richtige Format, da ich nicht viel Dokumentation dazu sehe?
OneVsRestClassifier
akzeptiert das ein 2D-Array (z. B.y
in Ihrem Beispielcode) oder ein Tupel von Listen mit Klassenbeschriftungen? Ich frage, weil ich mir gerade das Beispiel für die Klassifizierung mit mehreren Bezeichnungen auf scikit-learn angesehen habe und festgestellt habe, dass diemake_multilabel_classification
Funktion ein Tupel von Listen mit Klassenbezeichnungen zurückgibt, z. B.([2], [0], [0, 2], [0]...)
wenn 3 Klassen verwendet werden.metrics.confusion_matrix
erzeugt 2x2 Verwirrungsmatrizen. Unterstützt eine der Metriken Multi-Label-Klassifikatoren?Möglicherweise möchten Sie Folgendes überprüfen: Auf die Schichtung von Mehrfachetikettendaten .
Hier erzählen die Autoren zunächst die einfache Idee des Samplings aus eindeutigen Labelsets und führen dann einen neuen Ansatz zur iterativen Schichtung ein von Multi-Label-Datasets ein.
Der Ansatz der iterativen Schichtung ist gierig.
Im Folgenden finden Sie eine kurze Übersicht über die iterative Schichtung:
Zuerst finden sie heraus, wie viele Beispiele in jede der k-Faltungen passen sollten.
Finden Sie die gewünschte Anzahl von Beispielen pro Falteich pro Etikett j , cjich .
Aus dem Datensatz, der noch in k-Faltungen verteilt werden muss, das Etikettl identifiziert wird, für die die Anzahl der Beispiele das Minimum ist, Dl .
Dann für jeden Datenpunkt inDl finde die Falte k für welche cjk maximiert ist (hier Krawatten brechen). Was mit anderen Worten bedeutet: Welche Falte hat die maximale Nachfrage nach Etikettl , oder ist in Bezug auf das Etikett am unausgewogensten l .
Fügen Sie den aktuellen Datenpunkt zum Falz hinzuk Entfernen Sie aus dem obigen Schritt den Datenpunkt aus dem ursprünglichen Datensatz und passen Sie die Zählwerte von an c und fahren Sie fort, bis alle Datenpunkte nicht mehr in den Falten verteilt sind.
Die Hauptidee ist, sich zunächst auf die seltenen Etiketten zu konzentrieren. Diese Idee stammt aus der Hypothese, dass
Um zu verstehen, wie Bindungen gebrochen sind und andere Details, empfehle ich, die Zeitung zu lesen. Aus dem experimentellen Teil kann ich auch entnehmen, dass man je nach dem Verhältnis von Labelset zu Beispielen möglicherweise das auf Unique Labelset basierende oder das vorgeschlagene iterative Stratifizierungsverfahren verwenden möchte. Für niedrigere Werte dieses Verhältnisses ist die Verteilung der Etiketten über die Falten in einigen Fällen als iterative Schichtung eng oder besser. Bei höheren Werten dieses Verhältnisses hat sich gezeigt, dass die iterative Schichtung bessere Verteilungen in den Falten bewahrt hat.
quelle