具体请见论文Greedy Function Approximation: A Gradient Boosting Machine
1. GBDT的基本思想
单模型情况下预测结果容易产生过拟合,例如普通决策树,要想达到比较好的预测效果,需要将树的深度调得比较深,叶节点的最大样本数目调得小一点等才能达到比较高的准确率。但是这样会带来严重的过拟合问题,针对这些问题,GBDT采用多颗决策树组合的方法来实现比较高的准确率,同时避免过拟合问题。
假设待分类样本为
((X(1),y(1)),(X(2),y(2)),⋯,(X(m),y(m)))
(
(
X
(
1
)
,
y
(
1
)
)
,
(
X
(
2
)
,
y
(
2
)
)
,
⋯
,
(
X
(
m
)
,
y
(
m
)
)
)
,其中
m
m
为样本数量,为第
i
i
个样本的特征,为第
i
i
个样本的类标签。GBDT的任务是构建颗决策树
f1,f2,⋯fk
f
1
,
f
2
,
⋯
f
k
,对于每个样本
i
i
,其最终的预测值是每颗决策树的预测值的和:
2, 单颗决策树的构建过程
对于一批训练样本
((X(1),y(1)),(X(2),y(2)),⋯,(X(m),y(m)))
(
(
X
(
1
)
,
y
(
1
)
)
,
(
X
(
2
)
,
y
(
2
)
)
,
⋯
,
(
X
(
m
)
,
y
(
m
)
)
)
,首先计算标签的均值作为第一步的预测值:
然后计算每一个样本的残差:
这样得到的残差作为第一棵树的学习标准。即:
接下来会以 ((X(1),dY(1)),(X(2),dY(2)),⋯,(X(m),dY(m))) ( ( X ( 1 ) , d Y ( 1 ) ) , ( X ( 2 ) , d Y ( 2 ) ) , ⋯ , ( X ( m ) , d Y ( m ) ) ) 作为第一颗树的根节点,学习出一颗 CART C A R T 树,具体学习方法见 CART树算法详解。当指定最大树的深度,最大叶节点的个数,叶节点包含的最大样本数目后,树会在某一时刻停止训练,此时得到学习器,也就是第一个决策树 tree1 t r e e 1 。
对于得到的 tree1 t r e e 1 和所有的样本,根据 tree1 t r e e 1 得到每个样本的预测值 predicti p r e d i c t i ,然后跟新每个样本的残差:
其中 αk α k 为学习率,通常设置为定值, X(i) X ( i ) 为第 i i 个样本的特征值, 为第 k k 颗决策树对第个样本的预测值。由此得到更新后的残差值 (dY(1),dY(2),⋯,dY(m)) ( d Y ( 1 ) , d Y ( 2 ) , ⋯ , d Y ( m ) ) ,然后作为第2颗树的学习标准,以此类推,直到训练到第 K K 颗树为止。
3. 损失函数与梯度下降
在GBDT决策树当中,采用的损失函数为:
其中 hθ(X(i)) h θ ( X ( i ) ) 为前面 j j 颗树对于样本的预测值之和,即:
因此用 L(θ) L ( θ ) 对 X(i) X ( i ) 求导,得:
即梯度的方向就是每次训练完成之后样本的残差,然后将此残差作为下一颗树的 target t a r g e t 值继续学习,整个算法的基本过程为:
- 对于m个训练样本
((X(1),y(1)),(X(2),y(2)),⋯,(X(m),y(m)))
(
(
X
(
1
)
,
y
(
1
)
)
,
(
X
(
2
)
,
y
(
2
)
)
,
⋯
,
(
X
(
m
)
,
y
(
m
)
)
)
,计算均值:
μ=1m∑i=1my(i) μ = 1 m ∑ i = 1 m y ( i ) - 计算样本的残差 dYi=y(i)−μ d Y i = y ( i ) − μ
- 设树的总颗数为
K
K
,对于,对于所有的残差
dY1,dY2,⋯,dYm
d
Y
1
,
d
Y
2
,
⋯
,
d
Y
m
通过
CART
C
A
R
T
树学习出一个学习器
treek
t
r
e
e
k
,即:
treek=Train_Learner(X,dY) t r e e k = T r a i n _ L e a r n e r ( X , d Y )
然后更新残差:
dYi=dYi−α×treek(X(i)) d Y i = d Y i − α × t r e e k ( X ( i ) )
其中 α α 为学习率, treek(X(i)) t r e e k ( X ( i ) ) 为第 i i 个样本在第颗树上的预测值。 - 不断重复3中的步骤,直到训练到第 K K 颗树为止。
- 最终的预测结果为,第个样本的预测值为所有树的预测值的叠加和:
predict(X(j))=μ+α∑k=1Ktreek(X(j)) p r e d i c t ( X ( j ) ) = μ + α ∑ k = 1 K t r e e k ( X ( j ) )
4. gbdt中gradient和boosting的体现
4.1 gradient
到目前为止,我们的确没有用到求导的Gradient。在当前版本GBDT描述中,的确没有用到Gradient,该版本用残差作为全局最优的绝对方向,并不需要Gradient求解.
那么哪里体现了Gradient呢?其实回到第一棵树结束时想一想,无论此时的cost function是什么,是均方差还是均差,只要它以误差作为衡量标准,残差向量(-1, 1, -1, 1)都是它的全局最优方向,这就是Gradient。
4.2 boosting
gbdt是boosting,但不是Adaboost,GBDT不是Adaboost Decistion Tree。Adaboost是另一种boost方法,它按分类对错,分配不同的weight,计算cost function时使用这些weight,从而让“错分的样本权重越来越大,使它们更被重视”。Bootstrap也有类似思想,它在每一步迭代时不改变模型本身,也不计算残差,而是从N个instance训练集中按一定概率重新抽取N个instance出来(单个instance可以被重复sample),对着这N个新的instance再训练一轮。由于数据集变了迭代模型训练结果也不一样,而一个instance被前面分错的越厉害,它的概率就被设的越高,这样就能同样达到逐步关注被分错的instance,逐步完善的效果。Adaboost的方法被实践证明是一种很好的防止过拟合的方法
GBDT也可以在使用残差的同时引入Bootstrap re-sampling,GBDT多数实现版本中也增加的这个选项,但是否一定使用则有不同看法。re-sampling一个缺点是它的随机性,即同样的数据集合训练两遍结果是不一样的,也就是模型不可稳定复现,这对评估是很大挑战,比如很难说一个模型变好是因为你选用了更好的feature,还是由于这次sample的随机因素。
5. gbdt树的打印
5.1. 安装依赖的软件和库
- 安装GraphViz并配置环境变量
- 安装pydotplus
5.2. 获取gbdt模型
gbdt_model = grid.best_estimator_
5.3. 打印决策树
from sklearn import tree
import pydotplus
estimators = gbdt_model.estimators.shape[0]
for i in range(estimators):
dot_data = tree.export_graphviz(gbdt_model)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_pdf("../data/tree_"+str(i)+".pdf")