22(2).模型融合---GBDT
一、GBDT简介
- 全称:Gradient Boosting Decison Tree
- 别名:GBT(Gradient Boosting Tree), GTB(Gradient Tree Boosting ), GBRT(Gradient Boosting Regression Tree), MART(Multiple Additive Regression Tree)
- 作者:Friedman
- 所属:boosting迭代型、树类算法
- Boosting Tree 对于每一轮基学习器,拟合的是当前模型与标签值的残差
- GBDT 对于每一轮基学习器,拟合的是当前模型与标签值的残差的负梯度
- 适用范围:分类、回归
- 分类:用Gini系数,越小越好
- 回归:用平方误差,越小越好
- 回归树与决策树的生成框架是相同的,唯一不同在于节点的属性选择标准
- 基学习器:CART树(分类回归树)
- 思想:如果样本1的输出真实值为10,树T1针对样本1的预测值为18,然后我们让树T2去拟合样本1的值为10-18=-8(残差)。如果树T2的输出值为-10,我们再让树T3去拟合-8-(-10)=2(残差),结果树T3的预测值为1。如果到此迭代结束,在最终对样本1的预测值为:18+(-10)+1=9。通过多轮迭代,每轮迭代产生一个弱模型,每个模型都是在上一个模型的残差基础上进行训练的,最后将所有树的结果求和得出最终的结果。
- 优点:
- 能够处理连续值/离散值;
- 对异常值的鲁棒性很强,如Huber损失函数和Quantile损失函数
- GBDT的并行主要是针对单棵树特征处理和选择的并行(特征排序),以及在模型完成后进行预测时的并行。
- sklearn链接:https://www.studyai.cn/modules/ensemble.html#gradient-tree-boosting
- 论文链接:
二、GBDT步骤
GBDT流程图
1.负梯度拟合
第t棵树的第i个样本的损失函数的负梯度表示为:$r_{ti} = -\bigg[\frac{\partial L(y_i, f(x_i)))}{\partial f(x_i)}\bigg]_{f(x) = f_{t-1}\;\; (x)}$
负梯度的计算:
- 对于平方损失函数,拟合的残差就是负梯度;(为什么要拟合负梯度,见第三节)
- 对于一般损失函数(梯度下降),拟合的负梯度就是残差的近似值,分裂结点划分时枚举所有特征的值,选取划分点。
利用$(x_i,r_{ti})(i=1,2,...,m)$我们可以拟合一棵CART回归树,得到了第t棵回归树,其对应的叶节点区域$R_{tj},j=1,2,...,J$其中J为叶子节点的个数。
GBDT分类回归用的都是CART回归树,选择特征时用均方误差选择最小的分割点。对于任意划分特征A,对应的任意划分点s两边划分成的数据集D1和D2,求出使D1和D2各自集合的均方差最小,同时D1和D2的均方差之和最小所对应的特征和特征值划分点。表达式为:
$$\underbrace{min}_{A,s}\Bigg[\underbrace{min}_{c_1}\sum\limits_{x_i \in D_1(A,s)}(y_i - c_1)^2 + \underbrace{min}_{c_2}\sum\limits_{x_i \in D_2(A,s)}(y_i - c_2)^2\Bigg]$$
其中,c1为D1数据集的样本输出均值,c2为D2数据集的样本输出均值。
针对每一个叶子节点里的样本,我们求出使损失函数最小,也就是拟合叶子节点最好的输出值$c_{tj}$如下:$c_{tj} = \underbrace{arg\; min}_{c}\sum\limits_{x_i \in R_{tj}} L(y_i,f_{t-1}(x_i) +c)$
这样得到了本棵决策树拟合函数:$h_t(x) = \sum\limits_{j=1}^{J}c_{tj}I(x \in R_{tj})$
从而本轮最终得到的强学习器的表达式如下:$f_{t}(x) = f_{t-1}(x) + \sum\limits_{j=1}^{J}c_{tj}I(x \in R_{tj})$ ,最后预测的结果是每棵树的预测结果相加。
2.回归问题
给定数据集:$T=\{(x_,y_1),(x_2,y_2), ...(x_m,y_m)\}$
(1) 常用损失函数
a.MSE(GBDT回归所用)
- $Cost(y,f(x))=\frac{1}{2}\sum(y-f(x))^2$
- 负梯度:$y-f(x)$
- 对异常值很敏感
- 初始模型F0由目标变量的平均值给出
b.绝对损失
- $Cost(y,f(x))=\frac{1}{2}\sum|y-f(x)|$
- 负梯度:$sign(y-f(x))$
- 对异常值不敏感
- 初始模型F0由目标变量的中值给出
c.Huber损失
- $L(y, f(x))= \begin{cases} \frac{1}{2}(y-f(x))^2& {|y-f(x)| \leq \delta}\\ \delta(|y-f(x)| - \frac{\delta}{2})& {|y-f(x)| > \delta} \end{cases}$
- 负梯度:$r(y_i, f(x_i))= \begin{cases} y_i-f(x_i)& {|y_i-f(x_i)| \leq \delta}\\ \delta sign(y_i-f(x_i))& {|y_i-f(x_i)| > \delta} \end{cases}$
- 它是MSE和绝对损失的组合形式,对于远离中心的异常点,采用绝对损失,其他的点采用MSE,这个界限一般用分位数点度量。
- 对异常值不敏感
- 使用alpha参数来控制损失函数对离群点(outliers)的敏感度(sensitivity)
d.Quantile损失
- $L_q(\text{y},\hat{\text{y}})=\frac{1}{n}(1-q)\sum_{i:\hat{y_i}\geq y_i}(\hat{y_i} - y_i)+\frac{1}{n}q\sum_{j:\hat{y_j}< y_j}(y_j-\hat{y_j} )$
- 负梯度:$r(y_i, f(x_i))= \begin{cases} y_i-f(x_i)& {|y_i-f(x_i)| \leq \delta}\\ \delta sign(y_i-f(x_i))& {|y_i-f(x_i)| > \delta} \end{cases}$
- 怎么理解?
- 用于分位数回归
- 对于Huber损失和分位数损失,主要用于健壮回归,也就是减少异常点对损失函数的影响
- 当q>0.5时,目标函数对预测值偏小的结果惩罚更大
- 当q<0.5时,目标函数对预测值偏大的结果惩罚更大
(2)算法
step1
初始化:针对数据集,建立第一个CART回归树$T_1(x)$
- $f_0(x) = \underbrace{arg\; min}_{c}\sum\limits_{i=1}^{m}L(y_i, c)$
- c是针对每一个叶子节点里的样本,使得损失函数最小,也就是拟合叶子节点最好的输出值
step2
对迭代次数t=1,2,...,T有:
- a.对样本i=1,2,...,m,计算负梯度$r_{ti} = -\bigg[\frac{\partial L(y_i, f(x_i)))}{\partial f(x_i)}\bigg]_{f(x) = f_{t-1}\;\; (x)}$
- b.利用$(x_i,r_{ti})(i=1,2,3,...m)$拟合一棵CART回归树,得到第t棵回归树,其对应的叶子节点区域为$R_{tj},j=1,2,...,J$其中,J为回归树t的叶子节点的个数
- c.对叶子区域j=1,2,...J,计算最佳拟合值$c_{tj} = \underbrace{arg\; min}_{c}\sum\limits_{x_i \in R_{tj}} L(y_i,f_{t-1}(x_i) +c)$
- d.更新强学习器$f_{t}(x) = f_{t-1}(x) + \sum\limits_{j=1}^{J}c_{tj}I(x \in R_{tj})$
3.分类问题
这里解释下,为什么GBDT解决分类问题用的也是回归树。因为GBDT的根本就是在不断地拟合残差,残差的加减可以逐渐减小偏差。而分类树输出的是类别,他们之间的加减是没有意义的。分类问题和回归问题的最大不同在于损失函数的定义以及节点输出值的确定,其他都是一样的。
(1)损失函数
- 对数似然损失函数:
- 二元:$L(y, f(x)) = log(1+ exp(-yf(x)))$
- 多元:$L(y, f(x)) = - \sum\limits_{k=1}^{K}y_klog\;p_k(x)$
- 指数损失函数:
- 与adaboost的损失函数一样,与log loss相比,对于误标记的样本的鲁棒性较差,只能用于二元分类
- $L(y, f(x)) = exp(-yf(x))$
(2)二分类
- 损失函数:$L(y, f(x)) = log(1+ exp(-yf(x)))$,标签y属于{-1,+1}
- 负梯度:$r_{ti} = -\bigg[\frac{\partial L(y, f(x_i)))}{\partial f(x_i)}\bigg]_{f(x) = f_{t-1}\;\; (x)} = y_i/(1+exp(y_if(x_i)))$
- 生成的决策树每个叶子节点最佳负梯度拟合值为:$c_{tj} = \underbrace{arg\; min}_{c}\sum\limits_{x_i \in R_{tj}} log(1+exp(-y_i(f_{t-1}(x_i) +c)))$
- 上式比较难优化,一般用近似值替代:$c_{tj} = \sum\limits_{x_i \in R_{tj}}r_{ti}\bigg / \sum\limits_{x_i \in R_{tj}}|r_{ti}|(1-|r_{ti}|)$
(3)多分类
- 损失函数:$L(y, f(x)) = - \sum\limits_{k=1}^{K}y_klog\;p_k(x)$
- 其中如果样本输出类别为k,则yk=1。第k类的概率pk(x)的表达式为:
- 负梯度:第t轮的第i个样本对应类别l的负梯度误差$r_{til} = -\bigg[\frac{\partial L(y_i, f(x_i)))}{\partial f(x_i)}\bigg]_{f_k(x) = f_{l, t-1}\;\; (x)} = y_{il} - p_{l, t-1}(x_i)$
- 生成的决策树每个叶子节点的最佳负梯度拟合值为:$$c_{tjl} = \underbrace{arg\; min}_{c_{jl}}\sum\limits_{i=0}^{m}\sum\limits_{k=1}^{K} L(y_k, f_{t-1, l}(x) + \sum\limits_{j=0}^{J}c_{jl} I(x_i \in R_{tjl}))$$
- 上式比较难优化,一般用近似值代替:$c_{tjl} = \frac{K-1}{K} \; \frac{\sum\limits_{x_i \in R_{tjl}}r_{til}}{\sum\limits_{x_i \in R_{til}}|r_{til}|(1-|r_{til}|)}$(怎么得到的?)
- 除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,多元GBDT分类和二元GBDT分类以及GBDT回归算法过程相同。
4.GBDT用到的技巧
4.1 shrinkage
- Shrinkage的思想认为,每次走一小步逐渐逼近结果的效果,要比每次迈一大步很快逼近结果的方式更容易 得到精确值,即它不完全信任每一棵残差树,认为每棵树只学到了真理的一部分累加的时候只累加了一小部分多学几棵树来弥补不足。 这个技巧类似于梯度下降里的学习率
- $f_{k}(x) = f_{k-1}(x) + \nu h_k(x)$,其中v被称之为learning rate,它可以控制梯度下降的步长,并且可以通过learning_rate参数来设置,$\gamma$是人为设置的参数,用来调整学习的快慢和精度
- 选择小于1的比例可以减少泛化时的方差(测试集的方差),即防止过拟合,但是会增加样本拟合的偏差,因此取值不能太低。推荐在[0.5, 0.8]之间。
4.2 重复使用属性
在GBDT的每一棵树中,一个属性可以在多个节点用到
4.3 子采样
GBDT学习了RF里的样本采样方法,每一棵树基于原始原本的一个子集进行训练,达到防止过拟合和提升训练速度的目的。
- 样本子采样subsample,通过无放回采样获得(RF是有放回采样)
- 减少方差的策略是特征子采样,这种类似于随机森林中的随机分割,子采样的特征数量可以通过参数max_features来控制,使用一个小的max_features值能够显著降低计算时间。
4.4 剪枝
对于弱学习器即CART回归树进行正则化剪枝
5.对结果的解释
- 特征重要性
- 如果一个特征在树的分割节点中用的越频繁,则这个特征的重要性就越高。 这种特征重要性的概念可以 通过简单的平均一下每棵树上的特征重要性扩展到决策树集合。
- 如果一个特征在树的分割节点中用的越频繁,则这个特征的重要性就越高。 这种特征重要性的概念可以 通过简单的平均一下每棵树上的特征重要性扩展到决策树集合。
- 部分依赖性
三、GBDT面试总结
1.优缺点
优点:
-
可以灵活处理各种类型的数据,包括连续值和离散值。
-
在相对少的调参时间情况下,预测的准备率也可以比较高。这个是相对SVM来说的。
-
使用一些健壮的损失函数,对异常值的鲁棒性非常强。比如 Huber损失函数和Quantile损失函数。
缺点:由于弱学习器之间存在依赖关系,难以并行训练数据。不过可以通过自采样的SGBT来达到部分并行。
2.GBDT 和 随机森林/Adaboost/LR的区别与联系
-
GBDT和随机森林
- 相同点:
- 都是由多棵树组成
- 最终的结果都是由多棵树一起决定
- 不同点:
- 组成随机森林的树可以并行生成;而GBDT只能是串行生成 ;
- 对于最终的输出结果而言,随机森林采用多数投票等;而GBDT则是将所有结果累加起来,或者加权累加起来 ;
- 随机森林对异常值不敏感,GBDT对异常值非常敏感 ;
- 随机森林对训练集一视同仁,GBDT是基于权值的弱分类器的集成 ;
- 随机森林是通过减少模型方差提高性能,GBDT是通过减少模型偏差提高性能;
- 随机森林既可以使用决策树也可以使用回归树,但是gbdt采用的都是CART回归树。
- 相同点:
-
GBDT和Adaboost
和AdaBoost一样,Gradient Boosting也是重复选择一个表现一般的模型并且每次基于先前模型的表现进行调整。不同的是,AdaBoost是通过提升错分数据点的权重来定位模型的不足而Gradient Boosting是通过算梯度(gradient)来定位模型的不足。因此相比AdaBoost, Gradient Boosting可以使用更多种类的目标函数,而当目标函数是均方误差时,计算损失函数的负梯度值在当前模型的值即为残差。
-
GBDT和LR
从决策边界来说,线性回归的决策边界是一条直线,逻辑回归的决策边界是一条曲线,而GBDT的决策边界可能是很多条线。
3. 为什么拟和负梯度可以降低集成模型的损失,即为什么拟合负梯度是可行的?
4. 即便拟合负梯度是可行的,为什么不直接拟合残差? 拟合负梯度好在哪里?
Boosting Tree 和 GBDT 两者的相同之处在于,都是迭代回归树,都是累加每棵树的结果作为最终结果,每棵树都在学习前m-1棵树尚存的不足,从总体流程和输入输出上两者是没有区别的.
两者的主要区别就在于每步迭代的时候是否使用残差的负梯度作为树的拟合对象,前者不用残差的负梯度而是使用残差,是全局最优值,后者使用的是 局部最优方向(负梯度)*步长(𝛽),即前者是每一步都试图让结果变成最好,后者则每步试图让结果更好一点.
Boosting Tree的最大问题在于,它依赖残差进行优化,损失函数一般固定为反应残差的均方差损失函数,因此 当均方差损失函数失效(该损失函数对异常值敏感)的时候,换了其他一般的损失函数,便很难得到优化的结果。同时,因为损失函数的问题,Boosting Tree也很难处理回归之外问题。 而后者使用梯度下降的方法,对于任意可以求导的损失函数它都可以处理.
GBDT本质上是以梯度下降和参数搜索(𝛽)的办法简化了Boosting Tree对于损失函数的优化求解问题.
5.gbdt在分类时,当以指数损失作为损失函数时,为什么等价于adaboost?
如果采用指数函数,那么Adaboost每一步就在拟合指数损失的梯度。也就是第t轮要依据$(x_i, -y_i exp(-y_if_{t-1}x)$拟合一颗决策树。
$\sum\limits_{i=1}^{m}Loss(f_{t-1}(x)+\alpha_tG_t(x) , y_i) = \sum\limits_{i=1}^{m}exp(-y_i(f_{t-1}(x)+\alpha_tG_t(x))) = \sum\limits_{i=1}^{m}exp(-y_i(f_{t-1}(x)) exp(-y_i\alpha_tG_t(x)) = \sum\limits_{i=1}^{m} w_{ti}^{’}exp(-y_i\alpha G(x))$
最后这个式子就是我们Adaboost的需要极小化的损失函数公式,它可以从第一步的GBDT的残差思路递推出来。
参考文献:
【1】https://github.com/Anfany/Machine-Learning-for-Beginner-by-Python3/tree/master/Boosting/GBDT【大佬github】
【2】梯度提升树(GBDT)原理小结(刘建平大佬)