集成学习之GBDT超详细推导

本文深入解析GBDT算法,从回归树到梯度提升,再到Shrinkage技术,全面覆盖GBDT解决回归、二分类及多分类问题的原理与实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继上篇介绍的集成学习大框架后https://blog.youkuaiyun.com/weixin_42001089/article/details/84935462

本文介绍其框架里面的GBDT。

原论文:https://statweb.stanford.edu/~jhf/ftp/trebst.pdf

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

首先举一个简单例子来生动形象的看一下其思想,拿预测年龄来讲:

假设小明的年龄是20岁,我们通过训练第一个弱分类器(目标值是20)得到预测结果比如是11岁,那么差值(残差)是9岁,那么在训练下一个弱分类器将9作为目标值,假如第二个弱分类器预测的结果是12,那么差值(残差)是-3岁,那么在训练第三个弱分类器将-3作为目标值,假如正确预测即-3。

那么最终预测结果便是三个弱分类器预测结果线性组合即相加11+12-3=20

这就是GBDT的过程,只不过GBDT将这里的残差是换成了梯度,当采用 MSE作为loss function时,梯度正好就是残差,两者一致,从这一方面看,选用残差作为梯度的这一种方法只不过是GBDT在选用了MSE作为loss function所导致的一种特例,所以总体思想就是如此,只不过随着loss function选取的不同,梯度的具体表达式也随之换一换即可。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以上只是很简单的一个比如,具体还有很多细节在里面比如决策树的构建,学习率等等,下面我们开始讲解

对于GBDT我们先整体上从三方面来剖析其通用框架:

Regression Decistion Tree即GBDT中的DT

Gradient Boosting即GBDT中的GB,也是GBDT的核心

Shrinkage

然后再看其具体解决回归,二分类以及多分类问题。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

DT决策树

首先说明一棵树是由分裂节点和叶子节点的输出值组成的,即可以将其比作是一个分段函数,其是由分段点和段内函数值组成的。

注意GBDT中的DT本质上并不是决策树(ID3、C4.5、CART等等)而是回归树,为什么呢?

因为我们最终的预测结果是多个弱分类器的预测结果线性相加,回归树预测结果是连续值,最后相加才有意义,就像上面举的那个例子,如果采用真真的回归树,那么每个弱分类器的预测结果(比如二分类)就只有1,0,一系列0和1相加显然没有意义,或者说远没有连续值更能包含更多的信息。那么GBDT到底是怎么解决分类问题呢?毕竟分类问题最后结果要的是类别,很简单就采用回归树,对于二分类我们就将0和1看做是回归问题中的y,只不过其采用的loss function函数logloss,对于对分类问题采用one-hot的形式后续会详细介绍。

其次需要注意的就是在构建回归树的过程中分支节点的选取及取值(对比分类树来看)

1)回归树不是像分类树那样采用最大熵来作为划分标准,而是采用均方差

2)回归树的每个叶子节点得到的不是像分类树那样的样本计数,而是属于这个叶子节点所有样本的平均值(当然根据的loss function这里具体也会不同,下面会看到)。

总之记住一句话DT本质是回归树

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

GB梯度提升

关于梯度的知识这里不做理论介绍,不懂的请自行查阅资料,其实也很简单,而且也是深度学习中必不可少的利用工具,所以一定要理解透彻。

首先看一下GBDT的算法过程

F_{m}(x)代表的就是前m个弱分类器预测结果的累加值(注意是前m个,不是第m个)

L代表的是损失函数

下面我先来宏观看一下其是怎么工作的:

假设我们现在要训练第m个弱分离器h,那么我们要达到的目标是什么呢?

那就是使得L(y,F_{m-1}(x)+h(x))最小,y代表真实值

怎么训练h(x)这棵树使得上面最小呢?那就是求梯度,假设这里选用的损失函数是系数为四分之一二次函数如下:

假设真实值y为0,F_{m-1}(x) = -1,那么在-1处求导变得到是-1/2,那么F_{m-1}(x) -\frac{1}{2}=-\frac{1}{2}

看是不是距离0相较于-1更近了一步呢?

实际上梯度的含义就是下降速度最快的方向,

于是乎我们就将负的梯度值作为h(x)这棵树的目标值,只要它能够拟合出负的梯度值,那么我们通过F_{m-1}(x)加上这个梯度值就可以得到真实值。

好了上面就是核心过程,下面我们来一步步看看上面图片中公式的意思。

这里有较多的数学符号,所幸的是都比较容易理解,就提一下arg_{q} min(f(x,q))

其在数学中代表的含义是求变量q使得f(x,q)最小,是一个最优化求参数问题。

步骤1:是一个初始化求F_{0}(x)的过程,公式的意思就是说,求一个\rho,然后其分别和各个目标值y_{i}带入到损失函数L中,使得总体                   损失最小,其实这里只是为了使得给出的算法更具普遍性才写的这么复杂,大多数的时候这里的\rho就取所有y_{i}的平均值                   就 好。

步骤2:这里就是一个for循环,M代表的就是一共要生成M个弱分类器即最终的强分类器是由M个弱分类器线性组合而成的

步骤3:这里就是求负梯度值了,随着L函数的不同,所求出的结果也是不尽相同,比如:

                L(y_{i},F(x_{i}))=\frac{1}{2}(y_{i}-F(x_{i}))^{2}\Leftrightarrow y_{i}-F(x_{i})

                L(y_{i},F(x_{i}))=\left | y_{i}-F(x_{i}) \right |\Leftrightarrow sign(y_{i}-F(x_{i}))

步骤4:这里其实就是训练当前这一个分类器h,该树以x作为输入数据,以步骤3求得的负梯度值为拟合目标,然后训练得到构造                  该树的参数a_{m},可以看到在构造树的过程中没有采用最大熵而是采用了均方差,正如一开头DT中介绍的那样。至于这里                  还有一个\beta参数,其实就是更进一步提供了泛化能力,还是那句话为了使得给出的算法更具普遍性这里就再加一个参                        数。

步骤5:该步骤的目的就是训练得到模型相加时权值\rho _{m},Boosting模型不是将多个弱分类器线性相加嘛,比如                                                aF_{0}(x)+bF_{1}(x)+cF_{2}(x)+....  a,b,c就是系数对吧,\rho _{m}其实就是这里的a,b,c,大多时候这里的\rho _{m}可以看成是训练模               型时需要一个调的一个超参数即学习率。

步骤6:就是更新得到第m次的F_{m}(x)值,即前m颗树预测值的线性累加和。

说明一点:从数学角度来看,步骤4和步骤5其实都是采用了最小二乘法。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Shrinkage

其是一个规避过拟合的方法,具体来说就是每次走一大步可能错过最优解,导致的结果就是在最优解周围来回徘徊,却永远得不到最优解,所以Shrinkage的思想就是每一次走的都是小碎步,虽然收敛速度可能慢些,但是却能保证最大可能的到达最优解,即以收敛速度为代价来换取最优解,体现在GBDT中就是我们会训练更多的树,其实对应到GBDT算法图片中,步骤4中的\beta,步骤5中的\rho所做的目的就是Shrinkage过程即防止过拟合。

为了好理解我们还是举个小例子,还是以二次函数为类:y=x^{2}

假设目标值是0,当前值为-2,那么-2处的导数是-4对吧,接下来我们更新下一步即

-2+(4)=2,你会发现其跳到2了,那么2处的导数是4,接着更新下一步即

2+(-4)=-2,其又跳到-2了

实际上其会一直在-2和2中徘徊却永远不能更近一步的到达0

那我们用一下Shrinkage思想吧,就是缩减步伐,假设将步伐缩减为一半,即y=\frac{1}{2}x^{2}

当前值是-2时,导数是-2,接下来我们更新看一下:

-2+(2)=0,是不是直接就达到最优值啦!!!!!!!

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

GBDT回归问题

首先还是给出其算法

对比其通用框架,这里只是将每一步更加具体化

步骤1 :采用了均值作为初始化

步骤2 :不变

步骤3:由于这里采用了\frac{1}{2}(y_{i}-F(x_{i}))^{2}作为损失函数,所以得到了负梯度值为y_{i}-F(x_{i})

步骤4:通用模板这里是采用均方差训练树,这里一样,只不过这里将树的参数a_{m}写成了叶子节点R_{jm},其含义是第m颗树的第j个                叶子节点集合

             

              假设这是第8颗树,那么R_{81}={x_{2},x_{4}}  R_{82}=x_{1},x_{3},x_{5}

步骤5:准确来说并不是通用模板的步骤5,其其实就是通用模板中步骤6中的h(x;a_{m})的值,即当前树h预测的输出值,具体是多                少呢?其计算结果其实是和选用的loss function有关系的

                当选用MSE作为loss function时结果就是均值,ave(y_{i}) |x_{i}\in R_{jm},例如上面的例子,左边的叶子节点输出值为                                (8+10)/2=9,右边叶子节点输出为(25+30+47)/2=51,所以下次来一个输入值,当其落在左面这个叶子节点的时候,该                  树的输出值就是9,右边则是51,注意这里的y_{i}并不是样本真真的目标值,而是当前的梯度,即y_{i}上面还有个~号,因为输                   入的原因,笔者这里给y上面加不了~

                当选用MAE作为loss function时,输出值是median (y_{i}-F_{m-1}(x)) |x_{i}\in R_{jm}

                 当使用Logistic loss作为时,输出值为

                 注意使用GBDT作为二分类时,正是这种情况。

步骤6:没变

那么通用步骤中的步骤5呢?其实这里并没有给出,还是那句话,该步骤其实就是一个学习率

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

GBDT二分类问题

还是先给出其算法,和回归问题相比这里本质没什么大的不同,只不过目标值只有0和1这两个值,再一个不同就是采用了Logistic loss作为损失函数

步骤1:这里并没有采用均值,而是采用如图所示的形式。

步骤2:不变

步骤3:这里采用Logistic loss作为损失函数即L(y_{i},F_{m}(x)) = -\left \{ y_{i}logp_{i} +(1-y_{i})log(1-p_{i})\right \}

                其中p_{i}=\frac{1}{1+e^{-F_{m}(x_{i})}}

               那么求其梯度可以得到上图所示的形式。

步骤4:没啥说的和回归问题一样

步骤5:这里是因为采用Logistic loss作为损失函数导致的该结果

步骤6:没变

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

说明:通过看上面两部分可能有人会对步骤5公式的得来产生疑问,其到底是怎么得到的,其实其有严密的数学推导过程和逻辑在里面,GBDT论文作者在论文中也并没有详细介绍,有兴趣的同学可以自行查阅资料推导看看对于不同的loss function函数这里是怎么得到不同结果的,笔者这里直接就给出了结果

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

GBDT多分类问题

还是先给出算法:

这里比以前的多了一个for循环,其是这样做的:

现将分类转化为one-hot形式比如有如下:假设有三个类别,7个样本。

其针对类别1一共训练M颗树,类别2一共训练M颗树,类别3一共训练M颗树

所以假设有K个类别,实际上一共训练了M*K颗树

训练过程是先训练各个类别的第一棵树,然后再训练各个类别的第二棵树,,,,,,直到M即每个类别下有M棵树。

其它所有步骤和上面基本相同需要注意的就是其选用的损失函数:

L(y_{i},F_{m}(x)) = -\sum_{k=1}^{K}y_{k}logp_{k}(x)

其中p_{k}(x)=\frac{e^{F_{k}(x)}}{\sum_{l=1}^{K}e^{F_{l}(x)}}

----------------------------------------------------------------------------------------------------------------------------------------------------------------

说明:对于二分类和多分类中选用的损失的函数其实分别看做是Logistic loss和softmax形式即p_{k}(x),本质来说softmax是更具一般形式的,Logistic loss只不过是softmax的一种情况,这两种形式的损失函数在深度学习中尤为常见,如果大家打算入坑深度学习的话,也一定记得这哥俩,哈哈哈。

----------------------------------------------------------------------------------------------------------------------------------------------------------------

总结:

1)不论是回归还是分类,其本质思想没有变,即使用前m-1棵树损失函数总值的负梯度值作为目标值去训练当前这一棵m树,进而       使得m棵树的累加和逼近真实值!

2)通过上述我们发现对于GBDT回归模型也好,分类模型也罢,其在代码实现方面其实都是相同的,所以去看源码的话你会发现            GBDT虽然看似有GradientBoostingRegressor()和GradientBoostingClassifier()两种方法,但是两者都是继承了                                BaseGradientBoosting()类的,该类包含了共同的步骤比如求负梯度值

3)简单总结一下其何Adaboost的不同点:

      Adaboost是通过前项计算的一种模式,然后通过提升错分数据点的权重来定位模型的不足

     更具选取的损失函数等不同其可以分为:

      而GBDT求梯度反射可以看成是后向更新是通过算负梯度值来提升模型的不足

------------------------------------------------------------------------------------------------------------------------------------------------------------------

下一篇GBDT的升级版:Xgboost也是实际用的最多的一种模型https://blog.youkuaiyun.com/weixin_42001089/article/details/84965333

 

 

 

 

 

 

### XGBoost算法的数学公式与推导 XGBoost是一种基于梯度提升决策树(GBDT)的机器学习方法,其核心在于通过构建一系列加性模型来最小化目标函数。以下是关于XGBoost算法公式的具体描述及其推导过程。 #### 加性模型表示 XGBoost的整体模型可以表示为一组基函数 \( f_k(x) \) 的线性组合[^1]: \[ \hat{y}_i = \sum_{k=1}^{K} f_k(x_i), \quad f_k \in \mathcal{F} \] 其中,\( f_k \) 表示一棵回归树,而集合 \( \mathcal{F} \) 定义了所有可能的回归树空间。每棵回归树由结构 \( q(x) \) 和叶节点权重 \( w \) 组成[^4]。 #### 目标函数定义 为了优化模型性能,XGBoost引入了一个可微的目标函数,该函数通常包括两部分:训练损失和正则项。形式如下: \[ Obj(\theta) = L(y, \hat{y}) + \Omega(f) \] - 训练损失 \( L(y, \hat{y}) \) 度量预测值 \( \hat{y} \) 与真实标签 \( y \) 之间的差异。 - 正则项 \( \Omega(f) \) 控制模型复杂度,防止过拟合。 对于单棵树 \( f_t \),目标函数的具体表达式为[^3]: \[ Obj^{(t)} = \sum_{i=1}^n l(y_i, \hat{y}_i^{(t)}) + \sum_{j=1}^T \gamma_j \|w_j\|^2_2 + \lambda T \] 这里: - \( n \) 是样本数量; - \( T \) 是叶子节点的数量; - \( \gamma_j \) 和 \( \lambda \) 分别控制叶子权重和平滑参数。 #### 泰勒展开近似 为了简化计算,XGBoost利用二阶泰勒展开对损失函数进行局部逼近。假设当前迭代步数为 \( t \),则有: \[ l(y_i, \hat{y}_i^{(t)}) \approx g_i (\hat{y}_i^{(t)} - \hat{y}_i^{(t-1)}) + \frac{1}{2} h_i (\hat{y}_i^{(t)} - \hat{y}_i^{(t-1)})^2 \] 其中: - \( g_i = \partial_{\hat{y}_i^{(t-1)}} l(y_i, \hat{y}_i^{(t-1)}) \) 是一阶梯度; - \( h_i = \partial^2_{\hat{y}_i^{(t-1)}} l(y_i, \hat{y}_i^{(t-1)}) \) 是二阶梯度。 代入目标函数后得到: \[ Obj^{(t)} \approx \sum_{i=1}^n [g_i \hat{y}_i^{(t)} + \frac{1}{2} h_i (\hat{y}_i^{(t)})^2] + \gamma J + \frac{\lambda}{2}\|w\|^2_2 \] 进一步整理得: \[ Obj^{(t)} = \sum_{j=1}^J \left[ \sum_{i \in I_j} g_i w_j + \frac{1}{2} \left( \sum_{i \in I_j} h_i + \lambda \right) w_j^2 \right] + \gamma J \] 其中 \( I_j \) 表示分配到第 \( j \) 个叶子节点的样本索引集。 #### 最优解求解 针对每个叶子节点 \( j \),可以通过偏导数等于零的方式找到最优权重 \( w_j^\ast \)[^3]: \[ w_j^\ast = -\frac{\sum_{i \in I_j} g_i}{\sum_{i \in I_j} h_i + \lambda} \] 将此结果代回目标函数,则最终增益为: \[ Gain = \frac{1}{2} \frac{\left( \sum_{i \in I_L} g_i \right)^2}{\sum_{i \in I_L} h_i + \lambda} + \frac{1}{2} \frac{\left( \sum_{i \in I_R} g_i \right)^2}{\sum_{i \in I_R} h_i + \lambda} - \frac{1}{2} \frac{\left( \sum_{i \in I} g_i \right)^2}{\sum_{i \in I} h_i + \lambda} - \gamma \] 这一公式用于评估分裂点的有效性。 --- ```python import numpy as np def calculate_gain(g_left, h_left, g_right, h_right, lambda_reg=1.0, gamma_split=0.0): gain_left = (np.sum(g_left)**2 / (np.sum(h_left) + lambda_reg)) gain_right = (np.sum(g_right)**2 / (np.sum(h_right) + lambda_reg)) gain_total = ((np.sum(np.concatenate([g_left, g_right]))**2) / (np.sum(np.concatenate([h_left, h_right])) + lambda_reg)) return 0.5 * (gain_left + gain_right - gain_total) - gamma_split ``` 上述代码实现了分裂增益的计算逻辑。 --- 相关问题
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值