GBDT梯度提升树

181 阅读17分钟

GBDT梯度提升树

简单来说,绝大多数的机器学习算法都在处理两个因素:模型(model)和目标函数(objective function)或是损失函数(loss function),通常模型又由它所拥有的参数向量表示。在得到具体的训练数据和模型后,机器学习所做的就是根据当前数据来学习它所满足的条件概率分布,或者说根据损失函数来学习目标函数。

例如在最基本的线性回归中,假设当前数据集记为 D = ( x i , . . . , x m ) , x i ∈ R d D = (x_{i}, ...,x_{m}),x_{i} \in R^d D=(xi​,...,xm​),xi​∈Rd,样本对应的标签为 y i y_{i} yi​,那么线性模型可以表示为:
y i ^ = ∑ j w j x i j \hat{y_i} = \sum_j w_j x_{ij} yi​^​=j∑​wj​xij​
如果将模型的参数记为 Θ = { x j ∣ j = 1 , . . . , d } \Theta = \{x_j|j=1,...,d\} Θ={xj​∣j=1,...,d},那么目标函数可设为:
Obj ⁡ ( Θ ) = L ( Θ ) + Ω ( Θ ) = ∑ i = 1 n l ( y i , y i ^ ) + Ω ( Θ ) \operatorname{Obj}(\Theta)=L(\Theta)+\Omega(\Theta) = \sum_{i=1}^n l(y_i,\hat{y_i}) + \Omega(\Theta) Obj(Θ)=L(Θ)+Ω(Θ)=i=1∑n​l(yi​,yi​^​)+Ω(Θ)
其中第一项为损失项,它用来衡量模型学习的好坏,常见的如均方误差、Logitic损失等;后一项为正则化项,它用来控制模型的复杂度,从而避免模型过拟合,常见的正则化项有 L 1 L_1 L1​正则化和 L 2 L_2 L2​正则化,其对应的回归模型分别为Lasso回归Ridge回归。两者之间相互制约,从而满足偏差-方差权衡原则。

如果讲上述的原则推广到其他的机器学习算法中,同样成立。集成算法中Boosting算法通过分步迭代的方式来构建模型,在迭代的每一步所构建的弱学习器都是为了弥补前一步模型的不足。前面的Adaboost中讲到提升算法主要解决的两个核心问题就是:

  • 如何在迭代训练的每一轮改变训练数据的权值分布
  • 如何讲一系列的弱学习器组合成一个强学习器

而从Adaboost算法的原理中我们可以看出,在每一次的迭代中,使用的当前权值分布 D i = ( w i , 1 , w i , 2 , . . . , w i , N ) D_i = (w_{i,1}, w_{i,2},...,w_{i,N}) Di​=(wi,1​,wi,2​,...,wi,N​)的数据训练得到一个弱学习器,然后计算得到的弱学习器在此时数据分布上的误差率 e m e_m em​,进而计算当前弱学习器在最后组合过程中的权重,以及更新训练数据的权值分布 D m + 1 = ( w m + 1 , 1 , w m + 1 , 2 , . . . , w m + 1 , N ) D_{m + 1} = (w_{m+1,1}, w_{m+1,2},...,w_{m+1,N}) Dm+1​=(wm+1,1​,wm+1,2​,...,wm+1,N​),使得下一次迭代中的弱学习器更加关注分错的样本。

如果迭代训练逐步提升的思想不变,在每一次迭代中不是去更新训练样本的权重,而是取直接拟合残差,此时的提升算法就是梯度提升算法(Gradient Boosting Machine,GBM)。如果迭代中所使用的弱学习器为分类回归树(classification and regression tree,CART),那么此时的梯度提升算法就是梯度提升树(Gradient Boosting Decision Tree,GBDT)

GBDT中之所以使用CART作为弱学习器主要有如下的考量:

  • 决策树所表达的if-then的方式解释性更好,更加符合人的直观感受
  • 决策树相比而言需要更少的特征工程,如可以很好的处理缺失值的问题
  • 决策树能够自动的组合多个特征,很好的处理特征间的交互关系

但是,决策树一个很严重的问题就是容易过拟合,因此常采用一些手段来降低决策树的复杂性,如:

  • 限制树的深度
  • 限制叶子节点的个数
  • 训练时对训练样本进行采样
  • 训练时只是用一部分特征
  • 添加正则化项

当使用了如上所述的方式降低了决策树的复杂性后,虽然可以避免过拟合问题的出现,但是决策树本身的分类或是回归能力就可能随之下降。因此,我们又需要想办法在保证决策树不出现过拟合的前提下,确保模型的性能不下降太多。而提升算法就提供了一个很好的思路,在每一次的迭代中作为弱学习器的决策树复杂度很低,大概率不可能出现过拟合,同时通过多次迭代,不断地提升后面迭代过程中弱学习器的性能,最终通过综合迭代过程中所得到的所有决策树的结果来进行判断。因此可以说,决策树和提升算法是一对很好的搭档。

GBDT中涉及到两个重要的东西:CART树加法模型,下面我们来分别看一下它们分别是什么。首先,决策树中在分裂的时候根据不同的最优特征选择准则可以分为ID3C.4.5CART,它们的特征选择准则分别是信息增益信息增益率基尼系数。ID3、C4.5和CART均可以通过特征选择进行区域划分和剪枝策略来处理分类问题,此外CART还可以用于处理回归问题。

CART处理回归问题的流程如下所示:

# CART回归算法
遍历训练集中的每个特征
	对于特征fi,遍历每个取值s:
    	用切分点d将数据集分成两份
        计算切分后的误差
求出误差最小的特征及其对应的切分点,此特征即被选中作为分裂结点,切分点则形成左右分支
递归重复以上步骤,下一次递归时已经分裂的特征不再考虑

假设特征 j j j和切分点 s s s把训练集划分为 R 1 R_1 R1​和 R 2 R_2 R2​两部分,每组的预测值为 c 1 c_1 c1​和 c 2 c_2 c2​,那么如果采用均方误差作为损失项,对应的损失项为 ∑ x i ∈ R 1 ( y i − c 1 ) 2 + ∑ x i ∈ R 2 ( y i − c 2 ) 2 \sum_{x_{i} \in R_{1}}\left(y_{i}-c_{1}\right)^{2}+\sum_{x_{i} \in R_{2}}\left(y_{i}-c_{2}\right)^{2} ∑xi​∈R1​​(yi​−c1​)2+∑xi​∈R2​​(yi​−c2​)2,对应的目标函数为:
min ⁡ j , s [ min ⁡ c 1 ∑ x i ∈ R 1 ( y i − c 1 ) 2 + min ⁡ Q 2 ∑ x i ∈ R 2 ( y i − c 2 ) 2 ] \min _{j, s}\left[\min _{c_{1}} \sum_{x_{i} \in R_{1}}\left(y_{i}-c_{1}\right)^{2}+\min _{Q_{2}} \sum_{x_{i} \in R_{2}}\left(y_{i}-c_{2}\right)^{2}\right] j,smin​[c1​min​xi​∈R1​∑​(yi​−c1​)2+Q2​min​xi​∈R2​∑​(yi​−c2​)2]
优化目标函数的过程即最小化损失项的过程,那么对于两部分而言是相同的,如 min ⁡ c 1 ∑ x i ∈ R 1 ( y i − c 1 ) 2 \min _{c_{1}} \sum_{x_{i} \in R_{1}}\left(y_{i}-c_{1}\right)^{2} minc1​​∑xi​∈R1​​(yi​−c1​)2的过程就是求 ∑ x i ∈ R 1 ( y i − c 1 ) 2 \sum_{x_{i} \in R_{1}}\left(y_{i}-c_{1}\right)^{2} ∑xi​∈R1​​(yi​−c1​)2的最小值。根据函数的性质知,对其求导可得:
c 1 = 1 N 1 ∑ x i ∈ R 1 y i , c 2 = 1 N 2 ∑ x i ∈ R 2 y i c_1 = \frac{1}{N_1}\sum_{x_{i} \in R_1}y_i , c_2 = \frac{1}{N_2}\sum_{x_{i} \in R_2}y_i c1​=N1​1​xi​∈R1​∑​yi​,c2​=N2​1​xi​∈R2​∑​yi​

GBDT最后需要综合每次迭代得到的CART的预测来得到最终的结果,那么GBDT可以看成是所有得到的树的加法模型,即 y i ^ = ∑ k = 1 K f k ( x i ) , f k ∈ K \hat{y_i} = \sum_{k=1}^K f_k(x_i), f_k \in K yi​^​=∑k=1K​fk​(xi​),fk​∈K。其中 K K K表示迭代的次数,也就是CART的棵树; F F F是所有树组成的函数空间。那么,按照前面对于机器学习的描述,此时的目标函数可写为:
O b j = ∑ i = 1 n l ( y i , y ^ i ) + ∑ k = 1 K Ω ( f k ) O b j=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}_{i}\right)+\sum_{k=1}^{K} \Omega\left(f_{k}\right) Obj=i=1∑n​l(yi​,y^​i​)+k=1∑K​Ω(fk​)
等号两边的项依然分别对应损失项和正则化项。在得到了目标函数后,我们该如何优化它呢?或者说如何去学习这个加法模型呢?通常求解该优化问题常使用的是前向分布算法(forward stagewise algorithm)。因此加法模型中每个模型之间满足某种顺序关系,因此我么可以从前往后逐步学习,每一次迭代只学习此时的弱学习器及其系数,通过逐步的优化目标函数来提升学习器的性能,最终通过组合的方式来得到一个强学习器。这一学习过程称之为Boosting,通常从一个常量预测开始,每次迭代学习一个新的函数:
y ^ i 0 = 0 y ^ i 1 = f 1 ( x i ) = y ^ i 0 + f 1 ( x i ) y ^ i 2 = f 1 ( x i ) + f 2 ( x i ) = y ^ i 1 + f 2 ( x i ) ⋯ y ^ i t = ∑ k = 1 t f k ( x i ) = y ^ i t − 1 + f t ( x i ) \begin{aligned} &\hat{y}_{i}^{0}=0\\ &\begin{aligned} \hat{y}_{i}^{1} &=f_{1}\left(x_{i}\right)=\hat{y}_{i}^{0}+f_{1}\left(x_{i}\right) \\ \hat{y}_{i}^{2} &=f_{1}\left(x_{i}\right)+f_{2}\left(x_{i}\right)=\hat{y}_{i}^{1}+f_{2}\left(x_{i}\right) \\ & \cdots \\ \hat{y}_{i}^{t} &=\sum_{k=1}^{t} f_{k}\left(x_{i}\right)=\hat{y}_{i}^{t-1}+f_{t}\left(x_{i}\right) \end{aligned} \end{aligned} ​y^​i0​=0y^​i1​y^​i2​y^​it​​=f1​(xi​)=y^​i0​+f1​(xi​)=f1​(xi​)+f2​(xi​)=y^​i1​+f2​(xi​)⋯=k=1∑t​fk​(xi​)=y^​it−1​+ft​(xi​)​​
在每次迭代中,如果使用不同的特征进行划分就可以得到多棵CART树,那么如何选择哪一棵作为这次迭代的结果,即上式中的 f f f呢?这里所遵从的仍然是最后小目标函数原则。

假设第 t t t步对于 x i x_i xi​的预测为 y ^ i t = y ^ i t − 1 + f t ( x i ) \hat{y}_{i}^{t}=\hat{y}_{i}^{t-1}+f_{t}\left(x_{i}\right) y^​it​=y^​it−1​+ft​(xi​),此时目标函数可写作:
O b j ( t ) = ∑ i = 1 n l ( y i , y ^ i t ) + ∑ i = i t Ω ( f i ) = ∑ i = 1 n l ( y i , y ^ i t − 1 + f t ( x i ) ) + Ω ( f t ) + constant  \begin{aligned} O b j^{(t)} &=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}_{i}^{t}\right)+\sum_{i=i}^{t} \Omega\left(f_{i}\right) \\ &=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}_{i}^{t-1}+f_{t}\left(x_{i}\right)\right)+\Omega\left(f_{t}\right)+\text {constant } \end{aligned} Obj(t)​=i=1∑n​l(yi​,y^​it​)+i=i∑t​Ω(fi​)=i=1∑n​l(yi​,y^​it−1​+ft​(xi​))+Ω(ft​)+constant ​
如果损失项为均方误差,且 x i x_{i} xi​对应的标签为 y i y_i yi​,那么目标函数可转化为:
O b j ( t ) = ∑ i = 1 n ( y i − ( y ^ i t − 1 + f t ( x i ) ) ) 2 + Ω ( f t ) + constant  = ∑ i = 1 n [ 2 ( y ^ i t − 1 − y i ) f t ( x i ) + f t ( x i ) 2 ] + Ω ( f t ) + constant  \begin{aligned} O b j^{(t)} &=\sum_{i=1}^{n}\left(y_{i}-\left(\hat{y}_{i}^{t-1}+f_{t}\left(x_{i}\right)\right)\right)^{2}+\Omega\left(f_{t}\right)+\text {constant } \\ &=\sum_{i=1}^{n}\left[2\left(\hat{y}_{i}^{t-1}-y_{i}\right) f_{t}\left(x_{i}\right)+f_{t}\left(x_{i}\right)^{2}\right]+\Omega\left(f_{t}\right)+\text {constant } \end{aligned} Obj(t)​=i=1∑n​(yi​−(y^​it−1​+ft​(xi​)))2+Ω(ft​)+constant =i=1∑n​[2(y^​it−1​−yi​)ft​(xi​)+ft​(xi​)2]+Ω(ft​)+constant ​
其中 ( y ^ i t − 1 − y i ) \left(\hat{y}_{i}^{t-1}-y_{i}\right) (y^​it−1​−yi​)称为残差,GBDT的基本思想就是通过迭代不断的来拟合残差。

原始的目标函数是关于 y ^ i t − 1 + f t ( x i ) \hat{y}_{i}^{t-1}+f_{t}(x_{i}) y^​it−1​+ft​(xi​)的函数,将其二阶泰勒 f ( x + Δ x ) ≈ f ( x ) + f ′ ( x ) Δ x + 1 2 f ′ ′ ( x ) Δ x 2 f(x+\Delta x) \approx f(x)+f^{\prime}(x) \Delta x+\frac{1}{2} f^{\prime \prime}(x) \Delta x^{2} f(x+Δx)≈f(x)+f′(x)Δx+21​f′′(x)Δx2展开得:
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 t ) +  constant  O b j^{(t)}=\sum_{i=1}^{n}\left[l\left(y_{i}, \hat{y}_{i}^{t-1}\right)+g_{i} f_{t}\left(x_{i}\right)+\frac{1}{2} h_{i} f_{t}^{2}\left(x_{i}\right)\right]+\Omega\left(f_{t}\right)+\text { constant } Obj(t)=i=1∑n​[l(yi​,y^​it−1​)+gi​ft​(xi​)+21​hi​ft2​(xi​)]+Ω(ft​)+ constant 
对照原始的二阶泰勒展开式可知, g i g_i gi​为损失函数的一阶导, h i h_i hi​为损失函数的二阶导,去除常数项得:
O b j ( t ) ≈ ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) O b j^{(t)} \approx \sum_{i=1}^{n}\left[g_{i} f_{t}\left(x_{i}\right)+\frac{1}{2} h_{i} f_{t}^{2}\left(x_{i}\right)\right]+\Omega\left(f_{t}\right) Obj(t)≈i=1∑n​[gi​ft​(xi​)+21​hi​ft2​(xi​)]+Ω(ft​)
从最终得目标函数可以看出,我们只需要先定义好损失函数,然后在每次迭代过程中针对于每个样本分别求其一阶导和二阶导,通过最小化上式即可求得每次迭代的 f ( x ) f(x) f(x)。

上式中 Ω ( f t ) \Omega(f_t) Ω(ft​)还没有定义,GBDT中定义 Ω ( f t ) = γ T + 1 2 λ ∑ j = 1 T w j 2 \Omega\left(f_{t}\right)=\gamma T+\frac{1}{2} \lambda \sum_{j=1}^{T} w_{j}^{2} Ω(ft​)=γT+21​λ∑j=1T​wj2​,其中 T T T表示每棵决策树的叶子节点数, w j w_j wj​是每个叶子节点对应值向量的 L 2 L_2 L2​范数。将其带入到上式中可得:
Obj ⁡ ( t ) ≈ ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) = ∑ i = 1 n [ g i w q ( x i ) + 1 2 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 \begin{aligned} \operatorname{Obj}^{(t)} & \approx \sum_{i=1}^{n}\left[g_{i} f_{t}\left(x_{i}\right)+\frac{1}{2} h_{i} f_{t}^{2}\left(x_{i}\right)\right]+\Omega\left(f_{t}\right) \\ &=\sum_{i=1}^{n}\left[g_{i} w_{q\left(x_{i}\right)}+\frac{1}{2} h_{i} w_{q\left(x_{i}\right)}^{2}\right]+\gamma T+\frac{1}{2} \lambda \sum_{j=1}^{T} w_{j}^{2} \\ &=\sum_{j=1}^{T}\left[\left(\sum_{i \in I_{j}} g_{i}\right) w_{j}+\frac{1}{2}\left(\sum_{i \in I_{j}} h_{i}+\lambda\right) w_{j}^{2}\right]+\gamma T \end{aligned} Obj(t)​≈i=1∑n​[gi​ft​(xi​)+21​hi​ft2​(xi​)]+Ω(ft​)=i=1∑n​[gi​wq(xi​)​+21​hi​wq(xi​)2​]+γT+21​λj=1∑T​wj2​=j=1∑T​⎣⎡​⎝⎛​i∈Ij​∑​gi​⎠⎞​wj​+21​⎝⎛​i∈Ij​∑​hi​+λ⎠⎞​wj2​⎦⎤​+γT​
令 G j = ∑ i ∈ I j g i , H j = ∑ i ∈ I j h i G_{j}=\sum_{i \in I_{j}} g_{i}, H_{j}=\sum_{i \in I_{j}} h_{i} Gj​=∑i∈Ij​​gi​,Hj​=∑i∈Ij​​hi​可将目标函数写为 O b j ( t ) = ∑ j = 1 T [ G i w j + 1 2 ( H i + λ ) w j 2 ] + γ T O b j^{(t)}=\sum_{j=1}^{T}\left[G_{i} w_{j}+\frac{1}{2}\left(H_{i}+\lambda\right) w_{j}^{2}\right]+\gamma T Obj(t)=∑j=1T​[Gi​wj​+21​(Hi​+λ)wj2​]+γT

。同样优化目标函数对应于对其求一阶导并令导数为零得 w j ∗ = − G j H j + λ w_{j}^* = -\frac{G_j}{H_j + \lambda} wj∗​=−Hj​+λGj​​,将其代入上式得 O b j = − 1 2 ∑ j = 1 T G j 2 H j + λ + γ T O b j=-\frac{1}{2} \sum_{j=1}^{T} \frac{G_{j}^{2}}{H_{j}+\lambda}+\gamma T Obj=−21​∑j=1T​Hj​+λGj2​​+γT。因此,在每次迭代中学习的决策树为目标函数值最小的树。

但是在选择最小的目标函数值对应的决策树是一个NP难问题,因此通常采用贪心法来选择一棵较优的树,具体做法为:

  • 从深度为0的树开始,对每个叶节点枚举所有的可用特征
  • 针对每个特征,把属于该节点的训练样本根据该特征值升序排列,通过线性扫描的方式来决定该特征的最佳分裂点,并记录该特征的最大收益(采用最佳分裂点时的收益)
  • 选择收益最大的特征作为分裂特征,用该特征的最佳分裂点作为分裂位置,把该节点生长出左右两个新的叶节点,并为每个新节点关联对应的样本集
  • 回到第1步,递归执行到满足特定条件为止

如何计算每次分裂的收益呢?假设当前节点记为 C,分裂之后左孩子节点记为 L,右孩子节点记为 R,则该分裂获得的收益定义为当前节点的目标函数值减去左右两个孩子节点的目标函数值之和: G a i n = O b j C + O b j L + O b j R Gain = Obj_C +Obj_L +Obj_R Gain=ObjC​+ObjL​+ObjR​,根据 O b j = − 1 2 ∑ j = 1 T G j 2 H j + λ + γ T O b j=-\frac{1}{2} \sum_{j=1}^{T} \frac{G_{j}^{2}}{H_{j}+\lambda}+\gamma T Obj=−21​∑j=1T​Hj​+λGj2​​+γT可得:
Gain = 1 2 [ G L 2 H L + λ + G R 2 H R + λ − ( G L + G R ) 2 H L + H R + λ ] − γ \text {Gain}=\frac{1}{2}\left[\frac{G_{L}^{2}}{H_{L}+\lambda}+\frac{G_{R}^{2}}{H_{R}+\lambda}-\frac{\left(G_{L}+G_{R}\right)^{2}}{H_{L}+H_{R}+\lambda}\right]-\gamma Gain=21​[HL​+λGL2​​+HR​+λGR2​​−HL​+HR​+λ(GL​+GR​)2​]−γ

在知道了每一次迭代如何得到对应的决策树后,GBDT整体的算法流程就是不断迭代、不断优化的过程。

  • 算法每次迭代生成一颗新的决策树
  • 在每次迭代开始之前,计算损失函数在每个训练样本点的一阶导数和二阶导数
  • 通过贪心策略生成新的决策树,通过等式(7)计算每个叶节点对应的预测值
  • 把新生成的决策树添加到模型中

GBDT的正则化方式

  • 为了防止过拟合,首先我们可以设置一个验证集,在验证集上调整叶子结点的个数 J J J和树的颗数 M M M 。寻找最优 M M M的过程类似于深度学习中的早停

  • 对加入模型的树进行缩放: f m ( x ) = f m − 1 ( x ) + v ∑ j = 1 J c m j I { x ∈ R m j } f_{m}(x)=f_{m-1}(x)+v \sum_{j=1}^{J} c_{m j} I\left\{x \in R_{m j}\right\} fm​(x)=fm−1​(x)+v∑j=1J​cmj​I{x∈Rmj​}

    这里的缩放因子 v v v可以将其理解为学习率 l l l。那么类比学习率对模型的影响,我们不难得出这样的结论:相同的 M M M较小的 v v v 导致较大的训练风险; v v v较小,需要较大的 M M M, v v v和 M M M共同控制模型的泛化能力。实际应用中通常采用较小的 v v v,通过早停来选择 M M M

  • 子采样(subsample):采样比例(subsample)取值为 ( 0 , 1 ] (0,1] (0,1]。注意这里的子采样和随机森林不一样,随机森林使用的是放回抽样,而这里是不放回抽样。如果取值为1,则全部样本都使用,等于没有使用子采样。如果取值小于1,则只有一部分样本会去做GBDT的决策树拟合。选择小于1的比例可以减少方差,即防止过拟合,但是会增加样本拟合的偏差,因此取值不能太低。推荐在 [ 0.5 , 0.8 ] [0.5, 0.8] [0.5,0.8]之间

  • 回归树剪枝:对于弱学习器即CART回归树进行正则化剪枝。

GBDT优缺点

优点:

  • 泛化能力和表达能力都很好,因此是被使用最广的算法之一
  • 具有较好的可解释性和鲁棒性
  • 能够自动发现特征之间的高阶关系
  • 不需要对数据进行归一化等处理。

缺点:

  • 只能处理低维稠密的数据,对高维稀疏的数据表现较差
  • 处理类别特征效果没有数值型特征好,因此常被用于回归任务
  • 训练过程串行

参考

梯度提升决策树(Gradient Boosting Decision Tree,GBDT)

决策树(Decision Tree)算法探析

GBDT算法原理深入解析

GBDT 算法:原理篇

A Gentle Introduction to Gradient Boosting

XGBoost Documentation

A Gentle Introduction to Gradient Boosting

XGBoost Documentation

梯度提升树(GBDT)