Xgboost通俗理解

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乃异曲同工么?

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

其中

红色箭头所指向的L 即为损失函数(比如平方损失函数: (yi,y^i) = (yi−y^i)2,或logistic损失函数:

  • 红色方框所框起来的是正则项(包括L1正则、L2正则)
  •  红色圆圈所圈起来的为常数项
  •  对于f(x),xgboost利用泰勒展开三项,做一个近似

我们可以很清晰地看到,最终的目标函数只依赖于每个数据点的在误差函数上的一阶导数和二阶导数。

额,峰回路转,突然丢这么大一个公式,不少人可能瞬间就懵了。没事,下面,咱们来拆接下这个目标函数。

2 xgboost目标函数

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

从数学角度看这是一个泛函最优化,多目标,把目标函数简化下:

很明显,这个目标函数分为两部分:误差函数和正则化项。且误差/损失函数揭示训练误差,正则化定义复杂度。

对于上式而言,yi’是整个累加模型的输出,正则化项∑kΩ()是则表示树的复杂度的函数,值越小复杂度越低,泛化能力越强,其表达式为

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

插一句,一般的目标函数都包含下面两项

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

2.1 模型学习与训练误差

具体来说,目标函数第一部分中i 表示第i样本,l (y^i−yi) 表示第 i个样本的预测误差,我们的目标当然是误差越小越好。

在当前步yi,以及y(t-1)都是已知值,模型学习的是ft。

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

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

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

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

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

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

2.2 树的复杂度

首先,梳理下几个规则

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

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

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

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

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

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

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

把目标函数简化下:

这是目标函数优化的是整体的模型。很明显,这个目标函数分为两部分:误差函数和正则化项。且误差/损失函数揭示训练误差,正则化定义复杂度。

对于上式而言,yi’是整个累加模型的输出,正则化项∑kΩ(fk)是则表示树的复杂度的函数,值越小复杂度越低,泛化能力越强,其表达式为

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

在这种新的定义下,我们可以把目标函数进行如下改写

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

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

从而,加了正则项的目标函数里就出现了两种累加

▶ 一种是i - > n(样本数)

▶ 一种是j -> T(叶子节点数)

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

最终公式可以化简为

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

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

3 打分函数计算

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

3.1 分裂节点

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

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

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

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

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

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

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

下面是论文中的算法

(2)近似算法

主要针对数据太大,不能直接进行计算

4 小结:Boosted Tree Algorithm

总结一下,如图所示

咱们来再次回顾整个过程。

如果某个样本label数值为4,那么第一个回归树预测3,第二个预测为1; 另外一组回归树,一个预测2,一个预测2,那么倾向后一种,为什么呢?前一种情况,第一棵树学的太多,太接近4,也就意味着有较大的过拟合的风险。

OK,听起来很美好,可是怎么实现呢,上面这个目标函数跟实际的参数怎么联系起来,记得我们说过,回归树的参数:

1、选取哪个feature分裂节点呢

2、节点的预测值(总不能靠取平均值这么粗暴不讲道理的方式吧,好歹高级一点)

最终的策略就是:贪心 + 最优化(二次最优化,恩你没看错) 。

通俗解释贪心策略:就是决策时刻按照当前目标最优化决定,说白了就是眼前利益最大化决定,“目光短浅”策略。

这里是怎么用贪心策略的呢,刚开始你有一群样本,放在第一个节点,这时候T=1,w多少呢,不知道,是求出来的,这时候所有样本的预测值都是w,带入样本的label数值,此时loss function变为

  • 如果这里的l(w−yi)误差表示用的是平方误差,那么上述函数就是一个关于w的二次函数求最小值,取最小值的点就是这个节点的预测值,最小的函数值为最小损失函数。
  • 本质上来讲,这就是一个二次函数最优化问题!但要是损失函数不是二次函数咋办?泰勒展开,不是二次的想办法近似为二次。

接着来,接下来要选个feature分裂成两个节点,变成一棵弱小的树苗,那么需要:

1、确定分裂用的feature,how?最简单的是粗暴的枚举,选择loss function效果最好的那个;

2、如何确立节点的ww以及最小的loss function,大声告诉我怎么做?对,二次函数的求最值(计算二次的最值一般都有固定套路,即导数等于0的点) 。所以,选择一个feature分裂,计算loss function最小值,然后再选一个feature分裂,又得到一个loss function最小值,你枚举完,找一个效果最好的,把树给分裂,就得到了小树苗。

在分裂的时候,你可以注意到,每次节点分裂,loss function被影响的只有这个节点的样本,因而每次分裂,计算分裂的增益(loss function的降低量)只需要关注打算分裂的那个节点的样本。

原论文这里会推导出一个优雅的公式,如下图所示:

接下来,继续分裂,按照上述的方式,形成一棵树,再形成一棵树,每次在上一次的预测基础上取最优进一步分裂/建树,是不是贪心策略?

凡是这种循环迭代的方式必定有停止条件,什么时候停止呢?

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

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

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

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

参考原文地址:https://zhuanlan.zhihu.com/p/41417638

猜你喜欢

转载自blog.csdn.net/qq_19446965/article/details/82079486