目录
0x00 前言
0x01 总纲:什么是GBDT
0x02 融会:CART回归树
0x03 融会:最优化方法之梯度下降
0x04 融会:提升树
0x05 贯通:GBDT
5.1 为什么去拟合负梯度?
5.2 GBDT回归算法流程
5.3 GBDT分类算法流程
0x06 贯通:举例子
0xFF 总结
0x00 前言
我们知道集成学习是数据竞赛中的“大杀器”,那么在集成学习领域中,GBDT及其衍生算法则占据了半壁江山。
对于这样重要的算法,我们当然不仅仅满足于去使用它,更要透彻理解其算法细节。本篇文章就从CART回归树、梯度下降与提升树这三个概念出发,将我们之前学习过的旧知识融会贯通,一步一步地透彻理解GBDT算法。不但要知道算法思想是什么,还要知道如何推导。
0x01 总纲:什么是GBDT
到底什么是梯度提升树?所谓的GBDT实际上就是:
GBDT = Gradient Descent + Boosting + Desicion Tree
与Adaboost算法类似,GBDT也是使用了前向分布算法的加法模型。只不过弱学习器限定了只能使用CART回归树模型,同时迭代思路和Adaboost也有所不同。
在Adaboost算法中,我们是利用前一轮迭代弱学习器的误差率来更新训练集的权重。而Gradient Boosting是通过算梯度(gradient)来定位模型的不足。
在GBDT算法中,假设前一轮迭代得到的强学习器是,损失函数是,那么本轮迭代的目标是找到一个CART回归树模型的弱学习器,让本轮的损失函数最小。即本轮迭代找到决策树,要让样本的损失尽量变得更小。
0x02 融会:CART回归树
我们在决策树算法中学习过CART算法。
CART算法既可以解决分类问题,也可以解决回归问题。其原理是根据某一个维度d和某一个阈值v进行二分,且用基尼系数来进行特征划分,并且得到的决策树是二叉树。
这里我们要清楚一个很重要的思想:
回归树本质代表着一个被划分的输入空间和这些划分单元上面各自的输出值。
因此,**一棵回归树能够将一个输出空间划分为m个部分(也就是叶子结点的个数),并且用表示每个部分上面的固定输出值。**即,回归树的模型可以表示为:
其中,回归树中有个叶子节点,表示第个输出空间(叶子节点)上的值,表示当时输出为1,否则为0。
也就是说,确定选择切分特征(在哪个特征上进行选择)切分点(在哪个值上划分集合)由这两者共同决定样本数据集应该以怎么样的方式的来切分。只要知道输入向量属于哪个部分,就能够得到它的值。
CART回归树的的损失函数为最小化平方误差,即:
CART回归树的建树过程是二分裂节点,并且保证分裂的结果符合最小化平方误差,可以遍历所有输入变量,分别计算分裂后两组数据的平方损失(Square Error)。为左节点的平方损失,为右节点的平方损失,找到使平方损失和最小的那个划分节点,即为最佳划分节点。
找出最优切分特征和最优切分点来保证损失函数最小:
在上式中,我们找分裂出的左右子树的区域:
计算所有特征的所有分割点的平方误差,选择最小的进行分裂。分裂完毕以后,要确定每个叶子结点的输出值,其中在区域上的结果为该区域上所有输出的均值:
0x03 融会:最优化方法之梯度下降
在回顾梯度下降时,首先复习一下泰勒公式。泰勒公式是一个用函数在某点的信息描述其附近取值的公式。即符合局部有效性。
其一阶泰勒展开式为:
其迭代形式为,假设,将在处进行泰勒展开为:
梯度下降法常用来求解这种无约束最优化问题:
我们在最小化损失函数时,其中是要求解的模型参数。它是一种迭代方法:选取初值,不断迭代,更新的值,进行损失函数的极小化。其迭代公式为。
这时,我们就可以通过一阶泰勒展开证明负梯度方向是下降最快的方向,即能够找到最小化损失函数的参数。对于损失函数有:
优化损失函数时,要使损失函数极小化,即,因此令,则有:
0x04 融会:提升树
提升树(Boosting Desicion Tree)也是我们所熟悉的,之前学习的AdaBoost就是提升树的一种。
提升树是一个集成算法,训练出多棵CART回归树进行预测。其核心思想为残差拟合。
所谓残差拟合,就是用样本训练出一颗决策树,将样本的特征喂入后的预测值。残差即为预测值与真实值之间的误差。例如,当损失函数为均方损失时,残差为。
提升树为加法模型,其数学表达为:
我们也可以用迭代的方式来表达:
根据前向分布算法,定义其损失函数如下:
此时,我们假设损失函数为均方误差,则每一轮的损失函数如下:
其中,为残差。
在生成第棵决策树时,要用残差作为真实值去做拟合。即使用作为样本输入,去拟合第棵决策树。
0x05 贯通:GBDT
终于说到GBDT了。我们之前说过:
GBDT = Gradient Descent + Boosting + Desicion Tree
5.1 为什么去拟合负梯度?
在网络上,很多文章只是一笔带过说:“GBDT中用负梯度代替残差”。其实这种说法是不对的。
实际上,在GBDT中无论损失函数是什么形式,每个决策树拟合的都是负梯度。不是用负梯度代替残差,而是GBDT使用的CART回归树经常使用平方误差作为划分准则。只有当损失函数是均方损失时,负梯度恰好是残差,这只是特例。
下面我们来看具体的推导过程。
对于前向分布算法而言:
因此,我们定义GBDT的损失函数如下:
其实,GBDT的损失函数求解过程就是梯度下降在函数空间中的优化过程。我们对损失函数进行泰勒展开:
其中,。
因此,在优化时:
所以需要当前的弱学习器去学习负梯度,。
我们发现,GBDT的求解过程就是梯度下降在函数空间中的优化过程。
下面我们将GBDT与上一小节中回顾的梯度下降联系起来,做一个对比:
在上一小节中回顾的梯度下降是在参数空间中优化,每次迭代得到的是参数增量,这个增量就是负梯度乘以学习率。假设迭代了M次,则其优化过程如下:
可以得到累加结果为:
那么在GBDT中,其优化过程如下:
然后进行累加,其结果为:
无论损失函数是什么形式,每个决策树拟合的都是负梯度。准确的说,不是用负梯度代替残差,而是当损失函数是均方损失时,负梯度刚好是残差,残差只是特例。
5.2 GBDT回归算法流程
1、初始化学习器:
2、在第t轮中,计算每个样本的负梯度
3、用拟合得到第棵CART回归树,叶子节点区域划分为。
4、遍历节点区域,计算回归树的每个叶子节点的输出值,即为最佳拟合值:
5、更新学习器:
6、重复2-5直到达到终止条件,累加得到最终的强学习器表达式:
下面给出伪代码:
5.3 GBDT分类算法流程
GBDT的分类算法从思想上和GBDT的回归算法没有区别,但是由于样本输出不是连续的值,而是离散的类别,导致我们无法直接从输出类别去拟合类别输出的误差。
为了解决这个问题,主要有两个方法:
- 用指数损失函数,此时GBDT退化为Adaboost算法。
- 用类似于逻辑回归的对数似然损失函数的方法。也就是说,我们用的是类别的预测概率值和真实概率值的差来拟合损失。
下面我们用对数似然损失函数的GBDT分类。而对于对数似然损失函数,又有二元分类和多元分类的区别。
5.3.1 二元GBDT分类算法
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,二元GBDT分类和GBDT回归算法过程相同。
对于二元GBDT,如果用类似于逻辑回归的对数似然损失函数,则损失函数为:
其中。此时的负梯度误差为:
对于生成的决策树,我们各个叶子结点的最佳负梯度拟合值为:
由于上式比较难优化,我们一般使用近似值代替:
下面给出伪代码:
5.3.2 多元GBDT分类算法
多元GBDT要比二元GBDT复杂一些,对应的是多元逻辑回归和二元逻辑回归的复杂度差别。假设类别数为K,则此时我们的对数似然损失函数为:
其中如果样本输出类别为k,则。第k类的概率的表达式为:
结合上两式,我们可以计算出第t轮的第i个样本对应类别l的负梯度误差为:
观察上式可以看出,其实这里的误差就是样本t对应类别l的真实概率和t−1轮预测概率的差值。
对于生成的决策树,各个叶子节点的最佳负梯度拟合值为:
由于上式比较难优化,我们一般使用近似值代替:
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,多元GBDT分类和二元GBDT分类以及GBDT回归算法过程相同。
下面给出伪代码:
0x06 贯通:举例子
虽然上面的推导过程已经清晰明了了,但是不用一个具体的例子来说明,总觉得差点意思。下面我们就用经典的波士顿房价预测实例,来具体看一下GBDT。
对于如下数据,有4个特征,来预测房屋价格:
首先,我们根据上面的数据,生成一棵CART回归树,切分特征为“每栋住宅房间数”,切分值为6.941,二分裂节点生成树,来预测房价。至于生成回归树的具体过程暂且不表。
为了方便起见,我们假定:残差=真实值-预测值。计算好残差后,用残差代替,生成新的数据。
接着,我们用新数据来生成第二棵回归树,使用房东是否属于低收入阶级这个特征。我们注意到,回归树预测的不再是房屋价格了,预测的是残差:
然后我们计算新的残差,用新残差去替换旧残差,再次生成新数据。
最后我们用第二个新数据生成第三棵回归树。
OK,我们就先做到这里。为了方便起见,我们构建了三棵树桩,实际上我们树的棵树和深度都是可以参数调整的。
这是我们就可以先对数据进行一个预测了。我们分别得到3棵树的结果,然后将结果相加:19.934+2.817-0.566=22.185,即得到预测值。
0xFF 总结
GBDT有很多优点:
- 可以灵活处理连续值和离散值等各种类型的数据
- 可以少做一点特征工程部分
- 能够处理字段缺失的数据
- 能够自动组合多个特征,不用关心特征间是否依赖
- 能够自动处理特征间的交互,处理多种类型的异构数据
- 可以通过选择损失函数,来增强对异常值的鲁棒性,如:Huber损失函数和Quantile损失函数
GBDT也有一些局限性:
- 在高维稀疏数据集上,表现不如神经网络和SVM
- Boosting家族算法,基学习器需要串行训练,只能通过局部并行提高速度(自采样的SGBT)
终于用一篇文章将GBDT算法的原理讲完了。其实从集成学习系列开始,每一篇文章写的都很吃力。在网上学习了大量的视频、博客、文献等等。其实算法的思想并不复杂,但是要吃透其中原理的话,需要有一定的基础。GBDT在很多场景中都有很出色的表现,每一个学机器学习的人都应该掌握包括背后的原理和应用调参方法,这就要求我们在学习时不能不求甚解。