树算法的思想
提升树利用加法模型和前向分步算法实现学习的优化过程。当损失函数时平方损失和指数损失函数时,每一步的优化很简单,如平方损失函数学习残差回归树。
树算法最重要是寻找最佳的划分点,分类树用纯度来判断最佳划分点使用信息增益(ID3算法),信息增益比(C4.5算法),基尼系数(CART分类树)。但是在回归树中的样本标签是连续数值,可划分点包含了所有特征的所有可取的值。所以再使用熵之类的指标不再合适,取而代之的是平方误差,它能很好的评判拟合程度。
事实上当损失函数时平方损失和指数损失函数时,每一步的优化很简单,可以用前向分步算法,如平方损失函数学习残差回归树。
但是,对于一般的损失函数,往往每一步优化没那么容易,如绝对值损失函数和Huber损失函数。针对这一问题,Freidman提出了梯度提升算法:利用最速下降的近似方法,即利用损失函数的负梯度在当前模型的值,作为回归问题中提升树算法的残差的近似值,拟合一个回归树。
算法思路
1、初始化 f 0 ( x ) f_0(x) f0(x),估计使损失函数极小化的常数值,它是只有一个根节点的树,即 γ \gamma γ是一个常数值。
2、每一轮计算残差损失MSE
(a)计算损失函数的负梯度在当前模型的值,将它作为残差的估计
(b)估计回归树叶节点区域,以拟合残差的近似值
(c)利用线性搜索估计叶节点区域的值,使损失函数极小化
(d)更新回归树
或者 计算当前树模型的负梯度值
3、迭代
f
m
(
x
)
=
f
m
−
1
(
x
)
+
T
(
x
;
θ
m
)
f_m(x) = f_{m-1}(x)+T(x;\theta_m)
fm(x)=fm−1(x)+T(x;θm)
4、输出的
f
M
(
x
)
=
∑
m
=
1
M
T
(
x
;
Θ
m
)
f_{M}(x)=\sum_{m=1}^{M} T\left(x ; \Theta_{m}\right)
fM(x)=∑m=1MT(x;Θm)
GBDT的本质也是Boosting
- 将残差作为下一个弱学习器的训练数据,每个新的弱学习器的建立都是为了使得之前弱学习器的残差往梯度方向减少
- 将弱学习器联合起来,使用累加机制代替平均投票机制
为什么GDBT不能用分类树?
因为GDBT的核心是最小化残差(梯度值),残差是连续值,回归树才有残差的概念,分类树的结果为离散值;
在分类树中最佳划分点的判别标准是熵或者基尼系数,都是用纯度来衡量的,且分类树的分类结果做加法没有实际意义
GBDT整体是串行训练的,但是在每一轮迭代时,有以下几部分可以并行
计算(更新)每个样本的负梯度的时候 (第m-1轮迭代完毕时,第m轮的每个样本的负梯度就可以全部更新)
分裂挑选最佳特征及其分割点时,对特征计算相应的误差及均值*的时候(在拟合残差树时某个节点分类时,求各种可能的分类情况时的增益(基尼系数)是可以并行计算的。(GBDT没有做,xgboost做到了,用一个block结构存储这些特征增益)。但对于拟合一整棵残差树,增益是无法并行计算的,下一个节点的最大增益要在它的父节点生成后才可以求)
最后预测的过程当中,每个样本将之前的所有树的结果累加的时候(因为f(最终) = f(初) + f(残1) + f(残2) + …,一个测试样本最终的预测值等于各个子模型预测结果线性相加。各个子模型对于测试样本的预测是可以同时进行的,最后将各个模型的结果累加就是最终的预测值)
注意:能并行的条件是在计算时数据都是已知,不需要得到以往的数据(这里指上一轮迭代得到的数据)才能进行就算。比如,如果求特征2的增益要知道特征1的增益,那这样增益计算就无法并行了