上一篇介绍了AdaBoost算法,AdaBoost每一轮基学习器训练过后都会更新样本权重,再训练下一个学习器,最后将所有的基学习器加权组合。AdaBoost使用的是指数损失,这个损失函数的缺点是对于异常点非常敏感,(关于各种损失函数可见之前的文章: 常见回归和分类损失函数比较),因而通常在噪音比较多的数据集上表现不佳。Gradient Boosting在这方面进行了改进,使得可以使用任何损失函数 (只要损失函数是连续可导的),这样一些比较robust的损失函数就能得以应用,使模型抗噪音能力更强。
Boosting的基本思想是通过某种方式使得每一轮基学习器在训练过程中更加关注上一轮学习错误的样本,区别在于是采用何种方式?AdaBoost采用的是增加上一轮学习错误样本的权重的策略,而在Gradient Boosting中则将负梯度作为上一轮基学习器犯错的衡量指标,在下一轮学习中通过拟合负梯度来纠正上一轮犯的错误。这里的关键问题是:为什么通过拟合负梯度就能纠正上一轮的错误了?Gradient Boosting的发明者给出的答案是:函数空间的梯度下降。
函数空间的的梯度下降
这里首先回顾一下梯度下降 (Gradient Descend)。机器学习的一大主要步骤是通过优化方法最小化损失函数
Gradient Boosting 采用和AdaBoost同样的加法模型,在第m次迭代中,前m-1个基学习器都是固定的,即
因而在第m步我们的目标是最小化损失函数
对比式 (1.2)和 (1.3),可以发现若将
负梯度也被称为“响应 (response)”或“伪残差 (pseudo residual)”,从名字可以看出是一个与残差接近的概念。直觉上来看,残差
Gradient Boosting算法流程
初始化:
f0(x)=argminγ∑i=1NL(yi,γ) for m=1 to M:
(a) 计算负梯度:
y~i=−∂L(yi,fm−1(xi))∂fm−1(xi),i=1,2⋯N (b) 通过最小化平方误差,用基学习器
hm(x) 拟合yi~ ,wm=argminw∑i=1N[y~i−hm(xi;w)]2 (c) 使用line search确定步长
ρm ,以使L 最小,ρm=argminρ∑i=1NL(yi,fm−1(xi)+ρhm(xi;wm)) (d)
fm(x)=fm−1(x)+ρmhm(x;wm) 输出
fM(x)
回归提升树
在Gradient Boosting框架中,最常用的基学习器是决策树 (一般是CART),二者结合就成了著名的梯度提升树 (Gradient Boosting Decision Tree, GBDT)算法。下面先叙述回归问题,再叙述分类问题。注意GBDT不论是用于回归还是分类,其基学习器 (即单颗决策树) 都是回归树,即使是分类问题也是将最后的预测值映射为概率。
决策树可以看作是一个分段函数,将特征空间划分为多个独立区域,在每个区域预测一个常数,如下图所示:
因此单棵决策树可表示为
即先求出树划分出的区域,而相应的
接下来注意到2.c步中求出的
GBDT回归算法流程
初始化:
f0(x)=argminγ∑i=1NL(yi,γ) for m=1 to M:
(a) 计算负梯度:
y~i=−∂L(yi,fm−1(xi))∂fm−1(xi),i=1,2⋯N (b)
{Rjm}J1=argmin{Rjm}J1∑i=1N[y~i−hm(xi;{Rjm,bjm}J1)]2 (c)
γjm=argminγ∑xi∈RjmL(yi,fm−1(xi)+γ) (d)
fm(x)=fm−1(x)+∑j=1JγjmI(x∈Rjm) 输出
fM(x)
回归问题损失函数的选择
常用的损失函数为平方损失 (squared loss),绝对值损失 (absolute loss),Huber损失 (huber loss),下面给出各自的负梯度 (来自ESL 360页):
分类提升树
将GBDT由回归拓展到分类,关键是损失函数的选择。如果选用了指数损失 (exponential loss),则退化为AdaBoost算法。另一种常用的分类损失函数为logistic loss,形式为
要将其最小化,则对于
可以看到这与指数损失的目标函数一样,都是对数几率,见下图 (来自MLAPP 566页):
区别在于指数损失容易受异常点的影响,不够robust,且只能用于二分类问题。所以像scikit-learn中GradientBoostingClassifier的默认损失函数就是deviance。
与回归提升树的流程类似,求logistic loss的负梯度为:
对于每个区域
上式难以直接求出,因此常用近似值代替:
因为是分类问题,最后输出
正则化 (Regularization)
1、Shrinkage
对每个基学习器乘以一个系数
变为:
一般
2、Early stopping
将数据集划分为训练集和测试集,在训练过程中不断检查在测试集上的表现,如果测试集上的准确率下降到一定阈值之下,则停止训练,选用当前的迭代次数M,这同样是防止过拟合的手段。
3、限制树的复杂度
不加限制完全生成的树同样可能会学的太快导致过拟合,因而通常对其进行预剪枝。常用的方法是限制树的深度(scikit-learn中的max_depth)等。
4、Subsampling
借用bootstrap的思想,每一轮训练时只使用一部分样本,不同点是这里的采样是无放回抽样,这个方法被称为Stochastic Gradient Boosting。对于单棵树来说,只使用一部分样本拟合会增加单棵树的偏差和方差,然而subsampling会使树与树之间的相关性减少,从而降低模型的整体方差,很多时候会提高准确性。
subsampling的另一个好处是因为只使用一部分样本进行训练,所以能显著降低计算开销。
特征重要性
单棵决策树的可解释性很强,GBDT则继承了这个优点。
对于单棵树T,用下式来衡量每个特征
其中
对于M棵树的集成而言,特征重要性就是各棵树相应值的平均:
终末 —— 决策树和GBDT
Gradient Boosting算法理论上可以选择多种不同的学习算法作为基学习器,但实际使用地最多的无疑是决策树,这并非偶然。决策树有很多优良的特性,比如能灵活处理各种类型的数据,包括连续值和离散值;对缺失值不敏感;不需要做特征标准化/归一化;可解释性好等等,但其致命缺点是不稳定,导致容易过拟合,因而很多时候准确率不如其他算法。
决策树是非参数模型,这并不意味着其没有参数,而是在训练之前参数数量是不确定的,因此完全生长的决策树有着较大的自由度,能最大化地拟合训练数据。然而单颗决策树是不稳定的,样本数相同的训练集产生微小变动就能导致最终模型的较大差异,即模型的方差大,泛化性能不好。集成学习的另一代表Bagging是对付这个问题的一大利器 (详见前一篇文章Bagging与方差) 。而Bagging的拓展算法 —— 随机森林,通过在树内部结点的分裂过程中,随机选取固定数量的特征纳入分裂的候选项,这样就进一步降低了单模型之间的相关性,总体模型的方差也比Bagging更低。
另一方面,决策树和Gradient Boosting结合诞生了GBDT,GBDT继承了决策树的诸多优点,同时也改进了其缺点。由于GBDT采用的树都是复杂度低的树,所以方差很小,通过梯度提升的方法集成多个决策树,最终能够很好的解决过拟合的问题。然而Boosting共有的缺点为训练是按顺序的,难以并行,这样在大规模数据上可能导致速度过慢,所幸近年来XGBoost和LightGBM的出现都极大缓解了这个问题,后文详述。
Reference:
Friedman, J. Greedy Function Approximation: A Gradient Boosting Machine
Friedman, J. Stochastic Gradient Boosting
Friedman, J., Hastie, T. and Tibshirani, R. The Elements of Staistical Learning