Je teste différents classificateurs sur un ensemble de données où il y a 5 classes et chaque instance peut appartenir à une ou plusieurs de ces classes, j'utilise donc spécifiquement les classificateurs multi-étiquettes de scikit-learn sklearn.multiclass.OneVsRestClassifier
. Maintenant, je veux effectuer une validation croisée en utilisant le sklearn.cross_validation.StratifiedKFold
. Cela produit l'erreur suivante:
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
Notez que la formation du classificateur multi-étiquettes ne se bloque pas, mais la validation croisée le fait. Comment dois-je effectuer une validation croisée pour ce classificateur multi-étiquettes?
J'ai également écrit une deuxième version qui décompose le problème en formation et en validation croisée de 5 classificateurs distincts. Cela fonctionne très bien.
Voici mon code. La fonction test_classifier_multilabel
est celle qui pose problème. test_classifier
est mon autre tentative (décomposer le problème en 5 classificateurs et 5 validations croisées).
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()
J'utilise Ubuntu 13.04 et scikit-learn 0.12. Mes données se présentent sous la forme de deux tableaux (X et Y) qui ont des formes (98816, 4) et (98816, 5), soit 4 fonctionnalités par instance et 5 étiquettes de classe. Les étiquettes sont 1 ou 0 pour indiquer l'appartenance à cette classe. Suis-je en utilisant le format correct car je ne vois pas beaucoup de documentation à ce sujet?
OneVsRestClassifier
accepteur accepte-t-il un tableau 2D (par exempley
dans votre exemple de code) ou un tuple de listes d'étiquettes de classe? Je demande parce que j'ai regardé l'exemple de classification multi-étiquettes sur scikit-learn tout à l'heure et j'ai vu que lamake_multilabel_classification
fonction renvoie un tuple de listes d'étiquettes de classe, par exemple([2], [0], [0, 2], [0]...)
lors de l'utilisation de 3 classes?metrics.confusion_matrix
produit des matrices de confusion 2x2. Certaines mesures prennent-elles en charge les classificateurs multi-étiquettes?Vous voudrez peut-être vérifier: Sur la stratification des données multi-étiquettes .
Ici, les auteurs racontent d'abord l'idée simple d'échantillonner à partir de jeux d'étiquettes uniques, puis introduisent une nouvelle approche de stratification itérative pour les jeux de données multi-étiquettes.
L'approche de la stratification itérative est gourmande.
Pour un aperçu rapide, voici ce que fait la stratification itérative:
Ils découvrent d'abord combien d'exemples doivent entrer dans chacun des k-folds.
Trouvez le nombre d'exemples souhaité par pli par étiquette , .je j cjje
A partir de l'ensemble de données qui ne sont pas encore distribués en plis k, l'étiquette est identifiée pour laquelle le nombre d'exemples est le minimum, .l rél
Ensuite, pour chaque point de données dans trouvez le pli pour lequel est maximisé (rompez les liens ici). En d'autres termes, quel pli a la demande maximale pour l'étiquette ou est le plus déséquilibré par rapport à l'étiquette .rél k cjk l l
Ajoutez le point de données actuel au pli trouvé à l'étape ci-dessus, supprimez le point de données du jeu de données d'origine et ajustez les valeurs de comptage de et continuez jusqu'à ce que tous les points de données ne soient pas répartis dans les plis.k c
L'idée principale est de se concentrer d'abord sur les labels qui sont rares, cette idée vient de l'hypothèse que
Pour comprendre comment les liens sont rompus et d'autres détails, je recommanderai de lire le document. De plus, à partir de la section des expériences, ce que je peux comprendre est que, selon le rapport étiquettes / exemples, on peut vouloir utiliser le jeu d'étiquettes unique ou cette méthode de stratification itérative proposée. Pour des valeurs inférieures de ce rapport, la distribution des étiquettes à travers les plis est proche ou meilleure dans quelques cas comme stratification itérative. Pour des valeurs plus élevées de ce rapport, la stratification itérative s'est avérée avoir maintenu de meilleures distributions dans les plis.
la source