Wie berechnet man mit scikit learn Präzision, Rückruf, Genauigkeit und f1-Score für den Fall mit mehreren Klassen?

109

Ich arbeite an einem Stimmungsanalyseproblem. Die Daten sehen folgendermaßen aus:

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

Meine Daten sind also unausgeglichen, da 1190 instancesmit gekennzeichnet sind 5. Für die Klassifizierung verwende ich den SVC von scikit . Das Problem ist, dass ich nicht weiß, wie ich meine Daten richtig ausgleichen soll, um die Präzision, den Rückruf, die Genauigkeit und den f1-Score für den Fall mit mehreren Klassen genau zu berechnen. Also habe ich folgende Ansätze ausprobiert:

Zuerst:

    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)

Zweite:

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)

Dritte:

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

Ich bekomme jedoch Warnungen wie diese:

/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"

Wie kann ich mit meinen unausgeglichenen Daten richtig umgehen, um die Metriken des Klassifikators richtig zu berechnen?

new_with_python
quelle
Warum also nicht averageim dritten Fall einen Parameter hinzufügen ?
Yangjie
1
@ Yangjie Ich weiß es nicht. Ich überprüfe nur die Dokumentation, verstehe aber nicht, wie die Metriken für unausgeglichene Daten korrekt verwendet werden. Könnten Sie eine ausführlichere Erklärung und ein Beispiel geben? Vielen Dank!
new_with_python

Antworten:

163

Ich denke, es gibt viel Verwirrung darüber, welche Gewichte für was verwendet werden. Ich bin mir nicht sicher, ob ich genau weiß, was dich stört, also werde ich verschiedene Themen behandeln, trage mich;).

Klassengewichte

Die Gewichte aus dem class_weightParameter werden verwendet, um den Klassifikator zu trainieren . Sie werden bei der Berechnung der von Ihnen verwendeten Metriken nicht verwendet : Bei unterschiedlichen Klassengewichten sind die Zahlen einfach deshalb unterschiedlich, weil der Klassifizierer unterschiedlich ist.

Grundsätzlich werden in jedem Scikit-Learn-Klassifikator die Klassengewichte verwendet, um Ihrem Modell mitzuteilen, wie wichtig eine Klasse ist. Das bedeutet, dass der Klassifikator während des Trainings zusätzliche Anstrengungen unternimmt, um die Klassen mit hohen Gewichten richtig zu klassifizieren.
Wie sie das machen, ist algorithmisch. Wenn Sie Details zur Funktionsweise von SVC wünschen und das Dokument für Sie keinen Sinn ergibt, können Sie dies gerne erwähnen.

Die Metriken

Sobald Sie einen Klassifikator haben, möchten Sie wissen, wie gut er funktioniert. Hier können Sie die Metriken verwenden Sie erwähnt: accuracy, recall_score, f1_score...

Wenn die Klassenverteilung unausgeglichen ist, wird Genauigkeit normalerweise als schlechte Wahl angesehen, da Modelle, die nur die häufigste Klasse vorhersagen, hohe Punktzahlen erhalten.

Ich werde nicht alle diese Metriken detailliert beschreiben, aber beachten Sie, dass sie mit Ausnahme von accuracynatürlich auf Klassenebene angewendet werden: Wie Sie in diesem printKlassifizierungsbericht sehen können, werden sie für jede Klasse definiert. Sie stützen sich auf Konzepte wie true positivesoder false negative, bei denen definiert werden muss, welche Klasse die positive ist .

             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

Die Warnung

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".

Sie erhalten diese Warnung, weil Sie den f1-Score, den Rückruf und die Präzision verwenden, ohne zu definieren, wie diese berechnet werden sollen! Die Frage könnte umformuliert werden: Wie geben Sie aus dem obigen Klassifizierungsbericht eine globale Zahl für den F1-Score aus? Du könntest:

  1. Nehmen Sie den Durchschnitt der f1-Punktzahl für jede Klasse: das ist das avg / totalobige Ergebnis. Es wird auch als Makro- Mittelwertbildung bezeichnet.
  2. Berechnen Sie den f1-Score anhand der globalen Anzahl von True Positives / False Negatives usw. (Sie summieren die Anzahl der True Positives / False Negatives für jede Klasse). Aka Mikro- Mittelung.
  3. Berechnen Sie einen gewichteten Durchschnitt des f1-Scores. Bei Verwendung 'weighted'von scikit-learn wird der f1-Score durch die Unterstützung der Klasse gewichtet: Je mehr Elemente eine Klasse enthält, desto wichtiger ist der f1-Score für diese Klasse bei der Berechnung.

Dies sind 3 der Optionen in Scikit-Learn. Die Warnung besagt, dass Sie eine auswählen müssen . Sie müssen also ein averageArgument für die Bewertungsmethode angeben .

Welche Sie wählen, hängt davon ab, wie Sie die Leistung des Klassifikators messen möchten: Beispielsweise berücksichtigt die Makro-Mittelung das Klassenungleichgewicht nicht, und der f1-Score der Klasse 1 ist genauso wichtig wie der f1-Score der Klasse 5. Wenn Sie jedoch eine gewichtete Mittelung verwenden, erhalten Sie für die Klasse 5 eine größere Bedeutung.

Die gesamte Argumentspezifikation in diesen Metriken ist in scikit-learn derzeit nicht sehr klar, sie wird in Version 0.18 laut den Dokumenten besser. Sie entfernen ein nicht offensichtliches Standardverhalten und geben Warnungen aus, damit Entwickler es bemerken.

Punktzahlen berechnen

Das Letzte, was ich erwähnen möchte (Sie können es gerne überspringen, wenn Sie sich dessen bewusst sind), ist, dass Punktzahlen nur dann von Bedeutung sind, wenn sie anhand von Daten berechnet werden, die der Klassifikator noch nie gesehen hat . Dies ist äußerst wichtig, da jede Bewertung, die Sie für Daten erhalten, die für die Anpassung des Klassifikators verwendet wurden, völlig irrelevant ist.

Hier ist eine Möglichkeit, dies zu tun, indem StratifiedShuffleSplitSie eine zufällige Aufteilung Ihrer Daten (nach dem Mischen) erhalten, die die Etikettenverteilung beibehält.

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"))    

Hoffe das hilft.

ldirer
quelle
Wie geben Sie für eine Mehrfachklasse ein Klassengewicht an? Was class_weight={1:10}bedeutet beispielsweise für Daten mit 3 Klassen?
Aziz Javed
Gibt es überhaupt eine Möglichkeit, die Genauigkeit des Etiketts zu ermitteln?
Ankur Sinha
Können Sie erklären, wie Mikro klarer funktioniert? Auch Sie erwähnen nichts über binär
bescheiden
Für mich verursachte geschichtetes Shuffle Probleme, und so wechselte ich wieder zu Train-Test-Split, wie es zeigte 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.. Es funktioniert gut mit dem Zugtest-Split, aber kann mir jemand helfen, warum ich diesen Fehler mit SSS erhalte? Vielen Dank.
Akash Kandpal
HI Ich habe Ihren Code getestet, aber ich habe diese Fehlermeldung C: \ Benutzer \\ Anaconda3 \ lib \ Site-Pakete \ sklearn \ Metrics \ Classification.py: 976: DeprecationWarning: Ab Version 0.18 werden Binäreingaben bei der Verwendung nicht speziell behandelt gemittelte Präzision / Rückruf / F-Punktzahl. Verwenden Sie durchschnittlich = 'binär', um nur die positive Klassenleistung zu melden. 'positive Klassenleistung.', DeprecationWarning)
Chedi Bechikh
72

Viele sehr detaillierte Antworten hier, aber ich glaube nicht, dass Sie die richtigen Fragen beantworten. Soweit ich die Frage verstehe, gibt es zwei Bedenken:

  1. Wie kann ich ein Problem mit mehreren Klassen erzielen?
  2. Wie gehe ich mit unausgeglichenen Daten um?

1.

Sie können die meisten Bewertungsfunktionen in Scikit-Learn sowohl für Mehrklassenprobleme als auch für Einzelklassenprobleme verwenden. 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))

Auf diese Weise erhalten Sie für jede Klasse greifbare und interpretierbare Zahlen.

| 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    |

Dann...

2.

... können Sie feststellen, ob die unsymmetrischen Daten überhaupt ein Problem darstellen. Wenn die Bewertung für die weniger vertretenen Klassen (Klasse 1 und 2) niedriger ist als für die Klassen mit mehr Trainingsbeispielen (Klasse 4 und 5), wissen Sie, dass die unausgeglichenen Daten tatsächlich ein Problem darstellen, und können entsprechend handeln beschrieben in einigen der anderen Antworten in diesem Thread. Wenn jedoch in den Daten, für die Sie eine Vorhersage treffen möchten, dieselbe Klassenverteilung vorhanden ist, sind Ihre unausgeglichenen Trainingsdaten ein guter Vertreter der Daten, und daher ist die Unausgewogenheit eine gute Sache.

wunderkid2
quelle
1
Toller Beitrag und gut gesagt. Vielen Dank
Alvis
1
Hey, nur eine Folgefrage: Wie haben Sie die Etiketten mit gedruckt precision_recall_fscore_support? Werden die Etiketten auf Bestellung gedruckt?
BigD
@BigD Ja, siehe scikit-learn.org/stable/modules/generated/… ganz unten. Legen Sie average=Nonedie Beschriftungen fest und definieren Sie sie. Anschließend erhalten Sie für jede der angegebenen Beschriftungen die gesuchte Metrik.
Wonderkid2
Gibt es überhaupt eine Möglichkeit, die Genauigkeit des Etiketts zu ermitteln?
Ankur Sinha
@trollster Ich bin nicht sicher, was du meinst? Ist das, was ich in der Antwort zeige, nicht genau?
Wonderkid2
15

Gestellte Frage

Beantwortung der Frage „Welche Metrik sollte für die Klassifizierung mehrerer Klassen mit unausgeglichenen Daten verwendet werden?“: Makro-F1-Messung. Macro Precision und Macro Recall können ebenfalls verwendet werden, sind jedoch nicht so leicht zu interpretieren wie für die binäre Klassifizierung. Sie sind bereits in F-Measure integriert, und überschüssige Metriken erschweren den Methodenvergleich, die Parametereinstellung usw.

Mikro-Mittelung reagiert empfindlich auf Klassenungleichgewichte: Wenn Ihre Methode beispielsweise für die gängigsten Labels gut funktioniert und andere völlig durcheinander bringt, zeigen mikro-gemittelte Metriken gute Ergebnisse.

Die Mittelung der Gewichtung ist für unausgeglichene Daten nicht gut geeignet, da sie nach Anzahl der Etiketten gewichtet wird. Darüber hinaus ist es zu kaum interpretierbar und unbeliebt: Beispielsweise wird eine solche Mittelung in der folgenden sehr detaillierten Umfrage nicht erwähnt. Ich empfehle dringend, sie durchzusehen:

Sokolova, Marina und Guy Lapalme. "Eine systematische Analyse von Leistungsmaßstäben für Klassifizierungsaufgaben." Information Processing & Management 45.4 (2009): 427 & ndash; 437.

Anwendungsspezifische Frage

Um jedoch zu Ihrer Aufgabe zurückzukehren, würde ich zwei Themen untersuchen:

  1. Metriken, die üblicherweise für Ihre spezifische Aufgabe verwendet werden - Sie ermöglichen es (a), Ihre Methode mit anderen zu vergleichen und zu verstehen, ob Sie etwas falsch machen, und (b) dies nicht selbst zu untersuchen und die Ergebnisse anderer wiederzuverwenden;
  2. Kosten für verschiedene Fehler Ihrer Methoden - zum Beispiel kann der Anwendungsfall Ihrer Anwendung nur auf 4- und 5-Sterne-Bewertungen beruhen - in diesem Fall sollte eine gute Metrik nur diese 2 Bezeichnungen zählen.

Häufig verwendete Metriken. Wie ich nach Durchsicht der Literatur schließen kann, gibt es zwei Hauptbewertungsmetriken:

  1. Genauigkeit , die verwendet wird, z

Yu, April und Daryl Chang. "Multiclass Sentiment Prediction mit Yelp Business."

( Link ) - Beachten Sie, dass die Autoren mit fast der gleichen Verteilung der Bewertungen arbeiten, siehe Abbildung 5.

Pang, Bo und Lillian Lee. "Sterne sehen: Klassenbeziehungen für die Kategorisierung von Stimmungen in Bezug auf Bewertungsskalen ausnutzen." Tagungsband der 43. Jahrestagung der Vereinigung für Computerlinguistik. Verein für Computerlinguistik, 2005.

( Link )

  1. MSE (oder seltener Mean Absolute Error - MAE ) - siehe zum Beispiel

Lee, Moontae und R. Grafe. "Multiklassen-Stimmungsanalyse mit Restaurantbewertungen." Abschlussprojekte aus CS N 224 (2010).

( Link ) - Sie untersuchen sowohl Genauigkeit als auch MSE, wobei letztere als besser angesehen werden

Pappas, Nikolaos, Rue Marconi und Andrei Popescu-Belis. "Erklären der Sterne: Gewichtetes Lernen in mehreren Instanzen für die aspektorientierte Stimmungsanalyse." Vorträge der Konferenz 2014 über empirische Methoden in der Verarbeitung natürlicher Sprache. EPFL-CONF-200899. 2014.

( Link ) - Sie verwenden Scikit-Learn für Evaluierungs- und Basisansätze und geben an, dass ihr Code verfügbar ist. Ich kann es jedoch nicht finden. Wenn Sie es brauchen, schreiben Sie einen Brief an die Autoren. Die Arbeit ist ziemlich neu und scheint in Python geschrieben zu sein.

Kosten für verschiedene Fehler . Wenn Sie mehr Wert darauf legen, grobe Fehler zu vermeiden, z. B. eine Bewertung von 1 bis 5 Sternen oder ähnliches vorzunehmen, schauen Sie sich MSE an. Wenn der Unterschied wichtig ist, aber nicht so sehr, versuchen Sie es mit MAE, da der Unterschied nicht quadratisch ist. Andernfalls bleiben Sie bei der Genauigkeit.

Über Ansätze, keine Metriken

Versuchen Sie es mit Regressionsansätzen, z. B. SVR , da diese Multiklassenklassifizierer wie SVC oder OVA SVM im Allgemeinen übertreffen.

Nikita Astrakhantsev
quelle
12

Zunächst ist es etwas schwieriger, nur die Zählanalyse zu verwenden, um festzustellen, ob Ihre Daten unausgeglichen sind oder nicht. Zum Beispiel: 1 von 1000 positiven Beobachtungen ist nur ein Rauschen, ein Fehler oder ein Durchbruch in der Wissenschaft? Man weiß nie.
Es ist also immer besser, Ihr gesamtes verfügbares Wissen zu nutzen und seinen Status mit Bedacht zu wählen.

Okay, was ist, wenn es wirklich unausgeglichen ist?
Noch einmal - schauen Sie auf Ihre Daten. Manchmal finden Sie eine oder zwei Beobachtungen multipliziert mit hundert. Manchmal ist es nützlich, diese gefälschten Ein-Klassen-Beobachtungen zu erstellen.
Wenn alle Daten sauber sind, besteht der nächste Schritt darin, Klassengewichte im Vorhersagemodell zu verwenden.

Was ist also mit Metriken für mehrere Klassen?
Nach meiner Erfahrung wird normalerweise keine Ihrer Metriken verwendet. Es gibt zwei Hauptgründe.
Erstens: Es ist immer besser, mit Wahrscheinlichkeiten zu arbeiten als mit soliden Vorhersagen (denn wie sonst könnten Sie Modelle mit 0,9- und 0,6-Vorhersagen trennen, wenn beide dieselbe Klasse ergeben?)
Und zweitens: Es ist viel einfacher, Ihre Vorhersagemodelle zu vergleichen und neue zu erstellen diejenigen, die nur von einer guten Metrik abhängen.
Aus meiner Erfahrung könnte ich Logloss oder MSE empfehlen (oder nur quadratischen Fehler bedeuten).

Wie behebe ich sklearn-Warnungen?
Überschreiben Sie einfach (wie Yangjie bemerkte) averageParameter mit einem der folgenden Werte: 'micro'(Metriken global berechnen), 'macro'(Metriken für jedes Etikett berechnen) oder 'weighted'(wie Makro, jedoch mit automatischen Gewichten).

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

Alle Ihre Warnungen wurden nach dem Aufrufen von Metrikfunktionen mit einem Standardwert angezeigt average, 'binary'der für die Vorhersage mehrerer Klassen ungeeignet ist.
Viel Glück und viel Spaß beim maschinellen Lernen!

Bearbeiten:
Ich habe eine weitere Antwortempfehlung gefunden, um zu Regressionsansätzen (z. B. SVR) zu wechseln, denen ich nicht zustimmen kann. Soweit ich mich erinnere, gibt es nicht einmal eine Regression mit mehreren Klassen. Ja, es gibt eine Multilabel-Regression, die sehr unterschiedlich ist, und ja, es ist in einigen Fällen möglich, zwischen Regression und Klassifizierung zu wechseln (wenn die Klassen irgendwie sortiert sind), aber es ist ziemlich selten.

Was ich empfehlen würde (im Rahmen von Scikit-Learn), ist, ein anderes sehr leistungsfähiges Klassifizierungswerkzeug auszuprobieren: Gradientenverstärkung , Zufallswald (mein Favorit), KNeighbors und viele mehr.

Danach können Sie den arithmetischen oder geometrischen Mittelwert zwischen den Vorhersagen berechnen. Meistens erhalten Sie sogar noch bessere Ergebnisse.

final_prediction = (KNNprediction * RFprediction) ** 0.5
Vlad Mironov
quelle
1
> "Wechsel zwischen Regression und Klassifizierung (wenn Klassen irgendwie sortiert sind), aber es ist ziemlich selten" Es ist der Fall: 5> 4> 3> 2> 1. Ich würde Ihnen empfehlen, sich die Papiere für diese Aufgabe anzusehen - es gibt viele Regressions- und Klassifizierungsansätze für die Aufgabe (manchmal in derselben Arbeit).
Nikita Astrakhantsev
Dann ist es nicht einmal eine Klassifizierung in mehreren Klassen, sondern eine einfache Regression.
Vlad Mironov
Ja, intern oder aus ML-Sicht handelt es sich um eine Regression, aber im letzten Schritt konvertieren wir Regressionsergebnisse in Labels, sodass es sich um eine Klassifizierung mehrerer Klassen handelt - aus Sicht des Benutzers oder der Anwendung.
Nikita Astrakhantsev