一 样本不平衡

何谓样本不平衡——简单来说就是数据集中负样本的数量远远大于正样本的数量。在这个情况下,模型就会倾向于把样本预测为负样本,因为这是最便捷的降低损失、提高模型准确率的方法。例如:有一个正样本数量为1,负样本数量为99的数据集,模型就算无脑地把全部样本预测为负样本也能达到99%的准确度,试想有这么一个分类器,每次我们把数据喂‘给它时,在不调整阈值的情况下,它都倾向于把测试集的样本预测为负样本,你觉得这样的分类器还会是一个好的分类器吗?

在对不平衡数据进行训练时,通常会考虑一下怎么处理不平衡数据能使训练出来的结果较好。

在用xgboost训练二分类模型时,除了直接使用过采样和下采样,xgboost接口还提供一些处理不平衡数据的方法,有scale_pos_weight参数的设置,还有给样本赋予一定的权重。接下来让我们仔细看一下吧~

参数scale_pos_weight:

XGBoost中存在着调节样本不平衡的参数scale_pos_weight,通常我们在参数中输入的是负样本量与正样本量之比

底层原理:通过scale_pos_weight改变了正负样本的权重,进而改变了正负样本损失函数的大小,最终改变了样本的概率预测值 wi。

For common cases such as ads clickthrough log, the dataset is extremely imbalanced. This can affect the training of xgboost model,
and there are two ways to improve it.If you care only about the ranking order (AUC) of your predictionBalance the positive and negative weights, via scale_pos_weightUse AUC for evaluationIf you care about predicting the right probabilityIn such a case, you cannot re-balance the datasetIn such a case, set parameter max_delta_step to a finite number (say 1) will help convergence

官方的解释是这样的,scale_pos_weight 可以设置为数据中负样本数量/正样本数量

if (info.labels[i] == 1.0f) w *= param_.scale_pos_weight

scale_pos_weight 是用来调节正负样本不均衡问题的,用助于样本不平衡时训练的收敛。

scale_pos_weight = 负样本总数/正样本总数 。若训练负样本总数是500 ,正样本总数100,那么设置 scale_pos_weigh为 5 。

常见的情况比如广告点击日志,数据集是极其不平衡的,导致训练的xgboost模型受到影响,有两种方法可以改善:

1)  如果仅仅关注预测问题的AUC指标,那么你可以调节 scale_pos_weight参数来帮助训练数据不平衡带来的收敛问题 。

2)如果关注预测概率的准确性问题,那么你就不能调节scale_pos_weight参数来改变样本权重的方法帮助收敛,可通过设置参数 max_delta_step 为一个有限的值来帮助收敛 。

如何你仅仅关注预测问题的排序或者AUC指标,那么你尽管调节此参数。如果你希望得到真正的预测概率则不能够通过此参数来平衡样本。什么意思呢,让我们来举个例子:加入我们现在需要通过体重来预测男女,有三个人体重分别为50kg、60kg、70kg。假设他们是男生的真正概率是:0.4、0.6、0.8。那么好,我现在模型预测出的概率为:0.7、0.8、0.9。如果讲预测概率的话,显然模型效果很差,但是我们预测的男生概率的排序以及 ROU 曲线(包括对应 AUC 值)都不会改变。

关于scale_pos_weight ,在xgboost里边的源码是

          bst_float w = _is_null_weight ? 1.0f : _weights[_idx];bst_float label = _labels[_idx];if (label == 1.0f) {w *= _scale_pos_weight;}if (!Loss::CheckLabel(label)) {// If there is an incorrect label, the host code will know._additional_input[0] = 0;}# 改变了损失函数,即改变了损失函数的一阶导和二阶导大小,落到每个叶结点的概率预测值也随之改变。_out_gpair[_idx] = GradientPair(Loss::FirstOrderGradient(p, label) * w,Loss::SecondOrderGradient(p, label) * w);},# 见源码 src/objective/regression_obj.cu

从源代码也可以看出,scale_pos_weight其实就是改变样本weight,也就是和在DMatrix里边设置每个样本的weight是一样的。

在DMatrix里边设置每个样本的weight 是怎样改变训练过程的呢,其实是改变训练的损失函数,源代码里的代码如下,可以看到对不同的样本赋予不同的权重实际上是影响了该样本在训练过程中贡献的损失,进而改变了一阶导和二阶导。

其中​是损失函数关于上一棵树的预测值的的一阶导,​是损失函数关于上一棵树的预测值的二阶导,当正样本的损失函数发生改变,相应的叶子节点的预测值也会发生改变。

本质上说,scale_pos_weight参数也是通过调节样本的预测概率值来改变预测结果,当我们需要提高模型的评估标准 ——如 auc、召回率recall的大小等,可以通过调整scale_pos_weight参数达到我们的目的;但是,假如需要确切了解每个样本为正样本的可能性大小时,不宜使用scale_pos_weight参数。

使用官方数据例子:agaricus.txt.train 与 agaricus.txt.test

系统Default,设置scale_pos_weight = 1。观察训练过程

print("\n--------- scale_pos_weight = 1 -----------")
dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train')
dtest = xgb.DMatrix('../demo_data/agaricus.txt.test')
watchlist = [(dtrain, 'train'), (dtest, 'eval')]
params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1}
xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)

不平衡对比

使用weight给样本赋予权重。

label=1,权重设置为3

label=0,  权重设置为1

print("\n--------- custom set weight=3, scale_pos_weight=1-----------")
dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train', silent=True)
dtest = xgb.DMatrix('../demo_data/agaricus.txt.test', silent=True)
train_weight = [1 if i == 0 else 3 for i in dtrain.get_label().tolist()]
test_weight = [1 if i == 0 else 3 for i in dtest.get_label().tolist()]
dtrain2 = xgb.DMatrix('../demo_data/agaricus.txt.train', weight=train_weight, silent=True)
dtest2 = xgb.DMatrix('../demo_data/agaricus.txt.test', weight=test_weight, silent=True)
watchlist = [(dtrain2, 'train'), (dtest2, 'eval')]
params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1}
xgb.train(params=params, dtrain=dtrain2, num_boost_round=5, evals=watchlist, verbose_eval=1)

将正样本复制成原来的3倍,和负样本拼起来组成训练集训练

print("\n---------read agaricus.txt.xxx_weight3 scale_pos_weight = 1 -----------")
dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train_weight3')
dtest = xgb.DMatrix('../demo_data/agaricus.txt.test_weight3')
watchlist = [(dtrain, 'train'), (dtest, 'eval')]
params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1}
xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)

scale_pos_weight = 3

print("\n--------- scale_pos_weight = 3-----------")
dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train', silent=True)
dtest = xgb.DMatrix('../demo_data/agaricus.txt.test', silent=True)
watchlist = [(dtrain, 'train'), (dtest, 'eval')]
params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 3}
xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)

自定义损失函数,

将正样本的logloss设置为负样本的3倍,然后求一阶导和二阶导.

print("\n---------custom set weight=3, scale_pos_weight=1, use custom obj-----------")from sklearn.metrics import roc_auc_scoreratio = 3def logistic_obj(p, dtrain):y = dtrain.get_label()grad = p * (ratio * y + 1 - y) - ratio * yhess = p * (1 - p) * (beta * y + 1 - y)return grad, hessdef logistic_obj_feval(p, dtrain):y = dtrain.get_label()score = roc_auc_score(y, p)return 'feval-auc', scoredtrain = xgb.DMatrix('../demo_data/agaricus.txt.train', silent=True)
dtest = xgb.DMatrix('../demo_data/agaricus.txt.test', silent=True)
train_weight = [1 if i == 0 else 3 for i in dtrain.get_label().tolist()]
test_weight = [1 if i == 0 else 3 for i in dtest.get_label().tolist()]
dtrain2 = xgb.DMatrix('../demo_data/agaricus.txt.train', weight=train_weight, silent=True)
dtest2 = xgb.DMatrix('../demo_data/agaricus.txt.test', weight=test_weight, silent=True)
watchlist = [(dtrain2, 'train'), (dtest2, 'eval')]
params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1}
xgb.train(params=params, dtrain=dtrain2, num_boost_round=5,evals=watchlist, verbose_eval=1, obj=logistic_obj, feval=logistic_obj_feval)

5. 设置 subsample

如果参数subsample < 1 ,此时将正样本复制成原来的3倍,训练结果还是会不一样,因为样本总数改变了,子采样就会不一样, 其他情况输出不会变。

print("\n--------- scale_pos_weight = 3, subsample=0.8-----------")
dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train', silent=True)
dtest = xgb.DMatrix('../demo_data/agaricus.txt.test', silent=True)
watchlist = [(dtrain, 'train'), (dtest, 'eval')]
params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 3, "subsample":0.8}
xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)print("\n---------read agaricus.txt.xxx_weight3 scale_pos_weight = 1, subsample=0.8 -----------")
dtrain = xgb.DMatrix('../demo_data/agaricus.txt.train_weight3')
dtest = xgb.DMatrix('../demo_data/agaricus.txt.test_weight3')
watchlist = [(dtrain, 'train'), (dtest, 'eval')]
params = {'max_depth': 2, 'eta': 1, 'silent': 1, 'eval_metric': 'auc', "objective": "binary:logistic","scale_pos_weight": 1, "subsample":0.8}
xgb.train(params=params, dtrain=dtrain, num_boost_round=5, evals=watchlist, verbose_eval=1)

三 结论

sample_weight参数允许您为每个训练示例指定不同的权重。 scale_pos_weight参数允许您为整类示例(“正”类)提供权重。

这些对应于成本敏感学习的两种不同方法。如果您认为错误分类正面示例(错过癌症患者)的成本对于所有正面示例都是相同的(但比错误分类负面示例的成本更高,例如告诉某人他们实际上没有癌症),那么您可以指定一个通过 scale_pos_weight 获得所有正面示例的权重.

参考:

样本不平衡问题操作手册 - 知乎

不平衡处理:xgboost 中scale_pos_weight、给样本设置权重weight、 自定义损失函数 和 简单复制正样本的区别_大风车-CSDN博客

[机器学习] XGBoost 样本不平衡问题相关推荐

  1. 【机器学习】机器学习中样本不平衡,怎么办?

    在银行要判断一个"新客户是否会违约",通常不违约的人VS违约的人会是99:1的比例,真正违约的人 其实是非常少的.这种分类状况下,即便模型什么也不做,全把所有人都当成不会违约的人, ...

  2. 机器学习中样本不平衡,怎么办?

    在银行要判断一个"新客户是否会违约",通常不违约的人VS违约的人会是99:1的比例,真正违约的人 其实是非常少的.这种分类状况下,即便模型什么也不做,全把所有人都当成不会违约的人, ...

  3. 机器学习中样本不平衡处理办法

    在机器学习任务中,我们经常会遇到这种困扰:数据不平衡问题. 数据不平衡问题主要存在于有监督机器学习任务中.当遇到不平衡数据时,以总体分类准确率为学习目标的传统分类算法会过多地关注多数类,从而使得少数类 ...

  4. 【干货】机器学习中样本比例不平衡的处理方法

    推荐阅读时间:5min~12min 主要内容:机器学习中样本比例不平衡的处理方法 在机器学习中,常常会遇到样本比例不平衡的问题,如对于一个二分类问题,正负样本的比例是 10:1. 这种现象往往是由于本 ...

  5. [机器学习] focal loss:解决样本不平衡的一种通用方案

    文章目录 focal loss 提出的场景和针对的问题 focal loss 提出的场景:目标检测 focal loss 针对的问题:类别不平衡 如何处理目标检测下的类别不平衡 如何理解目标检测场景下 ...

  6. 样本不平衡不均衡数据处理

    20220302 对连续性的不平衡也可以参照分类型数据的不平衡处理方法?划分为多个集合求平均值? 20220125 # 数据划分negtive_rows = negtive_data.shape[0] ...

  7. 从重采样到数据合成:如何处理机器学习中的不平衡分类问题?

    从重采样到数据合成:如何处理机器学习中的不平衡分类问题? 2017-03-19 13:17 来源:机器之心 技术 原标题:从重采样到数据合成:如何处理机器学习中的不平衡分类问题? 选自Analytic ...

  8. 从重采样到数据合成:如何处理机器学习中的不平衡分类问题? 转载 2017年08月01日 17:09:03 标签: 机器学习 / 数据 719 转自:http://www.sohu.com/a/12

    从重采样到数据合成:如何处理机器学习中的不平衡分类问题? 转载 2017年08月01日 17:09:03 标签: 机器学习 / 数据 719 转自:http://www.sohu.com/a/1293 ...

  9. 文本分类 - 样本不平衡的解决思路与交叉验证CV的有效性

    现实情况中,很多机器学习训练集会遇到样本不均衡的情况,应对的方案也有很多种. 笔者把看到的一些内容进行简单罗列,此处还想分享的是交叉验证对不平衡数据训练极为重要. 文章目录 1 样本不平衡的解决思路 ...

最新文章

  1. 深究AngularJS——$sce的使用
  2. vue cli 4 多环境_Vue 前端uni-app多环境配置部署服务器的问题
  3. Impala介绍,Impala架构,Impala安装,impala Shell ,分区创建,refresh,load数据,获取数据的元数据
  4. 天猫总架构师何崚:好的技术团队不是“需求翻译机”或“架构优化机”
  5. 傅里叶变换 直观_A / B测试的直观模拟
  6. nas存储如何做远程服务器数据备份_备份数据?7 个理由告诉你为什么要用 NAS,而不用移动硬盘...
  7. 干货集锦:200+生信范文、30+款软件、12类图片素材PPT,今年的SCI稳了!(附下载)...
  8. 求素数--筛选法和打表
  9. [Linux] day03——REHL部署
  10. 【编译原理 思维导图】 陈火旺第三版 前七章
  11. 天正自定义填充图案怎么添加_自定义AutoCAD填充图案教程 - CAD自学网
  12. lisp型材库_STMX 1.3.2 发布,高性能的 Common Lisp 库
  13. html 空格怎么打,空白空格怎么打?
  14. 别踩白块儿游戏代码html,别踩白块儿.html · 知足常乐大哥哥/not-step-on-white-block - Gitee.com...
  15. YUV420P与YUVJ420P
  16. 【图片resize】图片三种缩放方式/letterbox_image实现
  17. photoshop中怎么绘制虚线
  18. Linux:僵尸进程 Zombie;waitpid
  19. 平台搭建_记一次CTFd平台搭建
  20. IOS系统通话录音功能的实现方案

热门文章

  1. 在iphone程序中打开word、execl、pdf等文档
  2. 计算机桌面组成部分教案,计算机基础 教案设计(完整版).doc
  3. Socket、Servlet、Tomcat
  4. 网易2016年研发project师编程题(2)
  5. 网站前端性能优化之javascript和css
  6. [系统集成] CI持续集成项目简介
  7. 浅析商业银行“业务连续性管理体系”的构建
  8. WPF and Silverlight 学习笔记(六):WPF窗体
  9. Android应用启动后自动创建桌面快捷方式
  10. 关于昌平100度健身俱乐部全民健身情况调查报告