版权声明:本文为博主原创文章,未经博主允许不得转载。 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∑Kfk(xi)
那么对于整个模型来说,我们的目标就是要使得损失函数最小:
Obj=i=1∑nl(yi,y^i)+k=1∑K
在上式中,前者是训练误差,后者是正则化项,用于控制模型的复杂度。但是,这个目标函数不能使用如随机梯度下降的方式来求解f,所以这里采用的方式为:Additive Training(Boosting)增量训练:
即从一个常量开始,每轮迭代都添加一个新的function(树)
那我们如何选择f加入到模型中呢?我们可以在每一轮迭代中优化目标函数。在每第t轮的迭代中,y的预测值可以表示为:
y^i(t)=y^i(t−1)+ftxi
于是每一轮的目标函数可以写为:
Obj(t)=i=1∑nl(yi,y^i(t−1))+i=1∑tΩ(fi)=i=1∑nl(yi,y^i(t−1)+ft(xi))+Ω(ft)+constant
假如损失函数是平方误差损失函数,那么上面的目标函数就可以写为:
Obj(t)=i=1∑n(yi−(y^i(t−1)+ft(xi)))2+Ω(fi)+constant=i=1∑n[2(y^i(t−1)−yi)ft(xi)+ft(xi)2]+Ω(fi)+constant
其中,
y^i(t−1)−yi称为残差。但是在其他损失函数时,这就变的非常复杂了,所以我们将目标函数进行泰勒展开:
Taylor function:f(x+Δx)≃f(x)+f′(x)Δx+21f′′(x)Δx2于是目标函数变为:Obj(t)≃i=1∑n[l(yi,y^i(t−1))+∂y^i(t−1)∂l(yi,y^i(t−1))ft(xi)+21∂2y^i(t−1)∂2l(yi,y^i(t−1))ft2(xi)]+Ω(fi)+constant令:gi=∂y^i(t−1)∂l(yi,y^i(t−1)); hi=∂2y^i(t−1)∂2l(yi,y^i(t−1))则目标函数可以写为:Obj(t)≃i=1∑n[l(yi,y^i(t−1))+gift(xi)+21hift2xi]+Ω(fi)+constant
其中,
l(yi,y^i(t−1))是上一轮迭代的预测结果与实际值之间的误差,是个常数。因此,移除目标函数中的常量,目标函数变为:
Obj(t)≃i=1∑n[gift(xi)+21hift2xi]+Ω(ft)
下一步就是要写出正则化项
Ω(ft):
ft是第t轮迭代生成的决策树,那么在这个决策树中,我们需要关注的就是叶子节点的个数T,以及每个叶子节点上的权重
wj,于是可以定义这个正则化项为:
Ω(ft)=γT+21j=1∑Twj2
有了上面的分析,我们定义在叶子节点j上的样本集合为:
Ij={i∣q(xi)=j}
所以,目标函数进一步的转化为:
Obj(t)≃i=1∑n[gift(xi)+hift2xi]+Ω(ft)=i=1∑n[giwq(xi)+hiwq(xi)2]+γT+21j=1∑Twj2=j=1∑T[(i∈Ij∑gi)wj+21(i∈Ij∑hi+λ)wj2]+γT
这里可能比较难理解,原来前者是对所有样本求误差和,经过转化后将样本放到了各个叶子节点上,变成了在每个叶子节点中的样本误差和,再将每个叶子节点上的误差进行求和,与原来的式子是等价的,只不过这样变换之后,可以与后面的正则化项进行合并。
上面的目标函数对
wj求偏导,令其等于0,就得到了
wj的取值,进而可以得到目标函数
Obj(t)的最优值:
∂wj∂Obj(t)=i∈Ij∑gi+(i∈Ij∑hi+λ)wj=0得到:wj=−∑i∈Ijhi+λ∑i∈Ijgi目标函数最优值为:Obj=−21j=1∑T∑i∈Ijhi+λ(∑i∈Ijgi)2+γT
以上的所有推导,全部是为了推出这个目标函数的最优值,因为有了这个,XGBoost才能开始运行!
因为这个函数可以当作一个打分函数,用于衡量一颗树的质量!
2.2 损失增益
因为不可能列举出所有可能的树结构,然后使用上面的打分函数来进行评价。因此,XGBoost中使用了一种贪心策略,即从一个节点开始生成决策树,那么选择哪个特征的哪个属性(取值)作为划分点呢?这里用到了损失增益函数,这个函数表明在以某个特征的某个取值作为划分点的情况下,损失减少的程度,这个增益表示为:
Gain=整棵树的得分−(左子树的得分+右子树的得分)=−21j=1∑THL+HR+λ(GL+GR)2+γ−(−21j=1∑THL+λ(GL)2+γ−21j=1∑THR+λ(GR)2+γ)=21[HL+λ(GL)2+HR+λ(GR)2−HL+HR+λ(GL+GR)2]−λ
因为每次都生成一个结点,所以T=1。
【等等!!!】:是不是很熟悉?
这个感觉就很像是决策树中ID3算法,打分函数相当于信息熵,而损失增益就相当于信息增益!!!但是XGBoost却是一种集成的算法,效果远比单棵决策树的效果要好!
2.3 XGBoost的完整流程
- 每轮迭代添加一颗新树;
- 在每轮迭代开始前,先计算
gi=∂y^i(t−1)∂l(yi,y^i(t−1));hi=∂2y^i(t−1)∂2l(yi,y^i(t−1))这两个值只与损失函数、上一轮迭代的预测值和实际值有关;
- 利用打分函数(Obj)和损失增益(Gain),利用贪婪算法的思想,迭代的生成一颗新的树;
- 把这颗新的数加入到模型中:
y^i(t)=y^i(t−1)+ft(xi);开始执行下一轮迭代。
通常,将一颗新树的加入到新模型时,一般采用:
y^i(t)=y^i(t−1)+εft(xi),其中
ε一般取0.1。这个系数称为步长或者收缩系数,它表明我们在每轮迭代的时候不进行充分的优化,给未来的迭代保留一些机会,这样可以避免过拟合(Overfit)。
3. 后记
以上就是XGBoost的原理,整个过程下来,不得不佩服陈天奇先生的奇思妙想!这只是XGBoost的核心,还有很多还需要我去探索和学习。后面真正使用XGBoost的时候,会有更加深刻的理解。
参考资料
xgboost入门与实战(原理篇)
XGBoost原理介绍
xgboost的原理没你想像的那么难
陈天奇2014年的《Introduction to Boosted Trees》,PPT
XGBoost论文原文:XGBoost:A Scalable Tree Boosting System