从零开始-Machine Learning学习笔记(34)-XGBoost原理详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kabuto_hui/article/details/88142203

0. 写在前面

  最近刚看完AdaBoost和GBDT部分,就想着一鼓作气将XGBoost的内容了解一下。在写这篇博文的时候,在网上也查找了大量的文章,但是看得还是云里雾里的。在看完了作者的Slide讲解后,思路就比较清晰了。所以这里总结一下我在理解XGBoost原理中的一些理解,以供大家参考。

1. XGBoost简介

  XGBoost(eXtreme Gradient Boosting)是一个优化的分布式梯度提升库,旨在实现高效,灵活和便携。 它在Gradient Boosting框架下实现机器学习算法。
  xgboost是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包,比常见的工具包快10倍以上。在数据科学方面,有大量kaggle选手选用它进行数据挖掘比赛,其中包括两个以上kaggle比赛的夺冠方案。在工业界规模方面,xgboost的分布式版本有广泛的可移植性,支持在YARN, MPI, Sungrid Engine等各个平台上面运行,并且保留了单机并行版本的各种优化,使得它可以很好地解决于工业界规模的问题。

2. XGBoost原理介绍

2.1 推导最优值函数(打分函数)

  原理主要总结于陈天奇在2014年名为《Introduction to Boosted Trees》的PPT和他在2016年发表的论文《XGBoost:A Scalable Tree Boosting System》(下载链接见文末的参考文献)。
  因为XGBoost是基于Gradient Boosting的,所以直接从GBDT开始,在GBDT中我们知道是通过负导数来近似残差,生成K颗决策树,最后的结果就是将这K颗决策树相加:
y ^ i = k = 1 K f k ( x i ) \hat y_i = \sum_{k=1}^{K} f_k(x_i)
那么对于整个模型来说,我们的目标就是要使得损失函数最小:
O b j = i = 1 n l ( y i , y ^ i ) + k = 1 K Obj = \sum_{i=1}^{n}l(y_i,\hat y_i)+\sum_{k=1}^{K}
在上式中,前者是训练误差,后者是正则化项,用于控制模型的复杂度。但是,这个目标函数不能使用如随机梯度下降的方式来求解f,所以这里采用的方式为:Additive Training(Boosting)增量训练:
即从一个常量开始,每轮迭代都添加一个新的function(树)

那我们如何选择f加入到模型中呢?我们可以在每一轮迭代中优化目标函数。在每第t轮的迭代中,y的预测值可以表示为:
y ^ i ( t ) = y ^ i ( t 1 ) + f t x i \hat y_i^{(t)} = \hat y_i^{(t-1)} + f_t{x_i}
于是每一轮的目标函数可以写为:
O b j ( t ) = i = 1 n l ( y i , y ^ i ( t 1 ) ) + i = 1 t Ω ( f i ) = i = 1 n l ( y i , y ^ i ( t 1 ) + f t ( x i ) ) + Ω ( f t ) + c o n s t a n t Obj^{(t)} = \sum_{i=1}^{n}l(y_i,\hat y_i^{(t-1)}) + \sum_{i=1}^{t}\Omega(f_i) \\ = \sum_{i=1}^{n}l(y_i,\hat y_i^{(t-1)} + f_t(x_i)) + \Omega (f_t)+constant
假如损失函数是平方误差损失函数,那么上面的目标函数就可以写为:
O b j ( t ) = i = 1 n ( y i ( y ^ i ( t 1 ) + f t ( x i ) ) ) 2 + Ω ( f i ) + c o n s t a n t = i = 1 n [ 2 ( y ^ i ( t 1 ) y i ) f t ( x i ) + f t ( x i ) 2 ] + Ω ( f i ) + c o n s t a n t Obj^{(t)} = \sum_{i=1}^{n}(y_i - (\hat y_i^{(t-1)} + f_t(x_i)))^2 + \Omega(f_i) + constant\\ = \sum_{i=1}^{n}[2(\hat y_i^{(t-1)}-y_i)f_t(x_i)+f_t(x_i)^2] + \Omega(f_i) + constant
其中, y ^ i ( t 1 ) y i \hat y_i^{(t-1)}-y_i 称为残差。但是在其他损失函数时,这就变的非常复杂了,所以我们将目标函数进行泰勒展开:
T a y l o r   f u n c t i o n : f ( x + Δ x ) f ( x ) + f ( x ) Δ x + 1 2 f ( x ) Δ x 2 O b j ( t ) i = 1 n [ l ( y i , y ^ i ( t 1 ) ) + l ( y i , y ^ i ( t 1 ) ) y ^ i ( t 1 ) f t ( x i ) + 1 2 2 l ( y i , y ^ i ( t 1 ) ) 2 y ^ i ( t 1 ) f t 2 ( x i ) ] + Ω ( f i ) + c o n s t a n t g i = l ( y i , y ^ i ( t 1 ) ) y ^ i ( t 1 ) ;      h i = 2 l ( y i , y ^ i ( t 1 ) ) 2 y ^ i ( t 1 ) O b j ( t ) i = 1 n [ l ( y i , y ^ i ( t 1 ) ) + g i f t ( x i ) + 1 2 h i f t 2 x i ] + Ω ( f i ) + c o n s t a n t Taylor\ function : f(x+\Delta x) \simeq f(x) + f^{'}(x)\Delta x+\frac{1}{2}f^{''}(x)\Delta x^2 \\ 于是目标函数变为:Obj^{(t)} \simeq \sum_{i=1}^{n}[l(y_i,\hat y_i^{(t-1)}) + \frac{\partial l(y_i,\hat y_i^{(t-1)})}{\partial \hat y_i^{(t-1)}}f_t(x_i) + \frac{1}{2}\frac{\partial^2 l(y_i,\hat y_i^{(t-1)})}{\partial^2 \hat y_i^{(t-1)}}f_t^2(x_i)] +\Omega(f_i) + constant \\ 令: g_i = \frac{\partial l(y_i,\hat y_i^{(t-1)})}{\partial \hat y_i^{(t-1)}}; \ \ \ \ h_i = \frac{\partial^2 l(y_i,\hat y_i^{(t-1)})}{\partial^2 \hat y_i^{(t-1)}} \\ 则目标函数可以写为:Obj^{(t)} \simeq \sum_{i=1}^{n}[l(y_i, \hat y_i^{(t-1)})+g_if_t(x_i)+\frac{1}{2}h_if_t^2{x_i}]+\Omega(f_i) + constant
其中, l ( y i , y ^ i ( t 1 ) ) l(y_i, \hat y_i^{(t-1)}) 是上一轮迭代的预测结果与实际值之间的误差,是个
常数
。因此,移除目标函数中的常量,目标函数变为:
O b j ( t ) i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 x i ] + Ω ( f t ) Obj^{(t)} \simeq \sum_{i=1}^{n}[g_if_t(x_i)+\frac{1}{2}h_if_t^2{x_i}] + \Omega(f_t)

下一步就是要写出正则化项 Ω ( f t ) \Omega(f_t)

f t f_t 是第t轮迭代生成的决策树,那么在这个决策树中,我们需要关注的就是叶子节点的个数T,以及每个叶子节点上的权重 w j w_j ,于是可以定义这个正则化项为:
Ω ( f t ) = γ T + 1 2 j = 1 T w j 2 \Omega (f_t) = \gamma T+\frac{1}{2}\sum_{j=1}^{T}w_j^2
有了上面的分析,我们定义在叶子节点j上的样本集合为: I j = { i q ( x i ) = j } I_j=\{i|q(x_i) = j\}

所以,目标函数进一步的转化为:
O b j ( t ) i = 1 n [ g i f t ( x i ) + h i f t 2 x i ] + Ω ( f t ) = i = 1 n [ g i w q ( x i ) + h i w q ( x i ) 2 ] + γ T + 1 2 j = 1 T w j 2 = j = 1 T [ ( i I j g i ) w j + 1 2 ( i I j h i + λ ) w j 2 ] + γ T Obj^{(t)} \simeq \sum_{i=1}^{n}[g_if_t(x_i)+h_if_t^2{x_i}] + \Omega(f_t) \\ =\sum_{i=1}^{n}[g_iw_{q(x_i)}+h_iw_{q(x_i)}^2] + \gamma T+\frac{1}{2}\sum_{j=1}^{T}w_j^2 \\ = \sum_{j=1}^{T}[(\sum_{i \in I_j}g_i)w_j+\frac{1}{2}(\sum_{i \in I_j}h_i+\lambda)w_j^2]+\gamma T
这里可能比较难理解,原来前者是对所有样本求误差和,经过转化后将样本放到了各个叶子节点上,变成了在每个叶子节点中的样本误差和,再将每个叶子节点上的误差进行求和,与原来的式子是等价的,只不过这样变换之后,可以与后面的正则化项进行合并。

上面的目标函数对 w j w_j 求偏导,令其等于0,就得到了 w j w_j 的取值,进而可以得到目标函数 O b j ( t ) Obj^{(t)} 的最优值:
O b j ( t ) w j = i I j g i + ( i I j h i + λ ) w j = 0 w j = i I j g i i I j h i + λ O b j = 1 2 j = 1 T ( i I j g i ) 2 i I j h i + λ + γ T \frac{\partial Obj^{(t)}}{\partial w_j} = \sum_{i \in I_j}g_i+(\sum_{i \in I_j}h_i+\lambda)w_j=0 \\ 得到:w_j = -\frac{\sum_{i \in I_j}g_i}{\sum_{i \in I_j}h_i+\lambda} \\ 目标函数最优值为:Obj = -\frac{1}{2}\sum_{j=1}^{T}\frac{(\sum_{i \in I_j}g_i)^2}{\sum_{i \in I_j}h_i+\lambda}+\gamma T
以上的所有推导,全部是为了推出这个目标函数的最优值,因为有了这个,XGBoost才能开始运行!

因为这个函数可以当作一个打分函数,用于衡量一颗树的质量!

2.2 损失增益

  因为不可能列举出所有可能的树结构,然后使用上面的打分函数来进行评价。因此,XGBoost中使用了一种贪心策略,即从一个节点开始生成决策树,那么选择哪个特征的哪个属性(取值)作为划分点呢?这里用到了损失增益函数,这个函数表明在以某个特征的某个取值作为划分点的情况下,损失减少的程度,这个增益表示为:
G a i n = + = 1 2 j = 1 T ( G L + G R ) 2 H L + H R + λ + γ ( 1 2 j = 1 T ( G L ) 2 H L + λ + γ 1 2 j = 1 T ( G R ) 2 H R + λ + γ ) = 1 2 [ ( G L ) 2 H L + λ + ( G R ) 2 H R + λ ( G L + G R ) 2 H L + H R + λ ] λ Gain = 整棵树的得分-(左子树的得分+右子树的得分)\\ =-\frac{1}{2}\sum_{j=1}^{T}\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}+\gamma-(-\frac{1}{2}\sum_{j=1}^{T}\frac{(G_L)^2}{H_L+\lambda}+\gamma-\frac{1}{2}\sum_{j=1}^{T}\frac{(G_R)^2}{H_R+\lambda}+\gamma) \\ =\frac{1}{2}[\frac{(G_L)^2}{H_L+\lambda}+\frac{(G_R)^2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}] - \lambda
因为每次都生成一个结点,所以T=1。

等等!!!】:是不是很熟悉?

这个感觉就很像是决策树中ID3算法,打分函数相当于信息熵,而损失增益就相当于信息增益!!!但是XGBoost却是一种集成的算法,效果远比单棵决策树的效果要好!

2.3 XGBoost的完整流程

  1. 每轮迭代添加一颗新树;
  2. 在每轮迭代开始前,先计算 g i = l ( y i , y ^ i ( t 1 ) ) y ^ i ( t 1 ) ; h i = 2 l ( y i , y ^ i ( t 1 ) ) 2 y ^ i ( t 1 ) g_i = \frac{\partial l(y_i,\hat y_i^{(t-1)})} {\partial \hat y_i^{(t-1)}}; h_i = \frac{\partial^2 l(y_i,\hat y_i^{(t-1)})}{\partial^2 \hat y_i^{(t-1)}} 这两个值只与损失函数、上一轮迭代的预测值和实际值有关;
  3. 利用打分函数(Obj)和损失增益(Gain),利用贪婪算法的思想,迭代的生成一颗新的树;
  4. 把这颗新的数加入到模型中: y ^ i ( t ) = y ^ i ( t 1 ) + f t ( x i ) \hat y_i^{(t)} = \hat y_i^{(t-1)}+f_t(x_i) ;开始执行下一轮迭代。

通常,将一颗新树的加入到新模型时,一般采用: y ^ i ( t ) = y ^ i ( t 1 ) + ε f t ( x i ) \hat y_i^{(t)} = \hat y_i^{(t-1)}+\varepsilon f_t(x_i) ,其中 ε \varepsilon 一般取0.1。这个系数称为步长或者收缩系数,它表明我们在每轮迭代的时候不进行充分的优化,给未来的迭代保留一些机会,这样可以避免过拟合(Overfit)。

3. 后记

以上就是XGBoost的原理,整个过程下来,不得不佩服陈天奇先生的奇思妙想!这只是XGBoost的核心,还有很多还需要我去探索和学习。后面真正使用XGBoost的时候,会有更加深刻的理解。


参考资料

xgboost入门与实战(原理篇)

XGBoost原理介绍

xgboost的原理没你想像的那么难

陈天奇2014年的《Introduction to Boosted Trees》,PPT

XGBoost论文原文:XGBoost:A Scalable Tree Boosting System

猜你喜欢

转载自blog.csdn.net/kabuto_hui/article/details/88142203