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):
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]
quelle
xgboost
unterstützt Klassengewichte. Das OP sollte mit diesen spielen, wenn er ist unzufrieden mit der Metrik, die er maximieren möchte.n_samples / (n_classes * np.bincount(y))
. Dies vermeidet, dass der Klassifikator bevölkerungsreicheren Klassen mehr Gewicht beimisst.