XGBoost 用于二分类的标定曲线

机器算法验证 分类 不平衡类 助推 校准
2022-03-21 12:27:03

我正在研究一个具有不平衡类(10:1)的二元分类问题。由于对于二元分类,XGBoost 的目标函数是'binary:logistic',所以应该很好地校准概率。但是,我得到了一个非常令人费解的结果:

xgb_clf = xgb.XGBClassifier(n_estimators=1000, 
                            learning_rate=0.01, 
                            max_depth=3, 
                            subsample=0.8, 
                            colsample_bytree=1, 
                            gamma=1, 
                            objective='binary:logistic', 
                            scale_pos_weight = 10)

y_score_xgb = cross_val_predict(estimator=xgb_clf, X=X, y=y, method='predict_proba', cv=5)

plot_calibration_curves(y_true=y, y_prob=y_score_xgb[:,1], n_bins=10)

在此处输入图像描述

这似乎是一条“不错的”(线性)可靠性曲线,但是斜率小于 45 度。

这是分类报告: 在此处输入图像描述

但是,如果我进行校准,生成的曲线看起来会更糟:

calibrated = CalibratedClassifierCV(xgb_clf, method='sigmoid', cv=5)

y_score_xgb_clb = cross_val_predict(estimator=calibrated, X=X, y=y, method='predict_proba', cv=5)

plot_calibration_curves(y_true=y, y_prob=y_score_xgb_clb[:,1], n_bins=10)

在此处输入图像描述

更奇怪的是,输出的概率现在限制在 ~0.75(我没有得到高于 0.75 的分数)。

我的方法有什么建议/缺陷吗?

2个回答

我不确定“XGBoost 的目标函数是'二进制:逻辑',概率应该被很好地校准”是否正确:梯度提升倾向于将概率推向 0 和 1。此外,你正在应用权重,这也应该扭曲你的概率。

因为梯度提升将概率向外推而不是向内推,所以使用 Platt scaling ( method='sigmoid') 通常不是最好的选择。另一方面,您的原始校准图看起来确实有点像 sigmoid 函数的最左侧部分。但这解释了为什么重新校准的分数在 0.75 处被截断:将 sigmoid 拟合到校准图上(这实际上不是发生的情况,但足够接近)将使 sigmoid 的右半部分被截断。

为方便起见,我会先尝试method='isotonic'. 为了更好地理解,我建议改变分数以说明您给出的权重,然后查看校准图的位置。(对于逻辑回归,移位校正有更好的记录,但请参阅下采样会改变逻辑回归系数吗?将下采样后的预测概率转换为分类中的实际概率

最后,sklearncalibration_curve默认使用等宽 bin,这在不平衡的数据集中可能不是最好的。您可能想要修改它以使用相等大小(如数据点数量)的 bin 来获得更好的图片。特别是,我怀疑您的第二条校准曲线上的最后两个点代表的数据点非常少,应该谨慎对待。(在 sklearn v0.21 中,使用新参数 变得更容易strategy='quantile'。)

我对梯度提升不是很熟悉,但我认为如果你扩展你的少数类,那么你的模型将不会得到很好的校准。归根结底,它了解了不反映现实的训练数据的分布。

至于 CalibratedClassifierCV,从阅读文档看来,sigmoid 方法在这里不适用,因为您的失真不是 sigmoid 形状的。因此,如果您有足够的数据表明过拟合不是问题,那么为什么不尝试 method='isotonic' 呢?