XGBoost für die binäre Klassifizierung: Auswahl des richtigen Schwellenwerts

8

Ich arbeite an einem stark unausgeglichenen Datensatz mit binären Bezeichnungen, bei dem die Anzahl der echten Bezeichnungen nur 7% des gesamten Datensatzes beträgt. Eine Kombination von Merkmalen kann jedoch zu einer überdurchschnittlichen Anzahl von Merkmalen in einer Teilmenge führen.

ZB haben wir folgenden Datensatz mit einem einzigen Merkmal (Farbe):

180 rote Proben - 0

20 rote Proben - 1

300 grüne Proben - 0

100 grüne Proben - 1

Wir können einen einfachen Entscheidungsbaum erstellen:

                      (color)

                red /       \ green

 P(1 | red) = 0.1              P(1 | green) = 0.25

P (1) = 0,2 für den Gesamtdatensatz

Wenn ich XGBoost für diesen Datensatz ausführe, können Wahrscheinlichkeiten vorhergesagt werden, die nicht größer als 0,25 sind. Was bedeutet, dass wenn ich eine Entscheidung bei 0,5 Schwelle treffe:

  • 0 - P <0,5
  • 1 - P> = 0,5

Dann bekomme ich immer alle Samples als Nullen . Hoffe, dass ich das Problem klar beschrieben habe.

Auf dem ersten Datensatz erhalte ich nun das folgende Diagramm (Schwellenwert auf der x-Achse):

Geben Sie hier die Bildbeschreibung ein

Mit einem Maximum von f1_score bei einem Schwellenwert von 0,1. Jetzt habe ich zwei Fragen:

  • sollte ich f1_score überhaupt für einen Datensatz einer solchen Struktur verwenden?
  • Ist es immer sinnvoll, einen Schwellenwert von 0,5 für die Zuordnung von Wahrscheinlichkeiten zu Labels zu verwenden, wenn XGBoost für die binäre Klassifizierung verwendet wird?

Aktualisieren. Ich sehe, dass dieses Thema ein gewisses Interesse weckt. Unten finden Sie den Python-Code zum Reproduzieren des Rot / Grün-Experiments mit XGBoost. Es gibt tatsächlich die erwarteten Wahrscheinlichkeiten aus:

from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
import numpy as np

X0_0 = np.zeros(180) # red - 0
Y0_0 = np.zeros(180)

X0_1 = np.zeros(20) # red - 1
Y0_1 = np.ones(20)

X1_0 = np.ones(300) # green - 0
Y1_0 = np.zeros(300)

X1_1 = np.ones(100) # green  - 1
Y1_1 = np.ones(100)

X = np.concatenate((X0_0, X0_1, X1_0, Y1_1))
Y = np.concatenate((Y0_0, Y0_1, Y1_0, Y1_1))

# reshaping into 2-dim array
X = X.reshape(-1, 1)

import xgboost as xgb

xgb_dmat = xgb.DMatrix(X_train, label=y_train)

param = {'max_depth': 1,
         'eta': 0.01,
         'objective': 'binary:logistic',
         'eval_metric': 'error',
         'nthread': 4}

model = xgb.train(param, xg_mat, 400)

X0_sample = np.array([[0]])
X1_sample = np.array([[1]])

print('P(1 | red), predicted: ' + str(model.predict(xgb.DMatrix(X0_sample))))
print('P(1 | green), predicted: ' + str(model.predict(xgb.DMatrix(X1_sample))))

Ausgabe:

P(1 | red), predicted: [ 0.1073855]
P(1 | green), predicted: [ 0.24398108]
Denis Kulagin
quelle

Antworten:

5

Sie müssen entscheiden, was Sie maximieren möchten.

Eine Klassifizierung durch Vergleichen der Wahrscheinlichkeit mit 0,5 ist angemessen, wenn Sie die Genauigkeit maximieren möchten. Es ist nicht angemessen, wenn Sie die f1-Metrik maximieren möchten.

Wenn Sie die Genauigkeit maximieren möchten, ist die Vorhersage von Null immer der optimale Klassifikator.

Alternativ besteht bei einer Wahrscheinlichkeitsbewertung andere Option darin, eine voreingenommene Münze zufällig zu werfen; mit Wahrscheinlichkeit Ausgangsklassifikation 1, sonst Ausgangsklassifikation 0. Dies sagt nicht immer Null voraus. Allerdings ist es wahrscheinlich in keiner nützlichen Weise besser.pp

Wenn Sie die f1-Metrik maximieren möchten, besteht ein Ansatz darin, Ihren Klassifikator so zu trainieren, dass er eine Wahrscheinlichkeit vorhersagt, und dann einen Schwellenwert zu wählen, der die f1-Punktzahl maximiert. Der Schwellenwert wird wahrscheinlich nicht 0,5 sein.

Eine andere Möglichkeit besteht darin, die Kosten für Fehler vom Typ I im Vergleich zu Fehlern vom Typ II zu verstehen und dann die Klassengewichte entsprechend zuzuweisen.

DW
quelle
1
Ich möchte nur zwei weitere Dinge erwähnen: (a) Anstelle der F1-Punktzahl kann das OP auch eine gewichtete Genauigkeit verwenden oder sogar eine Rangmetrik wie AUC ROC maximieren. (B) xgboostunterstützt Klassengewichte. Das OP sollte mit diesen spielen, wenn er ist unzufrieden mit der Metrik, die er maximieren möchte.
Ricardo Cruz
@ RicardoCruz, danke - gute Vorschläge! (Ich habe die Klassengewichte kurz erwähnt - letzter Absatz der Antwort - aber ich bin froh, dass Sie sie hervorgehoben haben.)
DW
Übrigens sind häufig verwendete Klassengewichte inverse Frequenzen : n_samples / (n_classes * np.bincount(y)). Dies vermeidet, dass der Klassifikator bevölkerungsreicheren Klassen mehr Gewicht beimisst.
Ricardo Cruz