Xgboost通俗理解

1 xgboost树的定义

2 xgboost目标函数                      --------- 2.1 模型学习与训练误差     2.2 树的复杂度

3 打分函数计算                           ---------- 3.1 分裂节点                      3.2 缺失值处理

4 XGBoost的特性

5 Boosted Tree Algorithm           -----------5.1 停止条件                      5.2 判断特征重要程度的三种指标

6.参数详解

GBDT算法原理 - CSDN博客  https://blog.csdn.net/qq_19446965/article/details/82079624


1 xgboost树的定义

本节的示意图基本引用自xgboost原作者陈天奇的讲座PPT中。

举个例子,我们要预测一家人谁是谁,则可以先通过年龄区分开小孩和大人,然后再通过性别区分开是男是女,如下图所示。

就这样,训练出了2棵树tree1和tree2,类似之前gbdt的原理,两棵树的结论累加起来便是最终的结论,所以小孩的预测分数就是两棵树中小孩所落到的结点的分数相加:2 + 0.9 = 2.9。爷爷的预测分数同理:-1 + (-0.9)= -1.9。具体如下图所示

恩,你可能要拍案而起了,惊呼,这不是跟上文介绍的gbdt乃异曲同工么?

2 xgboost目标函数

明确下我们的目标,是希望建立K个回归树,使得树群的预测值尽量接近真实值(准确率)而且有尽量大的泛化能力(更为本质的东西)。

从数学角度看这是一个泛函最优化,多目标,参数空间中的目标函数如下:

目标函数分为两部分:误差函数和正则化项。且误差/损失函数揭示训练误差,正则化定义复杂度,相比于GBDT,进行的优化,防止模型过拟合。

函数空间中的目标函数:

对于上式而言,\hat{y}_{i}是整个累加模型的输出,正则化项\sum_k\Omega f(k)是则表示树的复杂度的函数,值越小复杂度越低,泛化能力越强,其表达式为

T表示叶子节点的个数,w表示节点的数值。直观上看,目标要求预测误差尽量小,且叶子节点T尽量少,节点数值w尽量不极端。

误差函数鼓励我们的模型尽量去拟合训练数据,使得最后的模型会有比较少的 bias。而正则化项则鼓励更加简单的模型。因为当模型简单之后,有限数据拟合出来结果的随机性比较小,不容易过拟合,使得最后模型的预测更加稳定。

如果不考虑工程实现、解决问题上的一些差异,xgboost与gbdt比较大的不同就是目标函数的定义。

GBDT损失函数,最小化误差:

xgboost的目标函数如下图所示:

1. 红色箭头所指向的L 即为损失函数,不同的是对于误差函数 L(θ) 的拟合:

  • GBDT利用一阶泰勒展开两项,做一个近似
  • xgboost利用二阶泰勒展开三项,做一个近似

言为之意,

  • GBDT在函数空间中利用梯度下降法进行优化
  • XGBoost在函数空间中用牛顿法进行优化

最终的目标函数只依赖于每个数据点的在误差函数上的一阶导数和二阶导数。

误差函数可以自定义平方损失函数: (yi,y^i) = (yi−y^i)2,或logistic损失函数:

2. 红色方框所框起来的是正则项(包括L1正则、L2正则)

3. 红色圆圈所圈起来的为常数项

2.1 模型学习与训练误差

具体来说,目标函数第一部分中i 表示第 i个样本,l(y{_{i}}- \hat{y}_{i}^{^{t-1}})表示第 i个样本的预测误差,我们的目标当然是误差越小越好。

在当前步yi,以及y(t-1)都是已知值,模型学习的是f{_{t}}(x_i)

那接下来,我们如何选择每一轮加入什么f_t?答案是非常直接的,选取一f_t来使得我们的目标函数尽量最大地降低。

这个公式可能有些过于抽象,我们可以考虑l 是平方误差的情况,这个时候我们的目标可以被写成下面这样的二次函数

更加一般的,损失函数不是二次函数咋办?泰勒展开,不是二次的想办法近似为二次。

且把常数项移除之后,我们会发现如下一个比较统一的目标函数。

这时,目标函数只依赖于每个数据点的在误差函数上的一阶导数和二阶导数(xgboost的不同之处,目标函数保留了泰勒展开的二次项)。

到目前为止我们讨论了目标函数中的第一个部分:训练误差。接下来我们讨论目标函数的第二个部分:如何定义树的复杂度。

2.2 树的复杂度

首先,梳理下几个规则

用叶子节点集合以及叶子节点得分表示

每个样本都落在一个叶子节点上

q(x)表示样本x在某个叶子节点上,wq(x)是该节点的打分,即该样本的模型预测值

所以当我们把树成结构部分q和叶子权重部分w后,结构函数q把输入映射到叶子的索引号上面去,而w给定了每个索引号对应的叶子分数是什么。

这个树的复杂度复杂度包含了一棵树里面节点的个数,以及每个树叶子节点上面输出分数的L2模平方。用图说明下,可能更形象点:

从图中可以看出,xgboost算法中对树的复杂度项包含了两个部分,一个是叶子节点个数T,一个是叶子节点得分L2正则化项w,针对每个叶结点的得分增加L2平滑,目的也是为了避免过拟合。

还记得4.2节开头对目标函数的说明吧(损失函数揭示训练误差 + 正则化定义复杂度)?

到目前为止目标函数如下:

 

其中ij被定义为每个叶节点 j 上面样本集合

g是一阶导数,h是二阶导数。这一步是由于xgboost目标函数第二部分加了两个正则项,一个是叶子节点个数(T),一个是叶节点的分数(w)。

这一个目标包含了T个相互独立的单变量二次函数。我们可以定义

最终公式可以化简为

通过wj对求导等于0,可以得到

然后把wj最优解代入得到:

3 打分函数计算

Obj代表了当我们指定一个树的结构的时候,我们在目标上面最多减少多少。我们可以把它叫做结构分数(structure score)

3.1 分裂节点

xgboost的原始论文中给出了两种分裂节点的方法

(1)枚举所有不同树结构的贪心法

不断地枚举不同树的结构,利用这个打分函数来寻找出一个最优结构的树,加入到我们的模型中,再重复这样的操作。不过枚举所有树结构这个操作不太可行,所以常用的方法是贪心法,每一次尝试去对已有的叶子加入一个分割。对于一个具体的分割方案,我们可以获得的增益可以由如下公式计算。

对于每次扩展,我们还是要枚举所有可能的分割方案,如何高效地枚举所有的分割呢?我假设我们要枚举所有x < a 这样的条件,对于某个特定的分割a我们要计算a左边和右边的导数和。

我们可以发现对于所有的a,我们只要做一遍从左到右的扫描就可以枚举出所有分割的梯度和GL和GR。然后用上面的公式计算每个分割方案的分数就可以了。

观察这个目标函数,大家会发现第二个值得注意的事情就是引入分割不一定会使得情况变好,因为我们有一个引入新叶子的惩罚项。优化这个目标对应了树的剪枝, 当引入的分割带来的增益小于一个阀值的时候,我们可以剪掉这个分割。

大家可以发现,当我们正式地推导目标的时候,像计算分数和剪枝这样的策略都会自然地出现,而不再是一种因为heuristic(启发式)而进行的操作了。

下面是论文中的算法

(2)近似算法

对于每个特征,只考察分位点,减少计算复杂度。

举例:三分位数

实际上XGBoost.不足简单地按照样本个数进行分位,而是以二阶导数值作为权重?(论文中的WeightedQuantileSketch),比如:

为什么用hi加权?

把目标函数整理成以下形式,可以看出hi有对loss加权的作用

3.2 缺失值处理

当特征出现缺失值时,XGBoost可以学习出默汄的节点分裂方向。

算法的主要思想是,分别假设特征缺失的样本属于右子树和左子树,而且只在不缺失的样本上迭代,分别计算整体缺失样本属于右子树和左子树的增益,选择增益最大的方向为缺失数据的默认方向。

4 XGBoost的特性

  • w是最优化求出来的,不是啥平均值或规则指定的,这个算是一个思路上的新颖;

  • 正则化防止过拟合的技术,上述看到了,直接loss function里面就有;

  • 支持自定义loss function,不用多说,只要能泰勒展开(能求一阶导和二阶导)就行;

  • 支持并行化,这个地方有必要说明下,因为这是xgboost的闪光点,直接的效果是训练速度快,boosting技术中下一棵树依赖上述树的训练和预测,所以树与树之间应该是只能串行!只有在选择最佳分裂点,进行枚举的时候并行!(据说恰好这个也是树形成最耗时的阶段)。我们知道,决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点),xgboost在训练之前,预先对数据进行了排序,然后保存为block结构,后面的迭代中重复地使用这个结构,大大减小计算量。这个block结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行。

  • XGBoost还特别设计了针对稀疏数据的算法, 
    假设样本的第i个特征缺失时,无法利用该特征对样本进行划分,这里的做法是将该样本默认地分到指定的子节点,至于具体地分到哪个节点还需要某算法来计算,

    算法的主要思想是,分别假设特征缺失的样本属于右子树和左子树,而且只在不缺失的样本上迭代,分别计算整体缺失样本属于右子树和左子树的增益,选择增益最大的方向为缺失数据的默认方向。

  • 可实现后剪枝
  • 交叉验证,方便选择最好的参数,early stop,比如你发现30棵树预测已经很好了,不用进一步学习残差了,那么停止建树。

  • 行采样、列采样,随机森林的套路(防止过拟合)

  • Shrinkage,核心思想在于:Shrinkage 认为每次走一小步来逼近结果的效果,要比每次迈一大步很快逼近结果的方式更容易防止过拟合。

    也就是说,它不信任每次学习到的残差,它认为每棵树只学习到了真理的一小部分,累加的时候只累加一小部分,通过多学习几棵树来弥补不足。每一步的残差计算其实变相的增大了分错样本的权重,而已经分对的样本则都趋向于 0。这样后面就更加专注于那些分错的样本。

    具体的做法就是:仍然以残差作为学习目标,但是对于残差学习出来的结果,只累加一小部分(step* 残差)逐步逼近目标,step 一般都比较小 0.01-0.001, 导致各个树的残差是渐变而不是陡变的。

  • xgboost还支持设置样本权重,这个权重体现在梯度g和二阶梯度h上,是不是有点adaboost的意思,重点关注某些样本

5 Boosted Tree Algorithm

5.1 停止条件

1、当引入的分裂带来的增益小于一个阀值的时候,我们可以剪掉这个分裂,所以并不是每一次分裂loss function整体都会增加的,有点预剪枝的意思,阈值参数为(即正则项里叶子节点数T的系数);

2、当树达到最大深度时则停止建立决策树,设置一个超参数max_depth,避免树太深导致学习局部样本,从而过拟合;

3、当样本权重和小于设定阈值时则停止建树,这个解释一下,涉及到一个超参数-最小的样本权重和min_child_weight,和GBM的 min_child_leaf 参数类似,但不完全一样,大意就是一个叶子节点样本太少了,也终止同样是过拟合;

4、貌似看到过有树的最大数量的…

5.2 判断特征重要程度的三种指标

get_fscore 有三种种评判特征重要程度的方法:

‘weight’ - the number of times a feature is used to split the data across all trees. ‘gain’ - the average gain of the feature when it is used in trees. ‘cover’ - the average coverage of the feature when it is used in trees.

weight - 该特征在所有树中被用作分割样本的特征的次数。

gain - 在所有树中的平均增益。

cover - 在树中使用该特征时的平均覆盖范围。(还不是特别明白)

6.参数详解

Booster Parameters(模型参数) 
1.eta [default=0.3]:shrinkage参数,用于更新叶子节点权重时,乘以该系数,避免步长过大。参数值越大,越可能无法收敛。把学习率 eta 设置的小一些,小学习率可以使得后面的学习更加仔细。 
2.min_child_weight [default=1]:孩子节点中最小的样本权重和。如果一个叶子节点的样本权重和小于min_child_weight则拆分过程结束。在现行回归模型中,这个参数是指建立每个模型所需要的最小样本数。该参数值越小,越容易 overfitting。 
3.max_depth [default=6]: 每颗树的最大深度,树高越深,越容易过拟合。 
4.max_leaf_nodes:最大叶结点数,与max_depth作用有点重合。 
5.gamma [default=0]:后剪枝时,用于控制是否后剪枝的参数。 
6.max_delta_step [default=0]:这个参数在更新步骤中起作用,如果取0表示没有约束,如果取正值则使得更新步骤更加保守。可以防止做太大的更新步子,使更新更加平缓。 
7.subsample [default=1]:样本随机采样,较低的值使得算法更加保守,防止过拟合,但是太小的值也会造成欠拟合。 
8.colsample_bytree [default=1]:列采样,对每棵树的生成用的特征进行列采样.一般设置为: 0.5-1 
9.lambda [default=1]:控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合。 
10.alpha [default=0]:控制模型复杂程度的权重值的 L1 正则项参数,参数值越大,模型越不容易过拟合。 
11.scale_pos_weight [default=1]:如果取值大于0的话,在类别样本不平衡的情况下有助于快速收敛。
12.objective [ default=reg:linear ] 定义学习任务及相应的学习目标,可选的目标函数如下:
“reg:linear” –线性回归。
“reg:logistic” –逻辑回归。
“binary:logistic” –二分类的逻辑回归问题,输出为概率。
“binary:logitraw” –二分类的逻辑回归问题,输出的结果为wTx。
“count:poisson” –计数问题的poisson回归,输出结果为poisson分布。 在poisson回归中,max_delta_step的缺省值为0.7。(used to safeguard optimization)
“multi:softmax” –让XGBoost采用softmax目标函数处理多分类问题,同时需要设置参数num_class(类别个数)
“multi:softprob” –和softmax一样,但是输出的是ndata * nclass的向量,可以将该向量reshape成ndata行nclass列的矩阵。没行数据表示样本所属于每个类别的概率。
“rank:pairwise” –set XGBoost to do ranking task by minimizing the pairwise loss

参考文献:

  1. xgboost原始论文:https://arxiv.org/pdf/1603.02754v1.pdf
  2. xgboost作者讲座PPT:https://homes.cs.washington.edu/~tqchen/pdf/BoostedTree.pdf
  3. xgboost原理:https://blog.csdn.net/a819825294/article/details/51206410
  4. xgboost入门与实战(原理篇):https://blog.csdn.net/sb19931201/article/details/52557382
  5. 通俗理解kaggle比赛大杀器xgboost : https://zhuanlan.zhihu.com/p/41417638
  6. xgboost入门与实战(原理篇):  https://blog.csdn.net/sb19931201/article/details/52557382
  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值