推荐系统 之 XGBoost

        这篇文章不知道为什么被吞了....我又得重新写一下,方便以后自己复习

        写在前面:这篇文章觉得部分都是照搬 这里,详细的描述可以直接看原文。本文只是将原文翻译成自己比较能理解的思路而已。

1. XGBoost的原理

        XGBoost光从名字上我们就知道有boost的身影在里面了,它和AdaBoost的其中一个区别就是在合并模型的时候不需要加上一个权重系数,而是直接做加法运算模式。

        所以XGBoost也还是采用一个前向分布加法模型的,具体的表达式就是:这里的T是模型数量

\hat{y_i} = \sum^T_{t=1}f_t(x_i)

        最终损失函数就是:这里的N是样本数量

Loss = \sum^N_{n=1}L(y_i,\hat{y_i})

2. 定义目标函数:

        模型的预测精度由偏差和方差共同决定,损失函数代表了模型的偏差,想要方差小则需要更简单的模型

        所以XGBoost的 目标函数最终由损失函数L与抑制模型复杂度的正则项Ω组成, 所以目标函数如下:

obj^t = \sum^N_{n=1}l(y_i,\hat{y_i}^t) + \Omega(f_t)

        然后这个正则项可以的表达式是如下:

\Omega(f_t) = \gamma T_t + \frac{1}{2}\lambda\sum^T_{j=1}w_j^2

        其中T_t 就是叶子节点数,w_j 就是叶子结点上的权重,其余都是超惨

3. 简化目标函数

        我们上面说了,XGBoost是一个前向分布加法的模型,现在我们假定已经有t-1步了,求t步,模型对于第i个样本的预测为:

\hat{y_i}^t = \hat{y_i}^{t-1} + f_t(x_i)

        我们把目标函数根据上面这个公式继续改写一下:

obj^t = \sum^N_{n=1}l(y_i,\hat{y}_i^t+f_t(x_i)) + \Omega(f_t)

       这个时候最优化这个目标函数的关键点就落在了f_t(x_i) 上了,但是到现在我们还没有看到残差呀,我们还需要做一些小小的变换的。

        我们回到最关键的点上,这个fx我们指定是求不出来的,非常复杂。所以我们用泰勒二阶展开去逼近这个求不出来的函数:

f(x) = f(x_0)+f'(x_0)(x-x_0)+\frac{1}{2}f''(x_0)(x-x_0)^2

        于是我们把当前这个棵树的每一个l(y_i,\hat{y}_i^t+f_t(x_i))都在l(y_i,\hat{y}_i^t) 展开一下,因为这个是上一棵树了,所以后面的点是已知的,于是 x_0 = \hat{y}_i^{t-1}

        目标函数就可以改写成:

obj^t = \sum^N_{i=1}[L(y_i,\hat{y}_i^{t-1})+loss'*f_t(x_i)+\frac{1}{2}loss''f_t^2(x_i)] + \Omega(f_t)

        我们可以看到这个 x_0 = \hat{y}_i^{t-1},一阶导里面的x-x_0 写成了f_t(x_i), 二阶导里面的(x-x_0)^2写成了f_t^2(x_i)

        由于 L(y_i,\hat{y}_i^{t-1}) 是一个已知的value了,所以是一个常数,其实对优化没起作用,可以去掉。

obj^t = \sum^N_{i=1}[loss'*f_t(x_i)+\frac{1}{2}loss''f_t^2(x_i)] + \Omega(f_t)

        但是现在我们还是不知道fx究竟是什么东西,loss是可以求一阶二阶导的。所以我们要做进一步的化简才可以。

        我们可以往这方面思考,最终样本都是会回到叶子结点上去的,所以我们通过这一点才切入进行公示的化简和优化。

        f_t(x_i) 其实一个样本经过一个决策树模型的所输出的value,其实看这个公式也可以看得出f_t(x_i)是一个决策树:

\hat{y_i}^t = \hat{y_i}^{t-1} + f_t(x_i)

        在t-1棵树综合起来后 输入了i的样本\hat{y_i}^{t-1},并且经过t这个决策树f_t(x_i) 后两个值相加,就是综合t棵树后样本i得输出value了。

        于是我们决定将决策树模型定义成f_t(x) = w_q(x),其中q(x) 代表了该样本会被分到哪一个叶子结点,w就是这个叶子结点上的权重。所以w_q(x)就是代表了每一个样本的取值,于是我们可以继续改写一下obj的公式:

obj^t = \sum^N_{i=1}[loss'f_t(x_i)+\frac{1}{2}loss''f_t^2(x_i)] = \sum^N_{i=1}[loss'w_{q(x_i)}+\frac{1}{2}loss''w_{q(x_i)}^2] = \sum^T_{t=1}[(\sum_{i \in I_jg}g_i)w_j + \frac{1}{2}(\sum_{i \in I_j}h_i)w_j^2]

         来解释一下这里面的东西,首先就是看求和符号的上标,本来是N的后来变成对T求和了,这里的意思就是本来就是遍历样本,现在开始变成遍历每一个叶子节点了。所以在T求和后面还有两个求和符号,是统计当前叶子结点里面有多少个样本在里面,而w_j 就是叶子上面的取值。然后这里出现了 g_i 和 h_i,就是分别对应了loss的一阶导和loss的二阶导。

        到这步应该还是很清晰的,只是角度从遍历样本变成了遍历叶子结点而已。现在我们把正则化项提出来进行研究。在决策树中,决策树的复杂度可由叶子数 T 组成,叶子节点越少模型越简单,此外叶子节点也不应该含有过高的权重 w, 所以目标函数的正则项可以定义为


        \Omega(f_t) = \gamma T+\frac{1}{2}\lambda\sum^T_{j=1}w_j^2

        然后把这个正则化项放进去obj公式里面,继续化简:

        这里的只是做了一个简单的合并,然后我们继续化简,令:

G_j = \sum_{j \in I_j}g_i

H_j = \sum_{j \in I_j}h_i

        所以决策树版本的的XGBoost的目标函数是:

obj^t = \sum^T_{j=1}[G_jw_j+\frac{1}{2}(H_j+\lambda)w_j^2] + \gamma T

        我们这里要注意到,其实无论是G_j 还是H_j 他们都是前一棵树 t-1的loss的一阶导二阶导的结果,那么现在,整个式子,就剩下一个w_j 不知道是什东西了,于是我们对w_j进行求导,得出一个关于w_j 的表达式:

w_j^* = -\frac{G_j}{H_j+\lambda}

        继续代入!

obj^t = -\frac{1}{2}\sum^T_{j=1}\frac{G_j^2}{H_j+\lambda} + \gamma T

        所以你说,这个牛不牛:

        最后obj的表达式就只需要求导损失函数的一阶导和二阶导就好了!下面给出一个例子:

图片

         

4. 树的切分选择(就是怎么分bins)

        在决策树的生长过程中,一个非常关键的问题是如何找到叶子的节点的最优切分点,Xgboost 支持分裂节点的方法:贪心算法和近似算法还有一个叫Weight Quantile Sketch

4.1 贪心算法

         那么如何计算每个特征的分裂收益呢?

         这个和之前的什么用GINI系数,还有GBDT里面三个mini的评判收益是一样的。都是每一个点都要过一遍,然后找收益最大的哪个。

4.2 近似算法

        贪婪算法可以的到最优解,但当数据量太大时则无法读入内存进行计算,近似算法主要针对贪婪算法这一缺点给出了近似最优解

        该算法会首先根据特征分布的分位数提出候选划分点,然后将连续型特征映射到由这些候选点划分的桶中,然后聚合统计信息找到所有区间的最佳分裂点。换句人话说就是变成按照百分位去取点,然后选择出一个收益最大的。(精确算法是每一个点都会去计算,近似就是只取百分位点去计算)

4.3 Weight Quantile Sketch

        作者进行候选点选取的时候,考虑的是想让loss在左右子树上分布的均匀一些,而不是样本数量的均匀,因为每个样本对降低loss的贡献可能不一样,按样本均分会导致分开之后左子树和右子树loss分布不均匀,取到的分位点会有偏差。

在这里插入图片描述

         上面这个划分是为了将每个bin的贡献度都是保持在0.6的。

        然后里面提到的 h_i(贡献度)就是这个样本的loss二阶导(一列代表一个样本)

        然后为什么这个h_i 可以代表loss的贡献度呢?

        我们对目标函数进行化简,但不是化简到叶子结点的方向上,而是直接按照样本的思路进行化简:

        这里的 \frac{g_i}{h_i} 其实按照上面的公式去化简,就是一个残差:

        所以这个 h_i 是可以看做计算残差时某个样本的重要性,即每个样本对降低loss的贡献程度。        

        这一段非常重要:Xgboost引入了二阶导之后,相当于在模型降低残差的时候给各个样本根据贡献度不同加入了一个权重,这样就能更好的加速拟合和收敛,GBDT只用到了一阶导数,这样只知道梯度大的样本降低残差效果好,梯度小的样本降低残差不好,但是好与不好的这个程度,在GBDT中无法展现。而xgboost这里就通过二阶导可以展示出来,这样模型训练的时候就有数了

5. 利用新的决策树预测样本值,并累加到原来的值上

        运用加法训练,我们的目标不再是直接优化整个目标函数,而是分步骤优化目标函数,首先优化第一棵树,完了之后再优化第二棵树,直至优化完K棵树。

在这里插入图片描述

        上图中会发现每一次迭代得到的新模型前面有个η(这个是让树的叶子节点权重乘以这个系数), 这个叫做收缩率,这个东西加入的目的是削弱每棵树的作用,让后面有更大的学习空间,有助于防止过拟合。也就是,我不完全信任每一个残差树,每棵树只学到了模型的一部分,希望通过更多棵树的累加来来弥补,这样让这个让学习过程更平滑,而不会出现陡变。

        这个和正则化防止过拟合的原理不一样,这里是削弱模型的作用,而前面正则化是控制模型本身的复杂度, 而这里是削弱每棵树的作用,都是防止过拟合,但是原理不一样。

        xgboost是好多弱分类器的集成,训练弱分类器的策略就是尽量的减小残差,使得答案越来越接近正确答案。 xgboost的精髓部分是目标函数的Taylor化简,这样就引入了损失函数的一阶和二阶导数。然后又把样本的遍历转成了对叶子节点的遍历,得到了最终的目标函数。这个函数就是衡量一棵树好坏的标准。在建树过程中,xgboost采用了贪心策略,并且对寻找分割点也进行了优化。基于这个,才有了后面的最优点切分建立一棵树的过程。 xgboost训练的时候,是通过加法进行训练,也就是每一次只训练一棵树出来, 最后的预测结果是所有树的加和表示。

xgboost相比于GBDT有哪些优点:

  • 精度更高:GBDT只用到一阶泰勒, 而xgboost对损失函数进行了二阶泰勒展开, 一方面为了增加精度, 另一方面也为了能够自定义损失函数,二阶泰勒展开可以近似大量损失函数
  • 灵活性更强:GBDT以CART作为基分类器,而Xgboost不仅支持CART,还支持线性分类器,另外,Xgboost支持自定义损失函数,只要损失函数有一二阶导数。
  • 正则化:xgboost在目标函数中加入了正则,用于控制模型的复杂度。有助于降低模型方差,防止过拟合。正则项里包含了树的叶子节点个数,叶子节点权重的L2范式。这个东西的好处,就是XGBOOST在构建树的过程中,就可以进行树复杂度的控制,而不是像GBDT那样, 等树构建好了之后再进行剪枝。
  • Shrinkage(缩减):相当于学习速率。这个主要是为了削弱每棵树的影响,让后面有更大的学习空间,学习过程更加的平缓

        

        

        

Enable GingerCannot connect to Ginger Check your internet connection
or reload the browserEnable in this text fieldRephraseRephrase current sentence14Edit in Ginger×

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值