赞
踩
图解机器学习 | GBDT模型详解
XGBoost是eXtreme Gradient Boosting的缩写称呼,它是一个非常强大的Boosting算法工具包,优秀的性能(效果与速度)让其在很长一段时间内霸屏数据科学比赛解决方案榜首,现在很多大厂的机器学习方案依旧会首选这个模型。
XGBoost在并行计算效率、缺失值处理、控制过拟合、预测泛化能力上都变现非常优秀。本文我们给大家详细展开介绍XGBoost,包含「算法原理」和「工程实现」两个方面。
关于XGBoost的工程应用实践,欢迎大家参考ShowMeAI的另外一篇实战文章 XGBoost工具库建模应用详解。
(本篇XGBoost部分内容涉及到机器学习基础知识、决策树/回归树/GBDT算法,没有先序知识储备的宝宝可以查看ShowMeAI的文章 图解机器学习 | 机器学习基础知识 、决策树模型详解 、回归树模型详解)及图解机器学习 | GBDT模型详解)。
关于XGBoost的原理,其作者陈天奇本人有一个非常详尽的Slides做了系统性的介绍,我们在这里借助于这个资料给大家做展开讲解。
在开始介绍Boosted Tree之前,我们先来回顾一下机器学习中的一些重要的概念。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dlQCwI2K-1707200160851)(https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp3-juejin.byteimg.com%2Ftos-cn-i-k3u1fbpfcp%2Fd2190e08ed514d249162b07da03fdd16~tplv-k3u1fbpfcp-zoom-in-crop-mark%3A1512%3A0%3A0%3A0.awebp&pos_id=img-Fk94q9Un-1707146766401)]
符号(Notations):xi∈Rdx_i \in R^dxi∈Rd表示训练集中的第iii个样本。
模型(Model):对于已知的xix_ixi如何预测yi\hat{y}_iyi?
线性模型(Linear Model) y^i=Σjwjxij\hat{y}{i}=\Sigma{j} w_{j} x_{ij}yi=Σjwjxij(包括线性回归和逻辑回归),预测值yi\hat{y}_iy^i根据不同的任务有不同的解释:
参数(Parameters):需要从数据中学习的东西。
目标函数(Objective function)Obj(Θ)=L(Θ)+Ω(Θ)Obj(\Theta )=L(\Theta )+\Omega (\Theta)Obj(Θ)=L(Θ)+Ω(Θ)
训练数据损失函数(Training Loss)L=Σi=1nl(yi,yi)L=\Sigma_{i=1}{n}l(y_i,\hat{y}_i)L=Σi=1nl(yi,y^i)
正则化项(Regularization):描述了模型的复杂程度。
Ridge回归:Σi=1n(yi−wTxi)2+λ∣∣w∣∣2\Sigma_{i=1}{n}(y_i-wTx_i)2+\lambda||w||2Σi=1n(yi−wTxi)2+λ∣∣w∣∣2
Lasso:Σi=1n(yi−wTxi)2+λ∣∣w∣∣1\Sigma_{i=1}{n}(y_i-wTx_i)^2+\lambda||w||_1Σi=1n(yi−wTxi)2+λ∣∣w∣∣1
逻辑回归(Logistic Regression):Σi=1n(yiln(1+e−wTxi)+(1−yi)ln(1+ewTxi))+λ∣∣w∣∣2\Sigma_{i=1}{n}(y_iln(1+e{-wTx_i})+(1-y_i)ln(1+e{wTx_i}))+\lambda||w||2Σi=1n(yiln(1+e−wTxi)+(1−yi)ln(1+ewTxi))+λ∣∣w∣∣2
回顾一下目标函数Obj(Θ)=L(Θ)+Ω(Θ)Obj(\Theta )=L(\Theta )+\Omega (\Theta )Obj(Θ)=L(Θ)+Ω(Θ),为什么目标函数需要两部分组成呢?
回归树,也就是分类回归树(Classification and Regression Tree)(详情请查看ShowMeAI文章回归树模型详解)
从上图的左图可以看出,共有5个训练样本。
从上图的中图可以看出,每个叶子节点都有预测值:第一个叶子结点的预测值是2,第二个叶子结点的预测值是0.1,第三个叶子结点的预测值是-1。
最终的预测值就是样本在每颗树中所在的叶子结点的预测值的和。
树集成的方法使用非常广泛,像GBM、随机森林等(详见ShowMeAI文章 图解机器学习 | GBDT模型详解 和 图解机器学习 | 随机森林分类模型详解)。多达半数的数据挖掘竞赛通过使用各种各样的树集成方法而获胜。
模型:假设我们有K棵树:yi=Σk=1Kfk(xi),fk∈F\hat{y}_i=\Sigma_{k=1}Kf_k(x_i), f_k\in Fy^i=Σk=1Kfk(xi),fk∈F。其中,F为包含所有回归树的函数空间。
参数:包括每棵树的结构和叶子结点中的分数。或者使用函数当作参数:Θ={f1,f2,…,fK}\Theta =\left{f_1,f_2,…,f_K\right}Θ={f1,f2,…,fK}。
单变量也就是单个特征,通过了解如何在单变量上学习Boosted Tree,我们可以对Boosted Tree的学习模式有个简单的概念。
举例:假设回归树只有一个输入变量t(时间),希望预测小哥在t时刻有多喜欢浪漫音乐。
从上左图可以看到,这位小哥在单身的时候,对浪漫音乐的喜欢程度很低;但是当他遇到了女朋友,随着体内荷尔蒙的分布增加,他对浪漫音乐的喜欢程度增加了;但是有一天分手了,他对浪漫音乐的喜欢程度又变低了。当然,我们也可以发现,上右图的回归树很容易能表达上左图。
为了构建上右图的树,我们需要学习两个东西:
单变量回归树的目标(阶跃函数)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6p42bMRL-1707200160855)(https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp3-juejin.byteimg.com%2Ftos-cn-i-k3u1fbpfcp%2F674cb33840aa4b5fac7c9d6b2d3096a6~tplv-k3u1fbpfcp-zoom-in-crop-mark%3A1512%3A0%3A0%3A0.awebp&pos_id=img-Hcu4geK1-1707146766405)]
首先回顾上面我们对Boosted Tree的定义:
模型:假设我们有K棵树: y^i=Σk=1Kfk(xi),fk∈F\hat{y}i = \Sigma{k=1}^{K} f_k(x_i), f_k\in Fy^i=Σk=1Kfk(xi),fk∈F
目标函数:Obj=Σi=1nl(yi,yi)+Σk=1KΩ(fk)Obj=\Sigma_{i=1}nl(y_i,\hat{y}i)+\Sigma{k=1}^K\Omega (f_k)Obj=Σi=1nl(yi,y^i)+Σk=1KΩ(fk)
当我们讨论树的时候,通常是启发式的:
大多数启发式算法都能很好地映射到目标函数,采用形式(目标)视图让我们知道我们正在学习什么:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F6SBzypr-1707200160856)(https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp3-juejin.byteimg.com%2Ftos-cn-i-k3u1fbpfcp%2Fe0b272a351aa41f79b80fdaa22ff0555~tplv-k3u1fbpfcp-zoom-in-crop-mark%3A1512%3A0%3A0%3A0.awebp&pos_id=img-uHDb7ymV-1707146766405)]
回归树集成定义了如何得到预测值,它不仅仅可以做回归,同样还可以做分类和排序。具体做什么任务依赖于「目标函数」的定义:
在这一节中我们将正式学习Gradient Boosting。这里,xgboost的处理大家可以对比GBDT模型(可参考ShowMeAI文章 图解机器学习 | GBDT模型详解)来理解核心差异。
目标函数:Obj=Σi=1nl(yi,yi)+Σk=1KΩ(fk)Obj=\Sigma_{i=1}nl(y_i,\hat{y}i)+\Sigma{k=1}^K\Omega (f_k)Obj=Σi=1nl(yi,y^i)+Σk=1KΩ(fk)
在做GBDT的时候,我们没有办法使用SGD,因为它们是树,而非数值向量——也就是说从原来我们熟悉的参数空间变成了函数空间。
解决方案:初始化一个预测值,每次迭代添加一个新函数(fff):
yi(0)=0yi(1)=f1(xi)=yi(0)+f1(xi)yi(2)=f1(xi)+f2(xi)=yi(1)+f2(xi)…yi(t)=Σk=1tfk(xi)=y^i(t−1)+ft(xi)\begin{aligned} \hat{y}_i^{(0)} & = 0 \ \hat{y}_i^{(1)} & = f_1(x_i)=\hat{y}_i^{(0)}+f_1(x_i) \ \hat{y}_i^{(2)} & = f_1(x_i)+f_2(x_i)=\hat{y}_i^{(1)}+f_2(x_i) \ \dots \ \hat{y}i^{(t)} & = \Sigma{k=1}tf_k(x_i)=\hat{y}_i{(t-1)}+f_t(x_i) \ \end{aligned}yi(0)yi(1)yi(2)…yi(t)=0=f1(xi)=yi(0)+f1(xi)=f1(xi)+f2(xi)=yi(1)+f2(xi)=Σk=1tfk(xi)=y^i(t−1)+ft(xi)
第一步:根据上面的公式,目标函数可以做如下变形
Obj(t)=Σi=1nl(yi,yi(t))+Σk=1tΩ(fk)=Σi=1nl(yi,yi(t−1)+ft(xi))+Ω(ft)+constant\begin{aligned} Obj^{(t)} & =\Sigma_{i=1}nl(y_i,\hat{y}_i{(t)})+\Sigma_{k=1}^t\Omega (f_k)\ & =\Sigma_{i=1}nl(y_i,\hat{y}_i{(t-1)}+f_t(x_i))+\Omega (f_t)+constant \end{aligned}Obj(t)=Σi=1nl(yi,yi(t))+Σk=1tΩ(fk)=Σi=1nl(yi,yi(t−1)+ft(xi))+Ω(ft)+constant
这里我们考虑平方损失,此时目标函数又可以变形为:
Obj(t)=Σi=1n(2(yi−yi(t−1))ft(xi)+ft(xi)2)+Ω(ft)+constantObj{(t)}=\Sigma_{i=1}n(2(y_i-\hat{y}_i{(t-1)})f_t(x_i)+f_t(x_i)^2)+\Omega (f_t)+constantObj(t)=Σi=1n(2(yi−y^i(t−1))ft(xi)+ft(xi)2)+Ω(ft)+constant
第二步:所以我们的目的就是找到ftf_tft使得目标函数最低。然而,经过上面初次变形的目标函数仍然很复杂,目标函数会产生二次项。
在这里我们引入泰勒展开公式:
f(x+Δx)≃f(x)+f(x)Δx+1/2f(x)Δx2f(x+\Delta x)\simeq f(x)+f(x)\Delta x+1/2f(x)\Delta x^2f(x+Δx)≃f(x)+f(x)Δx+1/2f(x)Δx2
目标函数利用泰勒展开式就可以变成:
Obj(t)≃Σi=1n(l(yi,yi(t−1))+gift(xi)+1/2hift(xi)2)+Ω(ft)+constantObj{(t)}\simeq \Sigma_{i=1}n(l(y_i,\hat{y}_i{(t-1)})+g_if_t(x_i)+1/2h_if_t(x_i)^2)+\Omega (f_t)+constantObj(t)≃Σi=1n(l(yi,y^i(t−1))+gift(xi)+1/2hift(xi)2)+Ω(ft)+constant
第三部:把常数项提出来,目标函数可以简化为
Obj(t)≃Σi=1n[gift(xi)+1/2hift(xi)2]+Ω(ft)+constantObj^{(t)}\simeq \Sigma_{i=1}n[g_if_t(x_i)+1/2h_if_t(x_i)2]+\Omega (f_t)+constantObj(t)≃Σi=1n[gift(xi)+1/2hift(xi)2]+Ω(ft)+constant
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SaFiCPJn-1707200160857)(https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp3-juejin.byteimg.com%2Ftos-cn-i-k3u1fbpfcp%2F42c943a2141c49169e981c85265aa6ac~tplv-k3u1fbpfcp-zoom-in-crop-mark%3A1512%3A0%3A0%3A0.awebp&pos_id=img-mwoGQRJN-1707146766407)]
思考:为什么要做这么多变化而不直接生成树?
在前面,我们使用ft(x)f_t(x)ft(x)代表一颗树,在本小节,我们重新定义一下树:我们通过叶子结点中的分数向量和将实例映射到叶子结点的索引映射函数来定义树:(有点儿抽象,具体请看下图)
ft(x)=wq(x),w∈RT,q:Rd→{1,2,3,…,T}f_t(x)=w_q(x), w\in R^T, q:R^d\rightarrow \left{1,2,3,…,T\right}ft(x)=wq(x),w∈RT,q:Rd→{1,2,3,…,T}
从上图可以看出,共有3个叶子结点,第一个叶子结点的权重为+1,第二个叶子结点的权重为0.1,第三个叶子结点的权重为-1;其中,小男孩属于第1个叶子结点,老奶奶属于第3个叶子结点。
通过下面的式子定义树的复杂程度(定义并不是唯一的)
Ω(ft)=γT+12λΣj=1Twj2\Omega (f_t)=\gamma T+\frac{1}{2}\lambda\Sigma_{j=1}Tw_j2Ω(ft)=γT+21λΣj=1Twj2
定义在叶子结点jjj中的实例的集合为:
Ij={i∣q(xi)=j}I_j=\left{i|q(x_i)=j \right}Ij={i∣q(xi)=j}
根据每棵叶子重新定义目标函数:
Obj(t)≃Σi=1n[gift(xi)+12hift(xi)2]+Ω(ft)+constant=Σi=1n[giwq(xi)+12hiwq(xi)2]+γT+12λΣj=1Twj2+constant=Σj=1T[(ΣiϵIjgi)wj+12(ΣiϵIjhi+λ)wj2]+γT+constant\begin{aligned} Obj^{(t)}& \simeq \Sigma_{i=1}n[g_if_t(x_i)+\frac{1}{2}h_if_t(x_i)2]+\Omega (f_t)+constant \ & = \Sigma_{i=1}n[g_iw_q(x_i)+\frac{1}{2}h_iw_q(x_i)2]+\gamma T+\frac{1}{2}\lambda\Sigma_{j=1}Tw_j2+constant \ & = \Sigma_{j=1}^T[(\Sigma_{i\epsilon I_j} g_i)w_j+\frac{1}{2}(\Sigma_{i\epsilon I_j} h_i+\lambda)w_j^2]+\gamma T+constant \end{aligned}Obj(t)≃Σi=1n[gift(xi)+21hift(xi)2]+Ω(ft)+constant=Σi=1n[giwq(xi)+21hiwq(xi)2]+γT+21λΣj=1Twj2+constant=Σj=1T[(ΣiϵIjgi)wj+21(ΣiϵIjhi+λ)wj2]+γT+constant
一些知识需要先了解。对于一元二次函数:Gx+12Hx2Gx+\frac{1}{2}Hx^2Gx+21Hx2,我们很容易得到这个函数的最小值和最小值对应的xxx。
也就是:
argminxGx+12Hx2=−GH,H>0minxGx+12Hx2=−12G2H
如何求叶子结点最优的值?接着继续变化目标函数:
Obj(t)=Σj=1T[(ΣiϵIjgi)wj+12(ΣiϵIjhi+λ)wj2]+γT+constant=Σj=1T[Gjwj+12(Hj+λ)wj2]+γT+constant\begin{aligned} Obj^{(t)}&= \Sigma_{j=1}^T[(\Sigma_{i\epsilon I_j} g_i)w_j+\frac{1}{2}(\Sigma_{i\epsilon I_j} h_i+\lambda)w_j^2]+\gamma T+constant\ & = \Sigma_{j=1}T[G_jw_j+\frac{1}{2}(H_j+\lambda)w_j2]+\gamma T+constant \end{aligned}Obj(t)=Σj=1T[(ΣiϵIjgi)wj+21(ΣiϵIjhi+λ)wj2]+γT+constant=Σj=1T[Gjwj+21(Hj+λ)wj2]+γT+constant
假设树的结构q(x)q(x)q(x)是固定的,那么每一个叶子结点的权重的最优值为
wj∗=−Gj/(Hj+λ)w_j^*=-G_j/(H_j+\lambda)wj∗=−Gj/(Hj+λ)
目标函数的最优值为
Obj=−12Σj=1TGj2Hj+λ+γTObj=-\frac{1}{2}\Sigma_{j=1}T\frac{G_j2}{H_j+\lambda}+\gamma TObj=−21Σj=1THj+λGj2+γT
下图是前面公式讲解对应的一个实际例子。
这里再次总结一下,我们已经把目标函数变成了仅与G、H、γ、λ、TG、H、\gamma、\lambda、TG、H、γ、λ、T这五项已知参数有关的函数,把之前的变量ftf_{t}ft消灭掉了,也就不需要对每一个叶子进行打分了! 那么现在问题来,刚才我们提到,以上这些是假设树结构确定的情况下得到的结果。但是树的结构有好多种,我们应该如何确定呢?
上一部分中我们假定树的结构是固定的。但是,树的结构其实是有无限种可能的,本小节我们使用贪婪算法生成树:
Gain=12(GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ)−γGain=\frac{1}{2}(\frac{G_L2}{H_L+\lambda}+\frac{G_R2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda})-\gammaGain=21(HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2)−γ
接下来要考虑的是如何寻找最佳分裂点。
例如,如果xjx_jxj是年龄,当分裂点是aaa的时候的增益gain是多少?
我们需要做的仅仅只是计算每一边的ggg和hhh,然后计算
Gain=12(GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ)−γGain=\frac{1}{2}(\frac{G_L2}{H_L+\lambda}+\frac{G_R2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda})-\gammaGain=21(HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2)−γ
对排序后的实例进行从左到右的线性扫描就足以决定特征的最佳分裂点。
所以,分裂一个结点的方法是:
时间复杂度:
一些树学习算法分别处理分类变量和连续变量,我们可以很容易地使用我们推导出的基于分类变量的评分公式。但事实上,我们没有必要单独处理分类变量:
我们可以使用one-hot方式处理分类变量:
zj={1 if x is in category j0 otherwise z_{j}=\left{
如果有太多的分类的话,矩阵会非常稀疏,算法会优先处理稀疏数据。
回顾之前的增益,当训练损失减少的值小于正则化带来的复杂度时,增益有可能会是负数:
Gain=12(GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ)−γGain=\frac{1}{2}(\frac{G_L2}{H_L+\lambda}+\frac{G_R2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda})-\gammaGain=21(HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2)−γ
此时就是模型的简单性和可预测性之间的权衡。
XGBoost也是一个Boosting加法模型,每一步迭代只优化当前步中的子模型。 第mmm步我们有:
Fm(xi)=Fm−1(xi)+fm(xi)F_m(x_i) = F_{m-1}(x_i) + f_m(x_i)Fm(xi)=Fm−1(xi)+fm(xi)
目标函数设计为「经验风险」+「结构风险」(正则项):
Obj=∑i=1NL[Fm(xi),yi]+∑j=1mΩ(fj)=∑i=1NL[Fm−1(xi)+fm(xi),yi]+∑j=1mΩ(fj)
在数学中,我们可以用泰勒公式近似f(x)f(x)f(x),具体如下式。XGBoost对损失函数运用二阶展开来近似。
f(x0+Δx)≈f(x0)+f′(x0)Δx+f′′(x0)2(Δx)2f(x_0+\Delta x) \approx f(x_0)+f^{’}(x_0) \Delta x + \frac{f^{’’}(x_0)}{2} (\Delta x)^2 f(x0+Δx)≈f(x0)+f′(x0)Δx+2f′′(x0)(Δx)2
(更多数学知识推荐阅读ShowMeAI的AI数学基础系列教程 图解AI数学基础:从入门到精通系列教程)。
对应XGBoost的损失函数,我们在上式里将Fm−1(xi)F_{m-1}(x_i)Fm−1(xi)视作x0x_0x0,fm(xi)f_{m}(x_i)fm(xi)视作Δx\Delta xΔx,L(yi,yi)L(\hat{y_i},y_i)L(yi,yi)视作关于yi\hat{y_i}yi的函数,得到:
Obj=∑i=1N[L[Fm−1(xi),yi]+∂L∂Fm−1(xi)fm(xi)+12∂2L∂2Fm−1(xi)fm2(xi)]+∑j=1mΩ(fj)Obj = \sum_{i=1}^N \Big[ L[F_{m-1}(x_i),y_i] + \frac{\partial L}{\partial F_{m-1}(x_i)} f_m(x_i) + \frac{1}{2} \frac{\partial^2 L}{\partial^2 F_{m-1}(x_i)} f_m^2(x_i) \Big] +\sum_{j=1}^m \Omega (f_j) Obj=i=1∑N[L[Fm−1(xi),yi]+∂Fm−1(xi)∂Lfm(xi)+21∂2Fm−1(xi)∂2Lfm2(xi)]+j=1∑mΩ(fj)
又因前m−1m-1m−1个子模型已经确定了,故上式中除了关于fm(x)f_{m} (x)fm(x)的部分都是常数,不影响对fm(x)f_{m} (x)fm(x)的优化求解。目标函数可转化为:
Obj=∑i=1N[gifm(xi)+12hifm2(xi)]+Ω(fm)O b j=\sum_{i=1}^{N}\left[g_{i} f_{m}\left(x_{i}\right)+\frac{1}{2} h_{i} f_{m}^{2}\left(x_{i}\right)\right]+\Omega\left(f_{m}\right)Obj=i=1∑N[gifm(xi)+21hifm2(xi)]+Ω(fm)
实际上,XGBoost的基分类器对决策树和线性模型都支持,这里我们只讨论更常见的「基于树」的情况。为防止过拟合,XGBoost设置了基于树的复杂度作为正则项:
Ω(f)=γT+12λ∣∣w∣∣2\Omega(f) = \gamma T + \frac{1}{2} \lambda ||w||^2Ω(f)=γT+21λ∣∣w∣∣2
作为回归树,叶子节点越多、输出的回归值越大,树的复杂度越高。
最终目标函数如下:
Obj=∑i=1N[gifm(xi)+12hifm2(xi)]+γT+12λ∑j=1Twj2Obj = \sum_{i=1}^N \Big[g_i f_m(x_i)+\frac{1}{2} h_i f_m^2(x_i)\Big]+\gamma T + \frac{1}{2} \lambda \sum_{j=1}^T w_j^2 Obj=i=1∑N[gifm(xi)+21hifm2(xi)]+γT+21λj=1∑Twj2
下面是一个数学转换处理,为了使正则项和经验风险项合并到一起。我们把在样本层面上求和的经验风险项,转换为叶节点层面上的求和。
定义节点jjj上的样本集为I(j)={xi∣q(xi)=j}I(j)={x_i|q(x_i)=j}I(j)={xi∣q(xi)=j},其中q(xi)q(x_i)q(xi)为将样本映射到叶节点上的索引函数,叶节点jjj上的回归值为wj=fm(xi),i∈I(j)w_j=f_m(x_i),i \in I(j)wj=fm(xi),i∈I(j)。
Obj=∑j=1T[(∑i∈I(j)gi)wj+12(∑i∈I(j)hi+λ)wj2]+γTObj = \sum_{j=1}^{T} \Big[ (\sum_{i\in I(j)} g_i) w_j + \frac{1}{2}(\sum_{i\in I(j)} h_i + \lambda) w_j^2 \Big] + \gamma TObj=j=1∑T[(i∈I(j)∑gi)wj+21(i∈I(j)∑hi+λ)wj2]+γT
进一步简化表达,令∑i∈I(j)gi=Gj\sum_{i\in I(j)} g_i=G_j∑i∈I(j)gi=Gj,∑i∈I(j)hi=Hj\sum_{i\in I(j)} h_i=H_j∑i∈I(j)hi=Hj注意这里G和H都是关于jjj的函数:
Obj=∑j=1T[Gjwj+12(Hj+λ)wj2]+γTObj = \sum_{j=1}^{T} \Big[ G_j w_j + \frac{1}{2}(H_j + \lambda) w_j^2 \Big] + \gamma T Obj=j=1∑T[Gjwj+21(Hj+λ)wj2]+γT
转化到这个形式后,我们可以看出,若一棵树的结构已经确定,则各个节点内的样本(xi,yi,gi,hi)(x_i,y_i,g_i,h_i)(xi,yi,gi,hi)也是确定的,即GjG_jGj,HjH_jHj、TTT被确定,每个叶节点输出的回归值应该使得上式最小,由二次函数极值点:
wj∗=−GjHj+λw_j^*=-\frac{G_j}{H_j+\lambda}wj∗=−Hj+λGj
按此规则输出回归值后,目标函数值也就是树的评分如下公式,其值越小代表树的结构越好。观察下式,树的评分也可以理解成所有叶节点的评分之和:
Obj∗=∑j=1T(−12Gj2Hj+λ+γ)Obj^* = \sum_{j=1}^T \Big( -\frac{1}{2}\frac{G_j^2}{H_j + \lambda} + \gamma \Big)Obj∗=j=1∑T(−21Hj+λGj2+γ)
我们之前文章【决策树模型详解】里给大家讲到了决策树模型是递归生长形成的,而XGBoost的子模型树也一样,需要要依赖节点递归分裂的贪心准则来实现树的生成。
我们之前文章决策树模型详解里给大家讲到了决策树模型是递归生长形成的,而XGBoost的子模型树也一样,需要要依赖节点递归分裂的贪心准则来实现树的生成。
XGBoost子树的基本处理思路和CART一样,会对特征值排序后遍历划分点,将其中最优的分裂收益作为该特征的分裂收益,选取具有最优分裂收益的特征作为当前节点的划分特征,按其最优划分点进行二叉划分,得到左右子树。
上图是一次节点分裂过程,很自然地,分裂收益是树A的评分减去树B的评分。虚线框外的叶节点,即非分裂节点的评分均被抵消,只留下分裂后的LR节点和分裂前的S节点进行比较,因此分裂收益的表达式为:
Gain=12[GL2HL+λ+GR2HR+λ−(GL+GR)2HL+HR+λ]−γGain = \frac{1}{2} \Big[ \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}\Big]-\gammaGain=21[HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2]−γ
基于性能的考量,XGBoost还对贪心准则做了一个近似版本,简单说,处理方式是「将特征分位数作为划分候选点」。这样将划分候选点集合由全样本间的遍历缩减到了几个分位数之间的遍历。
展开来看,特征分位数的选取还有global和local两种可选策略:
这两种情况里,由于global只能划分一次,其划分粒度需要更细。
XGB原始paper中对Higgs Boson数据集进行了实验,比较了精确贪心准则、global近似和local近似三类配置的测试集AUC,用eps代表取分位点的粒度,如eps=0.25eps=0.25eps=0.25代表将数据集划分为1/0.25=4个buckets,发现global(eps=0.05)和local(eps=0.3)均能达到和精确贪心准则几乎相同的性能。
XGBoost工具包支持上述提到的3类配置。
查看目标函数Obj=∑i=1N[gifm(xi)+12hifm2(xi)]+Ω(fm)Obj=\sum_{i=1}^{N}\left[g_{i} f_{m}\left(x_{i}\right)+\frac{1}{2} h_{i} f_{m}{2}\left(x_{i}\right)\right]+\Omega\left(f_{m}\right)Obj=∑i=1N[gifm(xi)+21hifm2(xi)]+Ω(fm),令偏导为0易得fm∗(xi)=−gihif_m*(x_i)=-\frac{g_i}{h_i}fm∗(xi)=−higi,此目标函数可理解为以hih_ihi为权重,−gihi-\frac{g_i}{h_i}−higi为标签的二次损失函数:
Obj=∑i=1N[gifm(xi)+12hifm2(xi)]+Ω(fm)=∑i=1N12hi[fm(xi)−(−gihi)]2+Ω(fm)+C
在近似算法取分位数时,实际上XGBoost会取以二阶导hih_ihi为权重的分位数(Weighted Quantile Sketch),如下图表示的三分位。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bEnRjSYw-1707200160858)(https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp3-juejin.byteimg.com%2Ftos-cn-i-k3u1fbpfcp%2F49fa124b54d1419c8662cb1a9f11a951~tplv-k3u1fbpfcp-zoom-in-crop-mark%3A1512%3A0%3A0%3A0.awebp&pos_id=img-VekI55Od-1707146766413)]
XGBoost为了进一步优化效果,在以下2个方面进行了进一步设计:
XGBoost也能对缺失值处理,也对特征稀疏问题(特征中出现大量的0或one-hot encoding结果)做了一些优化。XGBoost用「稀疏感知」策略来同时处理这两个问题:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yg7IQgmx-1707200160859)(https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp3-juejin.byteimg.com%2Ftos-cn-i-k3u1fbpfcp%2F85c8023869da477abc663c465d224c3d~tplv-k3u1fbpfcp-zoom-in-crop-mark%3A1512%3A0%3A0%3A0.awebp&pos_id=img-YA3HFK4A-1707146766414)]
依然通过遍历得到分裂节点,NA的方向有两种情况,在此基础上对非缺失值进行切分遍历。
如上图所示,若某个特征值取值为1,2,5和大量的NA,XGBoost会遍历以上6种情况(3个非缺失值的切分点×缺失值的两个方向),最大的分裂收益就是本特征上的分裂收益,同时,NA将被分到右节点。
XGBoost将每一列特征提前进行排序,以块(Block)的形式储存在缓存中,并以索引将特征值和梯度统计量对应起来,每次节点分裂时会重复调用排好序的块。而且不同特征会分布在独立的块中,因此可以进行分布式或多线程的计算。
特征值排序后通过索引来取梯度gi,hig_i,h_igi,hi会导致访问的内存空间不一致,进而降低缓存的命中率,影响算法效率。为解决这个问题,XGBoost为每个线程分配一个单独的连续缓存区,用来存放梯度信息。
数据量非常大的情形下,无法同时全部载入内存。XGBoost将数据分为多个blocks储存在硬盘中,使用一个独立的线程专门从磁盘中读取数据到内存中,实现计算和读取数据的同时进行。 为了进一步提高磁盘读取数据性能,XGBoost还使用了两种方法:
我们对之前讲解过的GBDT(参考ShowMeAI文章【GBDT算法详解】)和这里的XGBoost做一个对比总结:
更多监督学习的算法模型总结可以查看ShowMeAI的文章 AI知识技能速查 | 机器学习-监督学习。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。