Estoy probando diferentes clasificadores en un conjunto de datos donde hay 5 clases y cada instancia puede pertenecer a una o más de estas clases, así que estoy usando los clasificadores de etiquetas múltiples de scikit-learn, específicamente sklearn.multiclass.OneVsRestClassifier
. Ahora quiero realizar una validación cruzada usando sklearn.cross_validation.StratifiedKFold
. Esto produce el siguiente error:
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
Tenga en cuenta que el entrenamiento del clasificador de etiquetas múltiples no se bloquea, pero la validación cruzada sí. ¿Cómo debo realizar la validación cruzada para este clasificador de etiquetas múltiples?
También he escrito una segunda versión que divide el problema en capacitación y validación cruzada de 5 clasificadores separados. Esto funciona bien.
Aquí está mi código. La función test_classifier_multilabel
es la que da problemas. test_classifier
es mi otro intento (dividir el problema en 5 clasificadores y 5 validaciones cruzadas).
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()
Estoy usando Ubuntu 13.04 y scikit-learn 0.12. Mis datos tienen la forma de dos matrices (X e Y) que tienen formas (98816, 4) y (98816, 5), es decir, 4 entidades por instancia y 5 etiquetas de clase. Las etiquetas son 1 o 0 para membresía indicada dentro de esa clase. ¿Estoy usando el formato correcto ya que no veo mucha documentación al respecto?
OneVsRestClassifier
acepta una matriz 2D (por ejemplo,y
en su código de ejemplo) o una tupla de listas de etiquetas de clase? Pregunto porque miré el ejemplo de clasificación de etiquetas múltiples en scikit-learn justo ahora y vi que lamake_multilabel_classification
función devuelve una tupla de listas de etiquetas de clase, por ejemplo,([2], [0], [0, 2], [0]...)
cuando se usan 3 clases.metrics.confusion_matrix
produce 2x2 matrices de confusión. ¿Alguna de las métricas admite clasificadores de etiquetas múltiples?Es posible que desee verificar: En la estratificación de datos de etiquetas múltiples .
Aquí los autores primero cuentan la idea simple de tomar muestras de conjuntos de etiquetas únicos y luego introducen un nuevo enfoque de estratificación iterativa para conjuntos de datos de etiquetas múltiples.
El enfoque de la estratificación iterativa es codicioso.
Para una descripción general rápida, esto es lo que hace la estratificación iterativa:
Primero descubren cuántos ejemplos deberían incluirse en cada uno de los k-pliegues.
La idea principal es centrarse primero en las etiquetas que son raras, esta idea proviene de la hipótesis de que
Para entender cómo se rompen los lazos y otros detalles, recomendaré leer el periódico. Además, de la sección de experimentos, lo que puedo entender es que, dependiendo de la relación conjunto de etiquetas / ejemplos, uno podría querer usar el conjunto de etiquetas único o este método de estratificación iterativo propuesto. Para valores más bajos de esta relación, la distribución de las etiquetas entre los pliegues es cercana o mejor en algunos casos como estratificación iterativa. Para valores más altos de esta relación, se muestra que la estratificación iterativa ha mantenido mejores distribuciones en los pliegues.
fuente