xgboost原理及论文剖析

1.xgboost介绍

xgboost来源于gbdt,gbdt发挥到了极致,xgboost采用多种方法加速了训练的过程,提高了准确率,陈天奇真是人才!哦不是天才!本文是根据陈天奇的论文以及xgboost官网的ppt所总结,如果出现错误请给我留言。如果想看完整版请移步xgboost官网和论文。本文持续更新,包括推导过程,举例,xgboost架构,xgboost性能分析。如果你是新手请先学习GBDT,如果已经会了请往下看,本文是原汁官网翻译加自己分析,博主忙,可能更新较慢,保证更完

2.提升树

2.1模型和参数

在监督式的学习中我们通常是利用多维度数据xi,yi来学习一种数学结构,这个数学结构可以利用输入x预测y,这个就是model。举个例子就像是线性回归, y ^ = ∑ j θ j x i , j \hat y=\sum_j\theta_jx_{i,j} y^=jθjxi,j,预测的值 y i y_i yi有多中解释,这个依赖于我们的任务是什么类型是classification or regression ,例如yi在logistic回归中它是被预测为正类的概率,同样它的意义也可以是其他,再例如是某一个rank的得分,在xgboost中就是给结构进行打分来评价树的结构的好坏.
什么是参数呢,这个就是要从数据中去发现的东西,这是一个不确定的值,通常调参方法会影响参数值,通常参数利用 θ \theta θ来表示

2.2目标函数:损失+正则化

在训练中,需要一个标准来衡量Model 有多么的匹配data,这个标准就是目标函数,目标函数通常由两个部分组成,loss与regularization,写成数学形式就是 o b j ( θ ) = L ( θ ) + Ω ( θ ) obj(\theta)=L(\theta)+\Omega(\theta) obj(θ)=L(θ)+Ω(θ)L是损失函数,它来衡量model的预测值与真实值之间的差别, Ω \Omega Ω是正则项。常见的损失函数平方误差函数 L ( θ ) = ∑ i ( y − y ^ i ) 2 L(\theta)=\sum_i(y-\hat y_i)^2 L(θ)=i(yy^i)2,logistic loss 等等,正则项是用来控制模型的复杂度的,它能帮助我们防止过拟合.

2.3决策树集合

在Chen的papaer和xgboost网站中都举了一个例子来帮助我们理解xgboost模型是如何工作的:下面是判断某个人是否喜欢某个游戏的cart树集合
xgboost原理及论文剖析_第1张图片
输入数据 x i x_i xi每个叶子中存放的是预测得分,在决策树中仅仅是将一系列的值分裂到不同的叶子中去,而在cart中,不仅仅分裂还要给每个叶子进行打分评判,这个打分评判将会在我们的预测中使用。
上面这个仅仅是一棵树,然鹅仅仅一棵树是不足以进行精确分类的,所以需要tree ensemble。将多棵树的结果进行相加得出最终的结果,这就是xgboost使用的方法。
xgboost原理及论文剖析_第2张图片
在上图中使用了两颗树来进行分类,你会发现两棵树是互为补充的,由此得出模型
y ^ = ∑ k = 1 K f k ( x i ) , f k ∈ F \hat y=\sum_{k=1}^Kf_k(x_i),f_k\in F y^=k=1Kfk(xi),fkF
其中k代表有棵树
在2.2中说过目标函数是loss + regularization所以目标函数如下
L ( θ ) = ∑ i n l ( y i , y ^ i ) + ∑ k = 1 K Ω ( f k ) L(\theta)=\sum_i^nl(y_i,\hat y_i)+\sum_{k=1}^K\Omega(f_k) L(θ)=inl(yi,y^i)+k=1KΩ(fk)后面我会专门介绍一下正则项,现在就当他是个已知的函数。

2.4提升树

现在我们首先搞明白一件事情,我们之前所学习的模型大部分要学习的参数是 θ \theta θ然而在这里参数是f,这个f代表的是什么呢,回想一下上一节中,我们需要给叶子进行打分,那么我们打分就需要知道xi被分到了哪一个叶子中去了,这个f 就是树的结构,也将就是要学习的对象。那么问题来了,参数的学习根据以往的知识是利用GBM等等方法,学习这个f 需要什么方法呢,就是提升树。让我们来看看什么是提升树。
在每一次迭代中加入一棵新的树,设在t步的时候预测值为 y ^ i ( t ) \hat y_i^{(t)} y^i(t),因此迭代式如下
y ^ i 0 = 0 \hat y_i^{0}=0 y^i0=0 y ^ i 1 = f 1 ( x i ) = y ^ i 0 + f 1 ( x i ) \hat y_i^{1}=f_1(x_i)=\hat y_i^{0}+f_1(x_i) y^i1=f1(xi)=y^i0+f1(xi)
y ^ i 2 = f 1 ( x i ) + f 2 ( x i ) = y ^ i 0 + f 1 ( x i ) + f 2 ( x i ) \hat y_i^{2}=f_1(x_i)+f_2(x_i)=\hat y_i^{0}+f_1(x_i)+f_2(x_i) y^i2=f1(xi)+f2(xi)=y^i0+f1(xi)+f2(xi) . . . . . . . . . . . . . . . . . . . . .................... .................... y ^ i ( t ) = f 1 ( x i ) + f 2 ( x i ) + . . . + f t ( x i ) = y ^ i 0 + f 1 ( x i ) + f 2 ( x i ) . . . + f t ( x i ) \hat y_i^{(t)}=f_1(x_i)+f_2(x_i)+...+f_t(x_i)=\hat y_i^{0}+f_1(x_i)+f_2(x_i)...+f_t(x_i) y^i(t)=f1(xi)+f2(xi)+...+ft(xi)=y^i0+f1(xi)+f2(xi)...+ft(xi)
上面式子式子再与前面的喜欢某游戏的例子进行结合,比对是不是发现计算如出一辙。将这个结构再次带入上面提到的目标式子中去,这样就可以对目标函数进行优化了,如下
o b j ( θ ) = ∑ i n l ( y i , y ^ i ) + ∑ k = 1 K Ω ( f i ) obj(\theta)=\sum_i^nl(y_i,\hat y_i)+\sum_{k=1}^K\Omega(f_i) obj(θ)=inl(yi,y^i)+k=1KΩ(fi) = ∑ i n l ( y i , y ^ i ( t − 1 ) + f t ( x i ) ) + Ω ( f t ) + c o n s t a n t =\sum_i^nl(y_i,\hat y_i^{(t-1)}+f_t(x_i))+\Omega(f_t)+constant =inl(yi,y^i(t1)+ft(xi))+Ω(ft)+constant
你可能会疑惑为什么要加上constant,其实这个是我们新加上的树的结构的模型复杂度,这个可以利用叶子进行计算,后面会专门讲正则项。我们来看一个loss function的特例,平方损失,在大多数文献中利用MSE来指代不要疑惑,那么上面的目标就变成了 o b j t = ( y i − ( y ^ i ( t − 1 ) + f t ( x i ) ) ) 2 + ∑ i = 1 t Ω ( f i ) obj^{ t}=(y_i-(\hat y_i^{(t-1)}+f_t(x_i)))^2+\sum_{i=1}^t\Omega(f_i) objt=(yi(y^i(t1)+ft(xi)))2+i=1tΩ(fi)
= ∑ i = 1 n [ 2 ( y ^ ( t − 1 ) − y i ) f t ( x i ) + f t ( x i ) 2 ] + Ω ( f t ) + c o n s t a n t =\sum_{i=1}^n[2(\hat y^{(t-1)}-y_i)f_t(x_i)+f_t(x_i)^2]+\Omega(f_t)+constant =i=1n[2(y^(t1)yi)ft(xi)+ft(xi)2]+Ω(ft)+constant
在这个特例中出现一个很好的式子形式, y ^ ( t − 1 ) − y i \hat y^{(t-1)}-y_i y^(t1)yi这种形式被称作残差,这个东西是GBDT中核心思想,GBDT就是不断拟合残差以减少偏差来达到目标函数的的优化的,在这里的残差是一个常数( y ^ ( t − 1 ) − y i \hat y^{(t-1)}-y_i y^(t1)yi中每一项都在t步中已知,第一项是上一步的预测值,yi为标签值)而且在上面的式子中海油一个二次项 f t ( x i ) 2 f_t(x_i)^2 ft(xi)2,有二次项为什么好呢,有二次项可以利用我们初中一年级的知识二次函数的最大值,最小值直接进行求解,,,,,这是不是太简单了呢?很抱歉大部分的loss function并不是这么友好,像logistic loss等等并不能有这种形式,那我们如何才能搞到这么好的数学形式,对于一般形式的loss function可以用泰勒展开式进行化简,泰勒展开式如下 f ( x + Δ x ) = f ( x ) + f ′ ( x ) Δ x + 1 2 f ′ ′ ( x ) Δ x 2 f(x+\Delta x)=f(x)+f^{'}(x)\Delta x+\frac {1}{2}f^{''}(x)\Delta x^2 f(x+Δx)=f(x)+f(x)Δx+21f(x)Δx2objective function 加入泰勒公式如下
o b j ( θ ) = ∑ i n l ( y i , y ^ i ) + ∑ k = 1 K Ω ( f i ) obj(\theta)=\sum_i^nl(y_i,\hat y_i)+\sum_{k=1}^K\Omega(f_i) obj(θ)=inl(yi,y^i)+k=1KΩ(fi) = ∑ i n l ( y i , y ^ i ( t − 1 ) + f t ( x i ) ) + Ω ( f t ) + c o n s t a n t =\sum_i^nl(y_i,\hat y_i^{(t-1)}+f_t(x_i))+\Omega(f_t)+constant =inl(yi,y^i(t1)+ft(xi))+Ω(ft)+constant = ∑ i n [ l ( y i , y ^ i ( t − 1 ) ) + l ′ ( y i , y ^ i ( t − 1 ) ) f t ( x i ) + 1 2 l ′ ′ ( y i , y ^ i ( t − 1 ) ) f t 2 ( x i ) ] + Ω ( f t ) + c o n s t a n t =\sum_i^n[l(y_i,\hat y_i^{(t-1)})+l^{'}(y_i,\hat y_i^{(t-1)})f_t(x_i)+\frac {1}{2}l^{''}(y_i,\hat y_i^{(t-1)})f_t^2(x_i)]+\Omega(f_t)+constant =in[l(yi,y^i(t1))+l(yi,y^i(t1))ft(xi)+21l(yi,y^i(t1))ft2(xi)]+Ω(ft)+constant
这里始终要注意一件事,未知数并不是xi而是第t步的f,上面的式子中 y i , y ^ i ( t − 1 ) y_i,\hat y_i^{(t-1)} yiy^i(t1),constant都是常数(记住后面要用到常数优化)将上面的式子进一步简化 o b j ( t ) = ∑ i n [ l ( y i , y ^ i ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) + c o n s t a n t 在 这 里 h i = l ′ ( y i , y ^ i ( t − 1 ) ) , g i = l ′ ′ ( y i , y ^ i ( t − 1 ) ) obj^{(t)}=\sum_i^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_t)+constant 在这里 h_i=l^{'}(y_i,\hat y_i^{(t-1)}),g_i=l^{''}(y_i,\hat y_i^{(t-1)}) obj(t)=in[l(yi,y^i(t1))+gift(xi)+21hift2(xi)]+Ω(ft)+constanthi=l(yi,y^i(t1))gi=l(yi,y^i(t1))
前边的Loss已经变成二次式子了,该轮到正则项了,我们前面提到过正则项的计算是根据叶子进行计算的,正则项就是对模型复杂度的惩罚,通常分为L1,L2,我们这里使用L2进行正则,每个叶子分数score值用 ω \omega ω代表,将树的结构看做q,那么每个叶子的值就是 ω q ( x ) \omega_{q_{(x)}} ωq(x),将每一个x映射到叶子上每一个x的打分为 ω q ( x ) \omega_{q_{(x)}} ωq(x)那么L2正则为 Ω ( f t ) = 1 2 λ ∑ j = 1 T ∣ ∣ ω ∣ ∣ 2 \Omega(f_t)=\frac {1}{2}\lambda \sum_{j=1}^T||\omega||^2 Ω(ft)=21λj=1Tω2在Chen的xgboost官网中还利用叶子数量控制项进行惩罚, Ω ( f t ) = 1 2 λ ∑ j = 1 T ∣ ∣ ω ∣ ∣ 2 + γ T \Omega(f_t)=\frac {1}{2}\lambda \sum_{j=1}^T||\omega||^2+\gamma^T Ω(ft)=21λj=1Tω2+γT其中T是叶子的数量,至于这么做陈天奇也说过在实际的使用中证明这种正则结构是最好的,所以不必纠结为什么L2正则会加入叶子惩罚项。
在文章的一开始我说过f同样带表着树的结构的映射,将 ω \omega ω与f进行替换j即 f t ( x ) = ω q ( x ) f_t(x)=\omega_{q_{(x)}} ft(x)=ωq(x)因此 o b j ( t ) = ∑ i n [ l ( y i , y ^ i ( t − 1 ) ) + g i ω q ( x i ) + 1 2 h i ω q ( x i ) 2 ] + Ω ( ω j 2 ) + c o n s t a n t obj^{(t)}=\sum_i^n[l(y_i,\hat y_i^{(t-1)})+g_i\omega_{q_{(x_i)}}+\frac {1}{2}h_i\omega_{q_{(x_i)}}^2]+\Omega(\omega^2_j)+constant obj(t)=in[l(yi,y^i(t1))+giωq(xi)+21hiωq(xi)2]+Ω(ωj2)+constant上文说过这个式子中有着常数,常数对于计算可以去掉,再将上面的正则项代换,所以 o b j ( t ) ≈ ∑ i n [ g i ω q ( x i ) + 1 2 h i ω q ( x i ) 2 ] + 1 2 λ ∑ j = 1 T ∣ ∣ ω j ∣ ∣ 2 + γ T obj^{(t)}\approx\sum_i^n[g_i\omega_{q_{(x_i)}}+\frac {1}{2}h_i\omega_{q_{(x_i)}}^2]+\frac {1}{2}\lambda \sum_{j=1}^T||\omega_j||^2+\gamma^T obj(t)in[giωq(xi)+21hiωq(xi)2]+21λj=1Tωj2+γT上面的式子中我们可以将前后两项进行合并,合并的原则是相同的叶子,因为 ω \omega ω代表叶子,注意式子中的合并加号的变化,如下 ∑ i n [ g i ω q ( x i ) + 1 2 h i ω q ( x i ) 2 ] + 1 2 λ ∑ j = 1 T ∣ ∣ ω j ∣ ∣ 2 + γ T \sum_i^n[g_i\omega_{q_{(x_i)}}+\frac {1}{2}h_i\omega_{q_{(x_i)}}^2]+\frac {1}{2}\lambda \sum_{j=1}^T||\omega_j||^2+\gamma^T in[giωq(xi)+21hiωq(xi)2]+21λj=1Tωj2+γT = ∑ j T [ ( ∑ i ∈ I j g i ) ω i + 1 2 ( ∑ i ∈ I j h i + λ ) ω 2 ] + γ T =\sum_j^T[(\sum_{i\in I_j}g_i)\omega_i+\frac{1}{2}(\sum_{i\in I_j}h_i+\lambda)\omega^2]+\gamma^T =jT[(iIjgi)ωi+21(iIjhi+λ)ω2]+γT其中 I j = { i ∣ q ( x i ) = j } I_j=\{i|q(x_i)=j\} Ij={iq(xi)=j}即数据被映射到那一片叶子上。再进一步化简,利用 G i = ( ∑ i ∈ I j g i ) G_i=(\sum_{i\in I_j}g_i) Gi=(iIjgi) H i = ∑ i ∈ I j h i H_i=\sum_{i\in I_j}h_i Hi=iIjhi那么式子变为
o b j ( t ) = ∑ j T [ G i ω i + 1 2 ( H i + λ ) ω 2 ] + γ T obj^{(t)}=\sum_j^T[G_i\omega_i+\frac{1}{2}(H_i+\lambda)\omega^2]+\gamma^T obj(t)=jT[Giωi+21(Hi+λ)ω2]+γT由此式子算是变换完成了,接下来就优化目标函数使得obj尽可能的小,通过我们上面一系列变化使得我们的式子具有了我们开始讨论的形式,二次式,这就意味着可以使用二次函数的最大值最小值进行优化,所以极值求得如下
ω j ∗ = − G i H i + λ \omega_j^*=-\frac{G_i}{H_i+\lambda} ωj=Hi+λGi o b j ∗ = − 1 2 ∑ j = 1 T G j 2 H j + λ + γ T obj^*=-\frac {1}{2}\sum _{j=1}^T\frac{G_j^2}{H_j+\lambda}+\gamma^T obj=21j=1THj+λGj2+γT
其中obj*代表的意义是我们所建立的树结构有多么的好,值越小代表着建立的树结构越好,xgboost原理及论文剖析_第3张图片
上图就是计算过程,首先计算各个数据的一次导数与二次导数然后映射到各个叶子中区,最终得到Obj,就是我们的优化值,这个优化值就代表着树的好坏,我们去优化这个值就意味着优化树的结构。

建立树结构

有了优化过程,对于树的建立过程还没有介绍,这里说一下树的建立过程,在GBDT中使用的是MSE,然鹅在这里我们使用的是一种类似信息增益的东西,如下
G a i n = [ G L 2 H L + λ + G R 2 H R + λ − ( G L + G R ) 2 ( H L + H R ) + λ ] − γ Gain=[\frac{G_L^2}{H_L+\lambda}+\frac{G_R^2}{H_R+\lambda}-\frac{(GL+G_R)^2}{(H_L+H_R)+\lambda}]-\gamma Gain=[HL+λGL2+HR+λGR2(HL+HR)+λ(GL+GR)2]γ上面第一项是左边叶子的obj,第二项是右边叶子的obj,第三项是左右节点的父亲节点。假设我们的分裂条件是 x i , m < N x_{i,m}xi,m<N其中i代表第i个数据,m代表第m个属性,也就是列维度,分裂的过程是这样的遍历所有在将要分裂节点的数据,按照 x i , m < N x_{i,m}xi,m<N假设性分裂计算每一维度的g,h最终计算Gain,选择第i个数据的第m维度的数据为分裂的依据,将大于分裂依据的分到一个叶子,小于的分到一边,计算左右Gain,计算父亲gain,相减。还有一项 γ \gamma γ的意思是为了控制分裂的条件,如果Gain小于0则不进行分裂,如果大于0选择增益最大的分裂依据进行分裂。因为选择obj最小的。
一般来说我们选择分裂依据的时候数据都是经过排序的,否则将会是一项大工程,排序后选择数据就好选择了。
xgboost原理及论文剖析_第4张图片
今天继续更新

3.xgboost举例

例子采用的是鸢尾花数据集,机器学习新手都是拿这个数据集来进行练手的,csdn的表格插入太麻烦,我用exel
xgboost原理及论文剖析_第5张图片
设置一下超参数,建立两棵树,深度为3,树的数量为2,learning rate=0.1,在xgboost中有一个值叫做base_score它是我们的 y ^ \hat y y^的初始值,在google之后我发现它的默认值是0.5,并且在实际应用中是一个不错的选择,相关参考https://github.com/dmlc/xgboost/issues/799。回到正题,在上面的表格中有大量的string类型的值,我们首先对其进行one-hot处理,我们只做二分类,多分类手动算不来。。。,鸢尾花数据集有一个特性,在做线性分类的时候只有两种是线性可分的我们就用xgboost来模拟线性分类如下
xgboost原理及论文剖析_第6张图片
二分类使用的是交叉熵,与sigmoid函数如下
交叉熵: L ( y i , h i ) = − y i l n h i − ( 1 − y i ) l n ( 1 − h i ) L(y_i,h_i)=-y_iln_{h_i}-(1-y_i)ln(1-h_i) L(yi,hi)=yilnhi(1yi)ln(1hi),有的可能写作log,这个取决于似然估计,在似然估计中你用什么了,可以补一下似然估计?算了有空再写一篇。。
其中hi是输入值,在xgboost中是sigmoid函数(多谢一位老哥博客才知道是sigmoid值,博客地址在参考中)输出我们将sigmoid带入,计算它的一阶导数,二阶导数,因为xgboost中利用导数求导如下,未知数为 y ^ = z \hat y=z y^=z(带帽的y难打出来)
L ′ ( y i , 1 1 + e − z ) = d { − y i l n 1 1 + e − z − ( 1 − y i ) l n ( 1 − 1 1 + e − z ) } / d z L'(y_i,\frac{1}{1+e^{-z}})=d\{-y_iln{\frac{1}{1+e^{-z}}}-(1-y_i)ln(1-\frac{1}{1+e^{-z}})\}/dz L(yi,1+ez1)=d{yiln1+ez1(1yi)ln(11+ez1)}/dz
将上面括号中拿出来化简
− y i l n 1 1 + e − z − ( 1 − y i ) l n ( 1 − 1 1 + e − z ) -y_iln{\frac{1}{1+e^{-z}}}-(1-y_i)ln(1-\frac{1}{1+e^{-z}}) yiln1+ez1(1yi)ln(11+ez1)
= y i l n ( 1 + e − z ) − ( 1 − y i ) l n ( e − z 1 + e − z ) =y_iln(1+e^{-z})-(1-y_i)ln(\frac{e^{-z}}{1+e^{-z}}) =yiln(1+ez)(1yi)ln(1+ezez)
= y i l n ( 1 + e − z ) − ( 1 − y i ) [ l n e − z − l n ( 1 + e − z ) ] =y_iln(1+e^{-z})-(1-y_i)[lne^{-z}-ln(1+e^{-z})] =yiln(1+ez)(1yi)[lnezln(1+ez)]
= y i l n ( 1 + e − z ) − [ l n e − z − l n ( 1 + e − z ) − y i l n e − z + y i l n ( 1 + e − z ) ] =y_iln(1+e^{-z})-[lne^{-z}-ln(1+e^{-z})-y_ilne^{-z}+y_iln(1+e^{-z})] =yiln(1+ez)[lnezln(1+ez)yilnez+yiln(1+ez)]
= l n e z + l n ( 1 + e − z ) − z y i =lne^z+ln(1+e^{-z})-zy_i =lnez+ln(1+ez)zyi
= l n ( 1 + e z ) − z y i =ln(1+e^z)-zy_i =ln(1+ez)zyi
对上述式子对z求导得
e z 1 + e z − y i \frac{e^z}{1+e^z}-y_i 1+ezezyi
= 1 1 + e − z − y i = 1 1 + e − y ^ − y i =\frac{1}{1+e^{-z}}-y_i=\frac{1}{1+e^{-\hat y}}-y_i =1+ez1yi=1+ey^1yi二阶导数如下
= e − y ^ ( 1 + e − y ^ ) 2 = 1 1 + e − y ^ ∗ ( 1 − 1 1 + e − y ^ ) =\frac{e^{-{\hat y}}}{(1+e^{-{\hat y}})^2}=\frac{1}{1+e^{-\hat y}}*(1-\frac{1}{1+e^{-\hat y}}) =(1+ey^)2ey^=1+ey^1(11+ey^1)参考的博客 将上述sigmoid换为 y i , p r e y_{i,pre} yi,pre是不是更好看
一阶导数 y i , p r e − y i y_{i,pre}-y_i yi,preyi二阶导数 y i , p r e ∗ ( 1 − y i , p r e ) y_{i,pre}*(1-y_{i,pre}) yi,pre(1yi,pre),如果设置base_score的默认值0.5,那么我们的起始的 y ^ = 0 \hat y=0 y^=0,这个你可以反向推导令sigmoid=0.5,我们设置所有数据的 y i , p r e y_{i,pre} yi,pre为0.5,求解所有数据的一阶导数,二阶导数如下:
xgboost原理及论文剖析_第7张图片
接下来就是利用Gain值进行节点的分裂,先从特征sepal.Length开始挨个作为分裂值计算Gain,取第一个值5.1,大于等于5.1放在一个节点,小于的放在一个节点。

未完成,明日更新。2020.3.20
参考

  1. https://xgboost.readthedocs.io/en/latest/tutorials/model.html
  2. https://blog.csdn.net/anshuai_aw1/article/details/82970489#51_min_child_weight__435

你可能感兴趣的:(机器学习)