Come calcolare precisione, richiamo, accuratezza e punteggio f1 per il caso multiclasse con scikit learn?


109

Sto lavorando a un problema di analisi del sentiment, i dati hanno questo aspetto:

label instances
    5    1190
    4     838
    3     239
    1     204
    2     127

Quindi i miei dati sono sbilanciati poiché 1190 instancessono etichettati con 5. Per la classificazione sto usando l' SVC di scikit . Il problema è che non so come bilanciare i miei dati nel modo giusto per calcolare accuratamente la precisione, il richiamo, l'accuratezza e il punteggio f1 per il caso multiclasse. Quindi ho provato i seguenti approcci:

Primo:

    wclf = SVC(kernel='linear', C= 1, class_weight={1: 10})
    wclf.fit(X, y)
    weighted_prediction = wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, weighted_prediction)
print 'F1 score:', f1_score(y_test, weighted_prediction,average='weighted')
print 'Recall:', recall_score(y_test, weighted_prediction,
                              average='weighted')
print 'Precision:', precision_score(y_test, weighted_prediction,
                                    average='weighted')
print '\n clasification report:\n', classification_report(y_test, weighted_prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, weighted_prediction)

Secondo:

auto_wclf = SVC(kernel='linear', C= 1, class_weight='auto')
auto_wclf.fit(X, y)
auto_weighted_prediction = auto_wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, auto_weighted_prediction)

print 'F1 score:', f1_score(y_test, auto_weighted_prediction,
                            average='weighted')

print 'Recall:', recall_score(y_test, auto_weighted_prediction,
                              average='weighted')

print 'Precision:', precision_score(y_test, auto_weighted_prediction,
                                    average='weighted')

print '\n clasification report:\n', classification_report(y_test,auto_weighted_prediction)

print '\n confussion matrix:\n',confusion_matrix(y_test, auto_weighted_prediction)

Terzo:

clf = SVC(kernel='linear', C= 1)
clf.fit(X, y)
prediction = clf.predict(X_test)


from sklearn.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, \
    accuracy_score, f1_score

print 'Accuracy:', accuracy_score(y_test, prediction)
print 'F1 score:', f1_score(y_test, prediction)
print 'Recall:', recall_score(y_test, prediction)
print 'Precision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test,prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)


F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1082: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
 0.930416613529

Tuttavia, ricevo avvisi come questo:

/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172:
DeprecationWarning: The default `weighted` averaging is deprecated,
and from version 0.18, use of precision, recall or F-score with 
multiclass or multilabel data or pos_label=None will result in an 
exception. Please set an explicit value for `average`, one of (None, 
'micro', 'macro', 'weighted', 'samples'). In cross validation use, for 
instance, scoring="f1_weighted" instead of scoring="f1"

Come posso gestire correttamente i miei dati sbilanciati al fine di calcolare nel modo giusto le metriche del classificatore?


Allora perché non aggiungere un averageparametro nel terzo caso?
yangjie

1
@yangjie non lo so. Controllo solo la documentazione ma non capisco come utilizzare correttamente le metriche per dati sbilanciati. Potresti fornire una spiegazione più ampia e un esempio ?. Grazie!
new_with_python

Risposte:


164

Penso che ci sia molta confusione su quali pesi siano usati per cosa. Non sono sicuro di sapere esattamente cosa ti infastidisce, quindi tratterò diversi argomenti, abbi pazienza;).

Pesi di classe

I pesi del class_weightparametro vengono utilizzati per addestrare il classificatore . Non vengono utilizzati nel calcolo di nessuna delle metriche che stai utilizzando : con pesi di classe diversi, i numeri saranno diversi semplicemente perché il classificatore è diverso.

Fondamentalmente in ogni classificatore scikit-learn, i pesi delle classi sono usati per dire al tuo modello quanto sia importante una classe. Ciò significa che durante l'allenamento, il classificatore farà ulteriori sforzi per classificare correttamente le classi con pesi elevati.
Il modo in cui lo fanno dipende dall'algoritmo. Se desideri dettagli su come funziona per SVC e il documento non ha senso per te, sentiti libero di menzionarlo.

Le metriche

Una volta che hai un classificatore, vuoi sapere se sta funzionando bene. Qui è possibile utilizzare le metriche che hai citato: accuracy, recall_score, f1_score...

Di solito quando la distribuzione delle classi è sbilanciata, l'accuratezza è considerata una scelta sbagliata in quanto dà punteggi alti ai modelli che prevedono solo la classe più frequente.

Non descriverò in dettaglio tutte queste metriche ma noterò che, ad eccezione di accuracy, sono naturalmente applicate a livello di classe: come puoi vedere in questo printrapporto di classificazione sono definite per ogni classe. Si basano su concetti come true positiveso false negativeche richiedono la definizione di quale classe sia quella positiva .

             precision    recall  f1-score   support

          0       0.65      1.00      0.79        17
          1       0.57      0.75      0.65        16
          2       0.33      0.06      0.10        17
avg / total       0.52      0.60      0.51        50

L'avviso

F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The 
default `weighted` averaging is deprecated, and from version 0.18, 
use of precision, recall or F-score with multiclass or multilabel data  
or pos_label=None will result in an exception. Please set an explicit 
value for `average`, one of (None, 'micro', 'macro', 'weighted', 
'samples'). In cross validation use, for instance, 
scoring="f1_weighted" instead of scoring="f1".

Ricevi questo avviso perché stai usando il punteggio f1, il richiamo e la precisione senza definire come dovrebbero essere calcolati! La domanda potrebbe essere riformulata: dal rapporto di classificazione sopra, come si produce un numero globale per il punteggio f1? Potresti:

  1. Prendi la media del punteggio f1 per ogni classe: questo è il avg / totalrisultato sopra. Si chiama anche media macro .
  2. Calcola il punteggio f1 utilizzando il conteggio globale di veri positivi / falsi negativi, ecc. (Somma il numero di veri positivi / falsi negativi per ogni classe). Aka micro media.
  3. Calcola una media ponderata del punteggio f1. L'uso 'weighted'in scikit-learn peserà il punteggio f1 in base al supporto della classe: più elementi ha una classe, più importante sarà il punteggio f1 per questa classe nel calcolo.

Queste sono 3 delle opzioni in scikit-learn, l'avviso è lì per dire che devi sceglierne uno . Quindi devi specificare un averageargomento per il metodo del punteggio.

Quale sceglierai dipende da come vuoi misurare la performance del classificatore: per esempio la macro-media non tiene conto dello squilibrio di classe e il punteggio f1 della classe 1 sarà importante quanto il punteggio f1 della classe 5. Tuttavia, se si utilizza la media ponderata, si otterrà maggiore importanza per la classe 5.

L'intera specificazione dell'argomento in queste metriche non è molto chiara in scikit-learn in questo momento, migliorerà nella versione 0.18 secondo i documenti. Stanno rimuovendo alcuni comportamenti standard non ovvi e stanno emettendo avvisi in modo che gli sviluppatori lo notino.

Calcolo dei punteggi

L'ultima cosa che voglio menzionare (sentitevi liberi di saltarla se ne siete consapevoli) è che i punteggi sono significativi solo se vengono calcolati su dati che il classificatore non ha mai visto . Questo è estremamente importante poiché qualsiasi punteggio ottenuto sui dati utilizzati per l'adattamento del classificatore è completamente irrilevante.

Ecco un modo per farlo usando StratifiedShuffleSplit, che ti dà una suddivisione casuale dei tuoi dati (dopo aver mescolato) che preserva la distribuzione dell'etichetta.

from sklearn.datasets import make_classification
from sklearn.cross_validation import StratifiedShuffleSplit
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report, confusion_matrix

# We use a utility to generate artificial classification data.
X, y = make_classification(n_samples=100, n_informative=10, n_classes=3)
sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
for train_idx, test_idx in sss:
    X_train, X_test, y_train, y_test = X[train_idx], X[test_idx], y[train_idx], y[test_idx]
    svc.fit(X_train, y_train)
    y_pred = svc.predict(X_test)
    print(f1_score(y_test, y_pred, average="macro"))
    print(precision_score(y_test, y_pred, average="macro"))
    print(recall_score(y_test, y_pred, average="macro"))    

Spero che questo ti aiuti.


Per un multiclasse, come si specifica il peso di una classe? Ad esempio, cosa class_weight={1:10}significa per dati che hanno 3 classi?
Aziz Javed

Esiste comunque per ottenere punteggi di accuratezza in termini di etichetta?
Ankur Sinha

Puoi spiegare come funziona il micro in modo più chiaro. Inoltre non dici nulla di binario
umile

Per me, lo shuffle stratificato stava creando problemi, quindi sono tornato alla divisione del test di allenamento mentre si vedeva ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of labels for any class cannot be less than 2.. Funziona bene con la divisione del test del treno, ma qualcuno può aiutarmi perché ricevo questo errore con SSS? Grazie.
Akash Kandpal

HI ho testato il tuo codice ma ho questo messaggio di errore C: \ Users \\ Anaconda3 \ lib \ site-packages \ sklearn \ metrics \ classification.py: 976: Deprecation Avvertenza: dalla versione 0.18, l'input binario non verrà gestito specialmente quando si usa precisione media / richiamo / punteggio F. Si prega di utilizzare average = 'binary' per riportare solo la performance positiva della classe. 'performance di classe positiva.', DeprecationWarning)
Chedi Bechikh

73

Molte risposte molto dettagliate qui, ma non credo che tu stia rispondendo alle domande giuste. A quanto ho capito la domanda, ci sono due preoccupazioni:

  1. Come posso assegnare un punteggio a un problema multiclasse?
  2. Come gestisco i dati sbilanciati?

1.

Puoi usare la maggior parte delle funzioni di punteggio in scikit-learn sia con problemi multiclasse che con problemi a classe singola. Ex.:

from sklearn.metrics import precision_recall_fscore_support as score

predicted = [1,2,3,4,5,1,2,1,1,4,5] 
y_test = [1,2,3,4,5,1,2,1,1,4,1]

precision, recall, fscore, support = score(y_test, predicted)

print('precision: {}'.format(precision))
print('recall: {}'.format(recall))
print('fscore: {}'.format(fscore))
print('support: {}'.format(support))

In questo modo ti ritroverai con numeri tangibili e interpretabili per ciascuna delle classi.

| Label | Precision | Recall | FScore | Support |
|-------|-----------|--------|--------|---------|
| 1     | 94%       | 83%    | 0.88   | 204     |
| 2     | 71%       | 50%    | 0.54   | 127     |
| ...   | ...       | ...    | ...    | ...     |
| 4     | 80%       | 98%    | 0.89   | 838     |
| 5     | 93%       | 81%    | 0.91   | 1190    |

Poi...

2.

... puoi dire se i dati sbilanciati sono anche un problema. Se il punteggio per le classi meno rappresentate (classe 1 e 2) è inferiore a quello per le classi con più campioni di allenamento (classe 4 e 5) allora sai che i dati sbilanciati sono di fatto un problema, e puoi agire di conseguenza, come descritto in alcune delle altre risposte in questo thread. Tuttavia, se la stessa distribuzione di classi è presente nei dati su cui si desidera prevedere, i dati di allenamento sbilanciati sono un buon rappresentativo dei dati e, quindi, lo squilibrio è una buona cosa.


1
Ottimo post e ben detto. Grazie
Alvis

1
Hey solo una domanda di follow-up: come hai stampato le etichette usando precision_recall_fscore_support? Le etichette vengono stampate su ordinazione?
BigD

@BigD Sì, vedi scikit-learn.org/stable/modules/generated/… in fondo. Imposta average=Nonee definisci le etichette, quindi ottieni la metrica che stai cercando, per ciascuna delle etichette specificate.
wonderkid2

Esiste comunque per ottenere punteggi di accuratezza in termini di etichetta?
Ankur Sinha

@trollster non sono sicuro di cosa intendi? Non è quello che mostro nella risposta punteggi di accuratezza labelwise?
wonderkid2

16

Domanda posta

Rispondere alla domanda "quale metrica dovrebbe essere utilizzata per la classificazione multi-classe con dati sbilanciati": misura Macro-F1. È possibile utilizzare anche Macro Precision e Macro Recall, ma non sono così facilmente interpretabili come per la classificazione binaria, sono già incorporati nella misura F e le metriche in eccesso complicano il confronto dei metodi, l'ottimizzazione dei parametri e così via.

La micro media è sensibile allo squilibrio di classe: se il tuo metodo, ad esempio, funziona bene per le etichette più comuni e rovina totalmente le altre, le metriche micro-medie mostrano buoni risultati.

La ponderazione della media non è adatta per i dati sbilanciati, perché pesa in base al conteggio delle etichette. Inoltre, è troppo poco interpretabile e impopolare: ad esempio, non si fa menzione di tale media nella seguente indagine molto dettagliata che consiglio vivamente di esaminare:

Sokolova, Marina e Guy Lapalme. "Un'analisi sistematica delle misure di performance per compiti di classificazione." Elaborazione e gestione delle informazioni 45.4 (2009): 427-437.

Domanda specifica dell'applicazione

Tuttavia, tornando al tuo compito, cercherò 2 argomenti:

  1. metriche comunemente utilizzate per il tuo compito specifico: consente di (a) confrontare il tuo metodo con gli altri e capire se fai qualcosa di sbagliato, e (b) non esplorarlo da solo e riutilizzare i risultati di qualcun altro;
  2. costo dei diversi errori dei tuoi metodi - ad esempio, il caso d'uso della tua applicazione può fare affidamento solo su revisioni a 4 e 5 stelle - in questo caso, una buona metrica dovrebbe contare solo queste 2 etichette.

Metriche comunemente utilizzate. Come posso dedurre dopo aver esaminato la letteratura, ci sono 2 principali metriche di valutazione:

  1. Precisione , che viene utilizzata, ad esempio in

Yu, April e Daryl Chang. "Previsione del sentimento multiclasse utilizzando l'attività di Yelp."

( link ) - nota che gli autori lavorano con quasi la stessa distribuzione di valutazioni, vedi Figura 5.

Pang, Bo e Lillian Lee. "Vedere le stelle: sfruttare le relazioni di classe per la categorizzazione del sentimento rispetto alle scale di valutazione." Atti della 43a Riunione Annuale dell'Associazione per la Linguistica Computazionale. Associazione per la linguistica computazionale, 2005.

( collegamento )

  1. MSE (o, meno spesso, Mean Absolute Error - MAE ) - vedi, ad esempio,

Lee, Moontae e R. Grafe. "Analisi del sentiment multiclasse con recensioni di ristoranti". Progetti finali da CS N 224 (2010).

( link ) - esplorano sia l'accuratezza che l'MSE, considerando quest'ultimo migliore

Pappas, Nikolaos, Rue Marconi e Andrei Popescu-Belis. "Explaining the Stars: Weighted Multiple-Instance Learning for Aspect-Based Sentiment Analysis". Atti della conferenza 2014 sui metodi empirici nell'elaborazione del linguaggio naturale. N. EPFL-CONF-200899. Il 2014.

( link ) - utilizzano scikit-learn per la valutazione e gli approcci di base e affermano che il loro codice è disponibile; comunque non riesco a trovarlo, quindi se ne hai bisogno scrivi una lettera agli autori, il lavoro è abbastanza nuovo e sembra scritto in Python.

Costo di diversi errori . Se ti interessa di più evitare grossolani errori, ad esempio assegnare una recensione da 1 stella a 5 stelle o qualcosa del genere, guarda MSE; se la differenza è importante, ma non così tanto, prova MAE, poiché non quadrata diff; altrimenti rimani con Precisione.

A proposito di approcci, non di metriche

Prova gli approcci di regressione, ad esempio SVR , poiché generalmente superano i classificatori Multiclass come SVC o OVA SVM.


13

Prima di tutto è un po 'più difficile usare solo l'analisi del conteggio per capire se i tuoi dati sono sbilanciati o meno. Ad esempio: 1 osservazione positiva su 1000 è solo un rumore, un errore o una svolta scientifica? Non si sa mai.
Quindi è sempre meglio usare tutte le tue conoscenze disponibili e scegliere il suo stato con tutta saggezza.

Ok, e se fosse davvero sbilanciato?
Ancora una volta, guarda i tuoi dati. A volte puoi trovare una o due osservazioni moltiplicate per cento volte. A volte è utile creare queste false osservazioni di una classe.
Se tutti i dati sono puliti, il passaggio successivo consiste nell'utilizzare i pesi delle classi nel modello di previsione.

E per quanto riguarda le metriche multiclasse?
Nella mia esperienza di solito nessuna delle tue metriche viene utilizzata. Ci sono due ragioni principali.
Primo: è sempre meglio lavorare con le probabilità che con una previsione solida (perché altrimenti come potresti separare i modelli con la previsione 0.9 e 0.6 se entrambi ti danno la stessa classe?)
E secondo: è molto più facile confrontare i tuoi modelli di previsione e crearne di nuovi quelli che dipendono da una sola metrica valida.
Dalla mia esperienza potrei consigliare logloss o MSE (o semplicemente errore quadratico medio).

Come correggere gli avvisi di sklearn?
Semplicemente (come ha notato yangjie) sovrascrivi il averageparametro con uno di questi valori: 'micro'(calcola le metriche a livello globale), 'macro'(calcola le metriche per ogni etichetta) o 'weighted'(come la macro ma con i pesi automatici).

f1_score(y_test, prediction, average='weighted')

Tutti gli avvisi sono arrivati ​​dopo aver chiamato le funzioni di metrica con un averagevalore predefinito 'binary'che non è appropriato per la previsione multiclasse.
Buona fortuna e divertiti con l'apprendimento automatico!

Modificare:
ho trovato un'altra raccomandazione del risponditore per passare agli approcci di regressione (ad esempio SVR) con cui non posso essere d'accordo. Per quanto ricordo, non esiste nemmeno una cosa come la regressione multiclasse. Sì, esiste una regressione multilabel che è molto diversa e sì, in alcuni casi è possibile passare dalla regressione alla classificazione (se le classi sono in qualche modo ordinate) ma è piuttosto raro.

Quello che consiglierei (nell'ambito di scikit-learn) è di provare altri strumenti di classificazione molto potenti: aumento del gradiente , foresta casuale (la mia preferita), KNeighbors e molti altri.

Dopodiché puoi calcolare la media aritmetica o geometrica tra le previsioni e la maggior parte delle volte otterrai risultati ancora migliori.

final_prediction = (KNNprediction * RFprediction) ** 0.5

1
> "passa dalla regressione alla classificazione (se le classi sono in qualche modo ordinate) ma è piuttosto raro" È il caso: 5> 4> 3> 2> 1. Ti suggerisco di dare un'occhiata ai documenti per questo compito - ci sono molti approcci di regressione e classificazione per l'attività (a volte nello stesso lavoro).
Nikita Astrakhantsev

Quindi non è nemmeno una classificazione multiclasse ma una semplice regressione.
Vlad Mironov

Sì, internamente, o dal punto di vista ML, è una regressione, ma nella fase finale convertiamo i risultati della regressione in etichette, quindi è una classificazione multiclasse - dal punto di vista dell'utente o dell'applicazione.
Nikita Astrakhantsev
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.