Estou testando diferentes classificadores em um conjunto de dados em que há 5 classes e cada instância pode pertencer a uma ou mais dessas classes; portanto, estou usando especificamente os classificadores de várias etiquetas do scikit-learn sklearn.multiclass.OneVsRestClassifier
. Agora eu quero executar a validação cruzada usando o sklearn.cross_validation.StratifiedKFold
. Isso produz o seguinte erro:
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
Observe que o treinamento do classificador com vários rótulos não falha, mas a validação cruzada. Como devo executar a validação cruzada para este classificador com vários rótulos?
Também escrevi uma segunda versão que divide o problema em treinamento e validação cruzada de 5 classificadores separados. Isso funciona muito bem.
Aqui está o meu código. A função test_classifier_multilabel
é a que apresenta problemas. test_classifier
é minha outra tentativa (dividir o problema em 5 classificadores e 5 validações 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()
Estou usando o Ubuntu 13.04 e o scikit-learn 0.12. Meus dados estão na forma de duas matrizes (X e Y) que possuem formas (98816, 4) e (98816, 5), ou seja, 4 recursos por instância e 5 rótulos de classe. Os rótulos são 1 ou 0 para indicar a associação nessa classe. Estou usando o formato correto, pois não vejo muita documentação sobre isso?
OneVsRestClassifier
aceita uma matriz 2D (por exemplo,y
no seu código de exemplo) ou uma tupla de listas de rótulos de classe? Eu perguntei porque vi o exemplo de classificação de vários rótulos no scikit-learn agora e vi que amake_multilabel_classification
função retorna uma tupla de listas de rótulos de classe, por exemplo,([2], [0], [0, 2], [0]...)
ao usar 3 classes?metrics.confusion_matrix
produz matrizes de confusão 2x2. Alguma das métricas suporta classificadores com vários rótulos?Você pode querer verificar: Na estratificação de dados com vários rótulos .
Aqui, os autores primeiro contam a idéia simples de amostragem de conjuntos de etiquetas exclusivos e, em seguida, introduzem uma nova abordagem de estratificação iterativa para conjuntos de dados com vários rótulos.
A abordagem da estratificação iterativa é gananciosa.
Para uma visão geral rápida, aqui está o que a estratificação iterativa faz:
Primeiro, eles descobrem quantos exemplos devem ser inseridos em cada uma das dobras em k.
Encontre o número desejado de exemplos por dobra por etiqueta , .j c j iEu j cjEu
A partir do conjunto de dados que ainda será distribuído em dobras k, é identificado o rótulo para o qual o número de exemplos é o mínimo, .D leu Deu
Então, para cada ponto de dados em encontre a dobra para a qual é maximizada (quebre os vínculos aqui). Em outras palavras, significa: qual dobra tem a demanda máxima pelo rótulo ou o mais desequilibrado em relação ao rótulo . k c j k l lDeu k cjk eu eu
Adicione o ponto de dados atual à dobra encontrada na etapa acima, remova o ponto de dados do conjunto de dados original e ajuste os valores de contagem de e continue até que todos os pontos de dados não sejam distribuídos nas dobras.ck c
A idéia principal é primeiro focar nos rótulos que são raros, essa idéia vem da hipótese de que
Para entender como os laços são rompidos e outros detalhes, recomendo a leitura do artigo. Além disso, na seção de experimentos, o que eu entendo é que, dependendo da proporção do conjunto de rótulos / exemplos, pode-se querer usar o conjunto de rótulos exclusivo ou esse método de estratificação iterativa proposto. Para valores mais baixos dessa relação, a distribuição dos rótulos nas dobras é próxima ou melhor em alguns casos, como estratificação iterativa. Para valores mais altos dessa relação, a estratificação iterativa mostra ter mantido melhores distribuições nas dobras.
fonte