2016-03-08 13 views
12

Sto cercando di valutare più algoritmi di apprendimento automatico con sklearn per un paio di parametri (precisione, richiamo, precisione e forse più).Valutazione di più punteggi su sklearn cross_val_score

Per quanto ho capito dalla documentazione here e dal codice sorgente (sto usando sklearn 0.17), la funzione cross_val_score riceve solo uno scorer per ogni esecuzione. Quindi, per il calcolo dei punteggi più, devo:

  1. eseguire più volte
  2. Implementare la mia (in termini di tempo e soggetto a errori) scorer

    ho eseguito più volte con questo codice:

    from sklearn.svm import SVC 
    from sklearn.naive_bayes import GaussianNB 
    from sklearn.tree import DecisionTreeClassifier 
    from sklearn.cross_validation import cross_val_score 
    import time 
    from sklearn.datasets import load_iris 
    
    iris = load_iris() 
    
    models = [GaussianNB(), DecisionTreeClassifier(), SVC()] 
    names = ["Naive Bayes", "Decision Tree", "SVM"] 
    for model, name in zip(models, names): 
        print name 
        start = time.time() 
        for score in ["accuracy", "precision", "recall"]: 
         print score, 
         print " : ", 
         print cross_val_score(model, iris.data, iris.target,scoring=score, cv=10).mean() 
        print time.time() - start 
    

E ottengo questo output:

Naive Bayes 
accuracy : 0.953333333333 
precision : 0.962698412698 
recall : 0.953333333333 
0.0383198261261 
Decision Tree 
accuracy : 0.953333333333 
precision : 0.958888888889 
recall : 0.953333333333 
0.0494720935822 
SVM 
accuracy : 0.98 
precision : 0.983333333333 
recall : 0.98 
0.063080072403 

Quale è ok, ma è lento per i miei dati. Come posso misurare tutti i punteggi?

+0

Vorrei provare ad implementare ciò che 'cross_val_score' sta facendo manualmente – Ryan

+0

Uso di Python 3.6 questo esempio non funziona in quanto i dati di destinazione sono multiclasse ma la media di cross_val_score è impostata su 'binary'. Viene visualizzato il seguente errore: "ValoreErrore: il target è multiclasse ma medio = 'binario'. Scegli un'altra impostazione media." Come potrei risolvere il problema? Non riesco davvero a catalogarlo, vero? –

+0

Ho usato Python 2.7. e sklearn 0.17. Penso che questo errore si verifichi in 0.18. Quale versione sklearn stai usando? –

risposta

14

Dal momento della stesura di questo post scikit-learn ha aggiornato e reso la mia risposta obsoleto, vedere la soluzione molto più pulito di sotto


È possibile scrivere la propria funzione di punteggio per catturare tutti e tre i pezzi di informazioni, tuttavia una funzione di calcolo del punteggio per la convalida incrociata deve solo restituire un numero singolo in scikit-learn (ciò è probabile per motivi di compatibilità). Di seguito è riportato un esempio in cui ciascuno dei punteggi per ogni sezione di convalida incrociata viene stampato sulla console e il valore restituito è solo la somma delle tre metriche. Se si desidera restituire tutti questi valori, è necessario apportare alcune modifiche a cross_val_score (riga 1351 di cross_validation.py) e a _score (riga 1601 o allo stesso file).

from sklearn.svm import SVC 
from sklearn.naive_bayes import GaussianNB 
from sklearn.tree import DecisionTreeClassifier 
from sklearn.cross_validation import cross_val_score 
import time 
from sklearn.datasets import load_iris 
from sklearn.metrics import accuracy_score, precision_score, recall_score 

iris = load_iris() 

models = [GaussianNB(), DecisionTreeClassifier(), SVC()] 
names = ["Naive Bayes", "Decision Tree", "SVM"] 

def getScores(estimator, x, y): 
    yPred = estimator.predict(x) 
    return (accuracy_score(y, yPred), 
      precision_score(y, yPred, pos_label=3, average='macro'), 
      recall_score(y, yPred, pos_label=3, average='macro')) 

def my_scorer(estimator, x, y): 
    a, p, r = getScores(estimator, x, y) 
    print a, p, r 
    return a+p+r 

for model, name in zip(models, names): 
    print name 
    start = time.time() 
    m = cross_val_score(model, iris.data, iris.target,scoring=my_scorer, cv=10).mean() 
    print '\nSum:',m, '\n\n' 
    print 'time', time.time() - start, '\n\n' 

Che dà:

Naive Bayes 
0.933333333333 0.944444444444 0.933333333333 
0.933333333333 0.944444444444 0.933333333333 
1.0 1.0 1.0 
0.933333333333 0.944444444444 0.933333333333 
0.933333333333 0.944444444444 0.933333333333 
0.933333333333 0.944444444444 0.933333333333 
0.866666666667 0.904761904762 0.866666666667 
1.0 1.0 1.0 
1.0 1.0 1.0 
1.0 1.0 1.0 

Sum: 2.86936507937 


time 0.0249638557434 


Decision Tree 
1.0 1.0 1.0 
0.933333333333 0.944444444444 0.933333333333 
1.0 1.0 1.0 
0.933333333333 0.944444444444 0.933333333333 
0.933333333333 0.944444444444 0.933333333333 
0.866666666667 0.866666666667 0.866666666667 
0.933333333333 0.944444444444 0.933333333333 
0.933333333333 0.944444444444 0.933333333333 
1.0 1.0 1.0 
1.0 1.0 1.0 

Sum: 2.86555555556 


time 0.0237860679626 


SVM 
1.0 1.0 1.0 
0.933333333333 0.944444444444 0.933333333333 
1.0 1.0 1.0 
1.0 1.0 1.0 
1.0 1.0 1.0 
0.933333333333 0.944444444444 0.933333333333 
0.933333333333 0.944444444444 0.933333333333 
1.0 1.0 1.0 
1.0 1.0 1.0 
1.0 1.0 1.0 

Sum: 2.94333333333 


time 0.043044090271 

Come di scikit-learn 0.19.0 la soluzione diventa molto più facile

from sklearn.model_selection import cross_validate 
from sklearn.datasets import load_iris 
from sklearn.svm import SVC 

iris = load_iris() 
clf = SVC() 
scoring = {'acc': 'accuracy', 
      'prec_macro': 'precision_macro', 
      'rec_micro': 'recall_macro'} 
scores = cross_validate(clf, iris.data, iris.target, scoring=scoring, 
         cv=5, return_train_score=True) 
print(scores.keys()) 
print(scores['test_acc']) 

che dà:

['test_acc', 'score_time', 'train_acc', 'fit_time', 'test_rec_micro', 'train_rec_micro', 'train_prec_macro', 'test_prec_macro'] 
[ 0.96666667 1.   0.96666667 0.96666667 1.  ] 
10

Ho riscontrato lo stesso problema e ho creato un modulo in grado di supportare più metriche in cross_val_score.
Al fine di realizzare ciò che si vuole con questo modulo, è possibile scrivere:

from multiscorer import MultiScorer 
import numpy as np 

scorer = MultiScorer({ 
    'Accuracy' : (accuracy_score, {}), 
    'Precision' : (precision_score, {'pos_label': 3, 'average':'macro'}), 
    'Recall' : (recall_score, {'pos_label': 3, 'average':'macro'}) 
}) 

for model, name in zip(models, names): 
    print name 
    start = time.time() 

    cross_val_score(model, iris.data, iris.target,scoring=scorer, cv=10) 
    results = scorer.get_results() 

    for metric_name in results.keys(): 
     average_score = np.average(results[metric_name]) 
     print('%s : %f' % (metric_name, average_score)) 

    print 'time', time.time() - start, '\n\n' 

è possibile controllare e scaricare il modulo dal GitHub. Spero che aiuti.