用于二进制分类的 XGBoost:选择正确的阈值

数据挖掘 决策树 xgboost
2021-10-02 05:44:41

我正在研究一个高度不平衡的二进制标记数据集,其中真实标签的数量仅占整个数据集的 7%。但是某些特征组合可能会产生高于子集中平均数量的特征。

例如,我们有以下具有单一特征(颜色)的数据集:

180 个红色样本 — 0

20 个红色样本 — 1

300 个绿色样本 — 0

100 个绿色样品 — 1

我们可以构建一个简单的决策树:

                      (color)

                red /       \ green

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

整个数据集的 P(1) = 0.2

如果我在这个数据集上运行 XGBoost,它可以预测不大于 0.25 的概率。这意味着,如果我以 0.5 的阈值做出决定:

  • 0 - P < 0.5
  • 1 - P >= 0.5

然后,我将始终将所有样本标记为zeroes希望我清楚地描述了问题。

现在,在初始数据集上,我得到以下图(x 轴处的阈值):

在此处输入图像描述

在阈值 = 0.1 处具有最大f1_score 。现在我有两个问题:

  • 我什至应该将f1_score用于这种结构的数据集吗?
  • 在使用 XGBoost 进行二元分类时,使用 0.5 阈值将概率映射到标签总是合理的吗?

更新。我看到这个话题引起了一些兴趣。下面是使用 XGBoost 重现红/绿实验的 Python 代码。它实际上输出了预期的概率:

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

输出:

P(1 | red), predicted: [ 0.1073855]
P(1 | green), predicted: [ 0.24398108]
1个回答

您必须决定要最大化什么。

如果您想最大限度地提高准确性,则通过将概率与 0.5 进行比较来进行分类是合适的。如果您想最大化 f1 指标,这是不合适的。

如果你想最大化准确率,总是预测为零最佳分类器。

或者,给定一个概率分数p,另一种选择是随机抛硬币;有概率p,输出分类 1,否则输出分类 0。这并不总是预测为零。然而,它实际上可能并没有以任何有用的方式变得更好。

如果你想最大化 f1 指标,一种方法是训练你的分类器来预测概率,然后选择一个最大化 f1 分数的阈值。阈值可能不会是 0.5。

另一种选择是了解 I 类错误与 II 类错误的成本,然后相应地分配类权重。