粒子物理XGBoost BDT二分类:损失函数修改及标准函数咨询
我从事粒子物理领域工作,正在训练BDT用于信号/背景的二分类任务,模型的Python实现代码如下:
import xgboost as xgb train = xgb.DMatrix(data=train_df[features],label=train_df["label"], missing="inf",feature_names=features,weight=(np.array(train_df['label'].array)*-0.99+1)) test = xgb.DMatrix(data=test_df[features],label=test_df["label"], missing="inf",feature_names=features,weight=(np.array(test_df['label'].array) *-0.99+1)) param = {} # Booster parameters param['eta'] = 0.1 # learning rate param['max_depth'] = 10 # maximum depth of a tree param['subsample'] = 0.5 # fraction of events to train tree on param['colsample_bytree'] = 0.5 # fraction of features to train tree on # Learning task parameters param['objective'] = 'binary:logistic' # objective function param['eval_metric'] = 'error' # evaluation metric for cross validation param = list(param.items()) + [('eval_metric', 'logloss')] + [('eval_metric', 'rmse')] num_trees = 50 # number of trees to make booster = xgb.train(param,train,num_boost_round=num_trees)
当前模型效果良好,但我希望略微修改损失函数,让假阳性受到比真阳性更严厉的惩罚。我希望得到一个背景事件尽可能少的筛选结果,即便这意味着要牺牲大量信号事件。
我已查阅XGBoost官方文档中关于自定义目标与评估函数的内容,且已成功添加文档中的示例案例。
请问我当前模型中已使用的标准目标函数和评估函数有哪些?由于模型当前表现已不错,我只想在已实现的函数基础上添加额外项。
以下是我使用的软件包版本供参考:
python version: 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] XGBoost version: 2.0.2 Pandas version: 2.1.4 Numpy version: 1.26.2
一、当前使用的标准目标与评估函数
目标函数
你当前用的是XGBoost内置的**binary:logistic**目标函数,这是二分类任务通用的逻辑斯蒂回归损失函数,损失表达式为:
$$L = -\sum_{i=1}^n \left[ y_i \log(p_i) + (1-y_i) \log(1-p_i) \right]$$
其中$y_i$是样本真实标签(1为信号,0为背景),$p_i$是模型预测样本为信号的概率。
评估函数
你在参数里指定了三个内置评估函数:
error:二分类错误率,统计分类错误的样本占总样本的比例;logloss:逻辑斯蒂损失值,计算逻辑与目标函数一致;rmse:均方根误差,衡量预测概率和真实标签之间的均方偏差。
这些指标会在训练过程中实时输出,用来监控模型训练状态。
二、修改损失函数加重假阳性惩罚
你的核心需求是尽可能减少背景事件(即假阳性:模型将背景样本预测为信号,对应$y_i=0$但$p_i$趋近于1的情况),可以在原binary:logistic损失基础上,给假阳性对应的损失项添加权重系数,实现差异化惩罚。
自定义目标函数实现
我们可以基于原逻辑斯蒂损失,给背景样本($y_i=0$)的损失项乘以一个大于1的权重$\alpha$($\alpha$值越大,对假阳性的惩罚力度越强),修改后的损失表达式为:
$$L = -\sum_{i=1}^n \left[ y_i \log(p_i) + \alpha(1-y_i) \log(1-p_i) \right]$$
对应代码修改如下(保留你原有代码的核心逻辑):
import xgboost as xgb import numpy as np # 自定义加权逻辑斯蒂损失函数 def weighted_logistic_obj(preds, dtrain): labels = dtrain.get_label() # 假阳性惩罚权重,可根据需求调整,示例设为5 alpha = 5.0 # 计算逻辑斯蒂损失的一阶导数(梯度)和二阶导数(海森矩阵) preds = 1.0 / (1.0 + np.exp(-preds)) grad = preds - labels hess = preds * (1.0 - preds) # 对背景样本(label=0)的梯度和海森矩阵乘以惩罚权重 grad = np.where(labels == 0, grad * alpha, grad) hess = np.where(labels == 0, hess * alpha, hess) return grad, hess # 原有数据准备代码保持不变 train = xgb.DMatrix(data=train_df[features],label=train_df["label"], missing="inf",feature_names=features,weight=(np.array(train_df['label'].array)*-0.99+1)) test = xgb.DMatrix(data=test_df[features],label=test_df["label"], missing="inf",feature_names=features,weight=(np.array(test_df['label'].array) *-0.99+1)) param = {} # Booster参数保留原有设置 param['eta'] = 0.1 param['max_depth'] = 10 param['subsample'] = 0.5 param['colsample_bytree'] = 0.5 # 移除原objective参数,改用自定义目标;评估函数保留原有三个 param['eval_metric'] = ['error', 'logloss', 'rmse'] num_trees = 50 # 训练时指定自定义目标函数 booster = xgb.train(param, train, num_boost_round=num_trees, obj=weighted_logistic_obj)
调整建议
- 权重$\alpha$需要根据实际任务需求调试:如果想要更严格过滤背景,可以逐步增大$\alpha$(比如从2到10);
- 训练过程中建议结合PR曲线(精确率-召回率曲线)评估效果,重点关注高背景过滤能力下的信号保留情况;
- 你原有代码中已经给背景样本设置了更高的样本权重(
label=0时权重为1,label=1时为0.01),自定义损失的权重是在这个基础上进一步加强惩罚,两者可以配合使用,达到更精准的效果。
内容的提问来源于stack exchange,提问作者Rodrigo

