老饼讲解:一步一步上手学习
GBDT梯度提升树(Gradient Boosting Decision Tree)也是一种经典的boosting集成模型,它通过集成回归树来解决二分类问题,它的特点是训练过程利用了梯度来训练回归树,从而使得树模型的提升更加有效,下面我们就一起看看GBDT模型的核心原理,并用一个具体的代码例子来熟悉GBDT模型的应用。
我们一步一步来理解GBDT的内容。首先,GBDT是用来解决二分类问题,也就是判断样本是正样本还是负样本。好了,下面我们先来看看GBDT模型的构成,这样可以有个初步印象:

如图,GBDT由多棵Cart弱回归树构成,再经过学习率lr与阈值b调整后,就得到样本类别最终的判别值,下面更直接的来看看模型的数学表述,如下:
GBDT的模型表达式为:
其中,
:第i颗Cart回归决策树的预测值
:学习率,自行设定的超参数
:类别的判别值,g>0时为正样本,g<0时为负样本
从模型的表达式可知,GBDT模型由多个回归树组成,将所有回归树的预测值乘以学习率lr后,加上阈值,就是模型的判别值,而判别的时候,只需要看判别值g是不是大于0,如果大于0就是正样本。
上面得到的是GBDT模型的判别值,如果需要得到类别的概率,就进一步将用sigmoid函数将判别值转换为概率就可以了,如下:
如公式所示,在GBDT的判别值上套上sigmoid函数后,就是样本属于正样本的概率了。
好了,GBDT模型的结构差不多就是这样了,从模型中我们可以看到,它需要训练的就是其中的各个Cart回归树,以及外层的阈值b,而lr则是一个预设参数,不需要训练。总的来说,就是要训练阈值b和各个各个Cart回归树,下面我们来看看它具体是如何训练的。
先来说说GBDT的损失函数,它采用的是对数似然损失函数,如下:
其中,是第i个样本的真实值
是第i个样本的预测值
好了,我们来看看GBDT整体的训练顺序,如下:

如图所示,GBDT先训练好阈值b,然后逐棵训练回归树,直到训练完m棵回归树为止,可知,它采用的是前向分步算法训练,也就是在已有树模型集合的基础上,再逐个添加新的回归树,以此来逐步提升模型的预测效果。
好了,我们都知道,GBDT采用逐棵树训练的方式,那么每棵回归树是如何训练的呢?
观察到损失函数是关于每个样本的预测值的函数,如果往负梯度方向移动, 将下降,基于此思路,GBDT训练新树时,将当前预测值在损失函数的负梯度,作为新树拟合值:

可知,GBDT每添加一棵回归树树,所有样本的预测值就往损失函数的负梯度方向挪一下,这就是梯度提升树GBDT,非常形象:每次都往负梯度方向增加树,逐步提升模型的精度。
事实上,GBDT“梯度提升决策树”这个命名,就非常形象地解析了GBDT算法的特性:
1、决策树 :使用一组决策树进行综合决策
2、提升 :训练时使用提升方式,逐棵逐棵训练
3、梯度 :每棵树拟合值为树集合预测值的负梯度方向
最后,一起整体来看看GBDT的具体训练算法流程。
先来上个算法流程图,大家结合下面的描述来理解就好了:

简单来说,GBDT就是先训练阈值b,再逐棵训练弱回归树T,最后所有的回归树就集成了GBDT模型。
先来说说阈值b的具体训练方法。
阈值b训练时,只需要使用下述公式来计算来就可以了:
其中,是样本y值的均值。
只要将损失函数对b求驻点,就可以得到这条公式了。
好了,再来说说弱回归树的具体训练流程,如下:
1. 计算本次回归树每个样本的拟合值(即残差):
残差的计算公式如下:
说明:该公式就是损失函数对的负梯度
2. 用上述残差作为每个样本的目标预测值,训练弱回归树
值得注意的是,训练回归树时需要注意,要将参数调为训练弱树。
例如把最大分裂深度<=3就是训练弱回归树的一种策略。
3. 优化弱回归树的叶子节点
进一步优化本次回归树的预测值(即树叶子节点的取值),使本次新增的回归树能更优地降低GBDT损失值。
回归树中第k个叶子节点的预测值取值如下:
其中,
: 指回归树第k个节点上的所有样本
说明:该公式由损失函数L对叶子节点值求驻点即可得到。
总的来说,GBDT就是先训练好阈值b,然后逐棵训练弱回归树,每训练完一棵弱回归树时都优化它叶子节点上的取值,尽可能降低损失函数。
GBDT的原理大概就是这么回事了,下面我们借助sklearn来实现一下GBDT。
"""
本代码展示sklearn包实现GBDT梯度提升树
本代码来自《老饼讲解-机器学习》www.bbblearn.com
"""
import matplotlib.pyplot as plt
from sklearn.datasets import make_gaussian_quantiles
from sklearn.ensemble import GradientBoostingClassifier
# ----- 数据生成 --------
# 生成2维正态分布,数据按分位数分为两类,500个样本,2个样本特征,协方差系数为2
X,y=make_gaussian_quantiles(n_classes=2,cov=2.0,n_samples=500,n_features=2,random_state=1) # 生成训练样本数据
#--------------模型训练与预测---------------------
clf = GradientBoostingClassifier(n_estimators=100,learning_rate=0.1,random_state=0) # 初始化GBDT模型
clf.fit(X, y) # 模型训练
pred = clf.predict(X) # 模型预测的类别
proba = clf.predict_proba(X) # 模型预测的概率
# ----------------- 打印结果-------------------------
fig, axes = plt.subplots(2, 1,figsize=(10, 6)) # 初始化画布
plt.subplots_adjust(wspace=0.2, hspace=0.3) # 调整画布子图间隔
axes[0].scatter(X[:, 0], X[:, 1], c=y) # 画出样本与真实类别
axes[0].set_title('sample-true-class') # 设置子图的标题
axes[1].scatter(X[:, 0], X[:, 1], c=pred) # 画出样本与预测类别
axes[1].set_title('sample-predict-class') # 设置子图的标题
plt.show() # 显示画布
print("\n----前10个样本预测结果-----:\n",proba[1:10,1]) # 前10个样本预测值代码运行结果如下:


从图中可以看到,模型的预测类别与真实类别几乎是一致的。
总的来说,GBDT就是一种Boosting算法,它集成多棵回归树来解决二分类问题。它的特点是每棵树训练时的拟合目标是树集合预测值的负梯度方向,所以就称为“梯度提升决策树”。
评论