在融合算法家族中,不同于bagging和Averaging算法主要降低子模型的方差,boosting算法主要用来降低偏差(保持方差不变)。GBDT和Xgboost算法是boosting算法中应用比较广泛的两种算法,我们下面就来介绍一下这两种算法。
前向分步算法
GBDT和Xgboost的基本模型都可以归类为前向分布算法,为了后续便于理解,我们首先来看下前向分布算法的机制。
我们知道,融合模型的基本模型 --- 加法模型:
其中为子模型的权重,h为子模型。已知损失函数L(y, f(x)),择我们的问题可以表示为:
该问题的求解辅助度是非常高的,不具有现实意义,为了简化计算,我们采用一种贪心的策略。即在计算每个子模型时,只考虑优化该子模型的参数与权重,来使得当前融合模型的损失函数最小:
我们可以重复以上步骤M次,得到的依然是M个子模型组成的融合模型;不同的是这不一定是一个全局最优的模型,只是计算过程中的每一步都是最优的。
GBDT回归算法原理
在前向分步算法中,这个问题具体该怎么解决呢?假设在前向算法分步算法中,我们已经获得了前 m - 1 个子模型,现在要计算第m个子模型,当前损失函数为:
我们此时可以把看做为Loss函数的自变量,那么
只要以其负梯度的方向移动就可以使损失函数变小:
如果我们以MSE(均方误差)作为损失函数,即 ,则有:
也就是loss关于f_m-1的梯度就是残差。所以,要计算第m个子模型,我们只需要用子模型
去拟合残差就可以了,而我们从算法流程可以看到,若学习器生成的过程,可以等效为损失函数梯度下降的过程。
以上就是GBDT回归的基本原理,但是还有一个问题,hm拟合残差需要用什么样的模型呢?我们知道boosting为减少偏差的融合算法,所以我们一般会选择偏差较大而方差较小的弱模型,在GBDT中,我们采用了以CART树为基础的浅层决策树。
Xgboost算法原理
前面介绍的GBDT利用Loss函数的一阶导数信息来优化(梯度下降法是基于损失函数的一阶导数),一个很自然的想法是利用Loss函数的二阶导数来优化。Xgboost就是这样的一种算法,对于Loss函数的二阶近似可以表示为:
这里,
。为了求得最优的hm,上式对hm求导:
并令其为0,可以获得:
加入正则项的XGboost
当然,Xgboost内部为了防止过拟合,在Loss函数的二阶近似的基础上加入了正则项,以防止过拟合发生:
其中。这里T是hm作为CART树的叶节点数目,同时hm可以表示为:
这里q(x)表示x属于哪个树叶,表示树叶j所代表的值(因为是回归树,样本落入了特定树叶就有了固定的数值)。我们令
为落在叶子
上的样本的集合。则有:
注意到,如果树结构已经确定了,那么上式的变量就只有w而已,且上式为w的一个二次方程,所以我们可以求得w的最优值:
如此,损失函数表示为:
XGboost树结构的确定
那么问题来了,没有固定的树结构无法求取w和loss,树结构如何求取呢?遍历所有树结构显然不可行,一般来说我们确定树结构都要使用贪心策略,而贪心策略的基础就是上面我们提到的由树结构可以完全确定的,不断地对节点进行分叉,直到整体的
不再降低。这里树结构的确定可以分为两个问题:(1) 是否需要分叉(2)怎么选择分叉点 。对于第一个问题,我们只需要查看
前后的大小即可。对于第二个问题,我们知道可以根据式
知道,只需要知道节点内部样本的h值,就可以很方便的计算出loss;一个很自然的想法是用样本的h代替特征值本身来做切分点,因为对h做百分位切分会使得计算简单很多。当然用h来代替原始特征值是有依据的,它可以代表样本在loss中的重要程度(见[1])。
XGboost并行化处理
XGboost并没有在树这个层面上做并行处理,这是boosting算法本身的性质决定的。但是在单一的树生长过程中,我们是可以使用并行化的。在树的生长过程中,最耗时的就是特征值或者h值排序,XGboost将这些排序信息统一存储在了我们称之为block的结构中(分布式系统则是多个block,每个block存储一定量的行的数据),这样可以避免重复排序工作。
参考文献:
[1] XGBoost: A Scalable Tree Boosting System
[2] Gradient Boosting梯度提升-GBDT与XGBoost解析及应用