UndefinedMetricWarning: Der F-Score ist schlecht definiert und wird in Labels ohne vorhergesagte Stichproben auf 0,0 gesetzt

77

Ich bekomme diesen seltsamen Fehler:

classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples.
'precision', 'predicted', average, warn_for)`

aber dann druckt es auch die f-Punktzahl, wenn ich das erste Mal laufe:

metrics.f1_score(y_test, y_pred, average='weighted')

Beim zweiten Start wird die Punktzahl fehlerfrei angezeigt. Warum das?

>>> y_pred = test.predict(X_test)
>>> y_test
array([ 1, 10, 35,  9,  7, 29, 26,  3,  8, 23, 39, 11, 20,  2,  5, 23, 28,
       30, 32, 18,  5, 34,  4, 25, 12, 24, 13, 21, 38, 19, 33, 33, 16, 20,
       18, 27, 39, 20, 37, 17, 31, 29, 36,  7,  6, 24, 37, 22, 30,  0, 22,
       11, 35, 30, 31, 14, 32, 21, 34, 38,  5, 11, 10,  6,  1, 14, 12, 36,
       25,  8, 30,  3, 12,  7,  4, 10, 15, 12, 34, 25, 26, 29, 14, 37, 23,
       12, 19, 19,  3,  2, 31, 30, 11,  2, 24, 19, 27, 22, 13,  6, 18, 20,
        6, 34, 33,  2, 37, 17, 30, 24,  2, 36,  9, 36, 19, 33, 35,  0,  4,
        1])
>>> y_pred
array([ 1, 10, 35,  7,  7, 29, 26,  3,  8, 23, 39, 11, 20,  4,  5, 23, 28,
       30, 32, 18,  5, 39,  4, 25,  0, 24, 13, 21, 38, 19, 33, 33, 16, 20,
       18, 27, 39, 20, 37, 17, 31, 29, 36,  7,  6, 24, 37, 22, 30,  0, 22,
       11, 35, 30, 31, 14, 32, 21, 34, 38,  5, 11, 10,  6,  1, 14, 30, 36,
       25,  8, 30,  3, 12,  7,  4, 10, 15, 12,  4, 22, 26, 29, 14, 37, 23,
       12, 19, 19,  3, 25, 31, 30, 11, 25, 24, 19, 27, 22, 13,  6, 18, 20,
        6, 39, 33,  9, 37, 17, 30, 24,  9, 36, 39, 36, 19, 33, 35,  0,  4,
        1])
>>> metrics.f1_score(y_test, y_pred, average='weighted')
C:\Users\Michael\Miniconda3\envs\snowflakes\lib\site-packages\sklearn\metrics\classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples.
  'precision', 'predicted', average, warn_for)
0.87282051282051276
>>> metrics.f1_score(y_test, y_pred, average='weighted')
0.87282051282051276
>>> metrics.f1_score(y_test, y_pred, average='weighted')
0.87282051282051276

Warum wird eine nachfolgende 'precision', 'predicted', average, warn_for)Fehlermeldung angezeigt? Es gibt keine offene Klammer. Warum endet sie mit einer schließenden Klammer? Ich führe sklearn 0.18.1 mit Python 3.6.0 in einer Conda-Umgebung unter Windows 10 aus.

Ich betrachteten auch hier und ich weiß nicht , ob es der gleiche Fehler ist. Dieser SO-Beitrag hat auch keine Lösung.

Klebrig
quelle
9
Es gibt einige Labels in y_true, die nicht in y_pred erscheinen und daher schlecht definiert sind
Vivek Kumar
3
@VivekKumar Ich bekomme auch die gleiche Warnung. Ich habe einen ausgeglichenen Datensatz (500 + 500) und diese Warnung scheint während der clf = GridSearchCV(SVC(C=2), tuned_parameters, cv=cv, scoring='f1') clf.fit(X_train, y_train)Phase aufzutauchen. Es wäre großartig zu sehen, was die Warnung verursacht oder wie sie behoben werden kann.
Salvu

Antworten:

109

Wie in den Kommentaren erwähnt, werden einige Beschriftungen in y_true nicht in y_pred angezeigt. Insbesondere in diesem Fall wird die Bezeichnung '2' niemals vorhergesagt:

>>> set(y_test) - set(y_pred)
{2}

Dies bedeutet, dass für dieses Etikett kein F-Score berechnet werden muss und der F-Score für diesen Fall daher als 0,0 angesehen wird. Da Sie einen Durchschnitt der Punktzahl angefordert haben, müssen Sie berücksichtigen, dass eine Punktzahl von 0 in die Berechnung einbezogen wurde. Aus diesem Grund zeigt Ihnen scikit-learn diese Warnung an.

Dies bringt mich zu Ihnen, dass Sie den Fehler kein zweites Mal sehen. Wie bereits erwähnt, handelt es sich um eine Warnung , die anders behandelt wird als ein Python-Fehler. In den meisten Umgebungen wird standardmäßig eine bestimmte Warnung nur einmal angezeigt. Dieses Verhalten kann geändert werden:

import warnings
warnings.filterwarnings('always')  # "error", "ignore", "always", "default", "module" or "once"

Wenn Sie dies vor dem Importieren der anderen Module festlegen, wird die Warnung jedes Mal angezeigt, wenn Sie den Code ausführen.

Es gibt keine Möglichkeit, diese Warnung beim ersten Mal zu vermeiden, abgesehen von der Einstellung warnings.filterwarnings('ignore'). Was Sie können tun, ist entscheiden , dass Sie nicht in den Noten von Etiketten interessiert sind , die nicht vorhergesagt wurden, und geben Sie dann explizit die Etiketten Sie sind interessiert in (die Etiketten sind, die mindestens einmal vorhergesagt wurden):

>>> metrics.f1_score(y_test, y_pred, average='weighted', labels=np.unique(y_pred))
0.91076923076923078

Die Warnung wird in diesem Fall nicht angezeigt.

Shovalt
quelle
2
Dies ist eine großartige Antwort, aber ich würde davor warnen, die f1-Punktzahl mit zu berechnen, unique(y_pred)da dies zu irreführenden Ergebnissen führen kann.
Robert Sim
@ RobertSim kannst du das bitte etwas näher erläutern? Vielen Dank.
Akash Kandpal
4
@ harrypotter0, ich denke, er meinte damit, dass die Verwendung unique(y_pred)als Standardpraxis, ohne zu verstehen, was Sie tun, unerwartete Konsequenzen haben kann. Was hier passiert ist, dass die Bezeichnungen, die überhaupt nicht vorhergesagt wurden, einfach ignoriert werden. Solange Sie aktiv entscheiden , dass Sie daran interessiert sind, ist das in Ordnung. Wenn ich diese Methode verwende, drucke ich persönlich immer die nicht vorhergesagten Etiketten aus (unter Verwendung der festgelegten Operationen am Anfang der Antwort), um sicherzustellen, dass ich diese Tatsache nicht verpasse.
Shovalt
Ich beziehe mich auf diese Frage, da ich ein ähnliches Problem habe. In meinem Fall, wenn ich die Länge von überprüfe y_testund y_preddiese die gleiche Länge haben. Wie könnte es also schlecht definiert sein, wenn jedes echte Etikett ein vorhergesagtes Etikett hat?
Akalanka
3
@akalanka, versuche es mit np.unique(y_pred)und np.unique(y_test). Diese haben wahrscheinlich unterschiedliche Längen. Alle Ihre ys haben ein vorhergesagtes Label, aber nicht alle Labels wurden mindestens einmal vorhergesagt.
Shovalt
4

Nach der Antwort von @ Shovalt, aber kurz gesagt:

Alternativ können Sie die folgenden Codezeilen verwenden

    from sklearn.metrics import f1_score
    metrics.f1_score(y_test, y_pred, labels=np.unique(y_pred))

Dies sollte Ihre Warnung entfernen und Ihnen das gewünschte Ergebnis liefern, da der Unterschied zwischen den Sätzen im eindeutigen Modus nicht mehr berücksichtigt wird.

Amir Md Amiruzzaman
quelle
3
Dies ist ein Duplikat von Shovalts Antwort.
Normanius
3

Die akzeptierte Antwort erklärt bereits gut, warum die Warnung auftritt. Wenn Sie einfach die Warnungen steuern möchten, können Sie verwenden precision_recall_fscore_support. Es bietet ein (halboffizielles) Argument warn_for, mit dem die Warnungen stummgeschaltet werden könnten.

(_, _, f1, _) = metrics.precision_recall_fscore_support(y_test, y_pred,
                                                        average='weighted', 
                                                        warn_for=tuple())

Wie bereits in einigen Kommentaren erwähnt, gehen Sie vorsichtig damit um.

normanius
quelle
1
Nein, beim Durchsuchen der sklearn-Quelle habe ich diese Option nur für gefunden precision_recall_fscore_support().
Normanius
3

Das gleiche Problem passierte mir auch, als ich mein Klassifizierungsmodell trainierte. Der Grund für dieses Problem ist, dass in der Warnmeldung "In Labels ohne prädizierte Stichproben" die Nullteilung bei der Berechnung des f1-Scores verursacht wird. Ich habe eine andere Lösung gefunden, als ich das Dokument sklearn.metrics.f1_score gelesen habe . Es gibt einen Hinweis wie folgt:

Wenn wahr positiv + falsch positiv == 0 ist, ist die Genauigkeit undefiniert; Wenn wahr positiv + falsch negativ == 0 ist, ist der Rückruf undefiniert. In solchen Fällen wird die Metrik standardmäßig auf 0 gesetzt, ebenso wie der f-Score, und UndefinedMetricWarning wird ausgelöst. Dieses Verhalten kann mit zero_division geändert werden

Der zero_divisionStandardwert ist "warn", Sie können ihn festlegen 0oder 1vermeiden UndefinedMetricWarning. es funktioniert für mich;) oh warte, es gibt ein anderes Problem bei der Verwendung zero_division, mein sklearn-Bericht, dass kein solches Keyword-Argument mit scikit-learn 0.21.3. Aktualisieren Sie einfach Ihr sklearn durch Ausführen auf die neueste Versionpip install scikit-learn -U

petty.cf
quelle
1

Wie ich bemerkt habe, tritt dieser Fehler unter zwei Umständen auf:

  1. Wenn Sie train_test_split () zum Teilen Ihrer Daten verwendet haben, müssen Sie sicherstellen, dass Sie den Index der Daten zurücksetzen (insbesondere, wenn Sie ein Objekt der Pandas-Serie verwenden): y_train, y_test-Indizes sollten zurückgesetzt werden. Das Problem ist, wenn Sie versuchen, eine der Partituren von sklearn.metrics zu verwenden, wie z. Mit precision_score wird versucht, mit den gemischten Indizes des y_test übereinzustimmen, die Sie von train_test_split () erhalten haben.

Verwenden Sie daher entweder np.array (y_test) für y_true in Scores oder y_test.reset_index (drop = True).

  1. Andererseits kann dieser Fehler immer noch auftreten, wenn Ihre vorhergesagten "True Positives" 0 sind, was für Präzision, Rückruf und f1_scores verwendet wird. Sie können dies mit einer confusion_matrix visualisieren. Wenn die Klassifizierung mehrschichtig ist und Sie param festlegen: Durchschnitt = 'gewichtet' / Mikro / Makro, erhalten Sie eine Antwort, solange die diagonale Linie in der Matrix nicht 0 ist

Hoffe das hilft.

Manula Vishvajith
quelle
-1

Wie in der Fehlermeldung angegeben, stammt die Methode zum Abrufen der F-Bewertung aus dem Teil "Klassifizierung" von sklearn - daher wird von "Labels" gesprochen.

Haben Sie ein Regressionsproblem? Sklearn bietet eine "F-Score" -Methode für die Regression unter der Gruppe "Feature-Auswahl": http://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.f_regression.html

Falls Sie ein Klassifizierungsproblem haben, scheint mir die Antwort von @ Shovalt richtig zu sein.

Tw UxTLi51Nus
quelle
Sie weisen zu Recht auf den Unterschied zwischen Regression und Klassifizierung hin, aber ich bin zu dem Schluss gekommen, dass dies ein Klassifizierungsproblem aufgrund der Diskretion von y_testund y_predin der Frage ist.
Shovalt