使用 Scikit-Learn API 时如何调整 XGBoost 分类器中的概率阈值

Posted

技术标签:

【中文标题】使用 Scikit-Learn API 时如何调整 XGBoost 分类器中的概率阈值【英文标题】:How to adjust probability threhold in XGBoost classifier when using Scikit-Learn API 【发布时间】:2019-09-01 04:24:48 【问题描述】:

我有一个关于使用 sklearn API 的 xgboost 分类器的问题。它似乎有一个参数来告诉应该返回多少概率为True,但我找不到它。

通常,xgb.predict 将返回布尔值,xgb.predict_proba 将返回区间 [0,1] 内的概率。我认为结果是相关的。应该有一个概率阈值来决定样本的类别。

dtrain, dtest = train_test_split(data, test_size=0.1, random_state=22)

param_dict='base_score': 0.5,
 'booster': 'gbtree',
 'colsample_bylevel': 1,
 'colsample_bytree': 1,
 'gamma': 0,
 'learning_rate': 0.1,
 'max_delta_step': 0,
 'max_depth': 4,
 'min_child_weight': 6,
 'missing': None,
 'n_estimators': 1000,
 'objective': 'binary:logistic',
 'reg_alpha': 0,
 'reg_lambda': 1,
 'scale_pos_weight': 1,
 'subsample': 1

xgb = XGBClassifier(**param_dict,n_jobs=2)

xgb.fit(dtrain[features], dtrain['target'])

result_boolean = xgb.predict(dtest[features])
print(np.sum(result_boolean))
Output:936

result_proba = xgb.predict_proba(dtest[features])
result_boolean2= (result_proba[:,1] > 0.5) 
print(np.sum(result_boolean2))
Output:936

看起来默认概率阈值为 0.5,因此结果数组具有相同的 True 值。但我找不到在代码中调整它的位置。 predict(data, output_margin=False, ntree_limit=None, validate_features=True) 另外,我也测试过base_score,但不影响结果。

我想更改概率阈值的主要原因是我想通过GridSearchCV 方法以不同的概率阈值测试XGBClassifierxgb.predict_proba 似乎无法合并到 GridSearchCV 中。如何更改XGBClassifier中的概率阈值?

【问题讨论】:

predict_proba() 和 GridSearchCV 到底有什么问题? 对不起,我发现'不能合并到GridSearchCV'是相当误导的。例如,如果我写grid = GridSearchCV(xb, param_grid, scoring='precision',fit_params=fit_params,cv=4)grid.fit(X=dtrain[features],y=dtrain[target])然后我会根据精度得到最好的参数当概率阈值为 0.5 时。但我想将概率阈值更改为 0.7 或 0.8。 【参考方案1】:

当您使用 ROC AUC (ROC=Receiver Operating Characteristic, AUC=Area Under Curve) 作为评分函数时,网格搜索将使用 predict_proba() 完成。选择的分类器超参数将是在所有可能的决策阈值中具有最佳整体性能的超参数

GridSearchCV(scoring='roc_auc', ....)

然后您可以绘制 ROC 曲线以确定决策阈值,该阈值可为您提供所需的精度与召回率/真阳性与假阴性平衡。

更多信息scikit-learn documentation on ROC

【讨论】:

谢谢。我认为 ROC-AUC 在我的情况下很有用。但是是否可以更改XGBClassifier的决策阈值,所以我不需要使用predict_proba然后自己设置决策阈值?【参考方案2】:

我认为您应该查看源代码才能理解。我很难找到它,但我发现它在 lightgbm 中工作,我猜 xgboost 应该也能工作。

到这里(https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMClassifier.html#lightgbm.LGBMClassifier.predict)看看方法“predict”:

def predict(self, X, raw_score=False, num_iteration=None,
            pred_leaf=False, pred_contrib=False, **kwargs):
    """Docstring is inherited from the LGBMModel."""
    result = self.predict_proba(X, raw_score, num_iteration,
                                pred_leaf, pred_contrib, **kwargs)
    if callable(self._objective) or raw_score or pred_leaf or pred_contrib:
        return result
    else:
        class_index = np.argmax(result, axis=1)
        return self._le.inverse_transform(class_index)


predict.__doc__ = LGBMModel.predict.__doc__

实际上,分类器每次都被训练为多类分类器,它会选择概率较高的类。 predict_proba 的输出为:

predicted_probability (array-like of shape = [n_samples, n_classes]) – 每个样本的每个类别的预测概率。

你看到方法说:

class_index = np.argmax(result, axis=1)

其中“结果”是 predict_proba 的输出。 现在,如果你有很多类的 predict_proba,它们的总和是 1 吗?我想是的,但我想我们应该进入分类器损失函数才能真正了解发生了什么......

这是我接下来要阅读的内容! http://wiki.fast.ai/index.php/Log_Loss

【讨论】:

以上是关于使用 Scikit-Learn API 时如何调整 XGBoost 分类器中的概率阈值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有 GridSearchCV 对象的 TimeSeriesSplit 来调整 scikit-learn 中的模型?

如何调整 scale scikit-learn Logistic Regression coeffs 以对非缩放数据集进行评分?

在 scikit-learn 中跨多个模型进行交叉验证时如何保持相同的折叠?

如何使用 scikit-learn API 实现元估计器?

了解 scikit-learn GridSearchCV - 参数调整和平均性能指标

使用 GridSearchCV 调整 scikit-learn 的随机森林超参数