集成学习是机器学习的一种重要方法,集成学习中常用的思想主要是Bagging、Boosting、Stacking等,其中bagging思想最主要的代表就是随机森林算法,而boosting方法中最常见的代表是AdaBoost、GBDT、XGboost等,Boosting思想是通过串行多个弱学习器来构建强学习器模型,核心思想是通过不断迭代,将多个弱学习器的预测结果进行加权组合,从而产生一个更准去且泛化能力更强的模型,同时在这里提一下Bagging方法是并行将多个弱学习器组合来构建模型。在讲解GBDT提升树算法之前,我们先讲一下Gradient Boosting(梯度提升)思想,Gradient Boosting是将真实值与预测值之间的差异(也就是残差)作为弱学习器优化的目标。损失函数代表了模型对数据的拟合程度,如果说损失函数越小,代表模型对数据的拟合越小,通过多个弱学习对残差的优化,使损失函数不断下降,从而提高模型的性能。
梯度提升算法流程如下:
梯度提升算法是梯度提升树基础,所以在讲解梯度提升树算法之前,我们先对梯度提升算法做一个了解,这样当后面子模型变换成树模型之后,大家才不会陌生,在讲解梯度提升算法之前,我们先做一下基础理论知识的铺垫,第一、梯度的知识,多元函数对每个参数求偏导,然后讲各个参数的偏导数组合成一个向量,这个向量就是偏导,几何意义是函数值增加最快的方向,例如;第二、梯度下降,优化模型的目标是最小化损失函数,梯度提升算法就是通过梯度下降的方式解决最小化损失函数的问题,即沿着负梯度方向一步一步接近最小值。以上就是我们做的一些基础知识储备,接下来我们将来讲解梯度提升算法。
我们首先初始化了一个算法模型,模型的公式如图中所示,代表我们使用了一个常数来使得真实值和常数之间的误差平方和最小,大家如果对之前的决策树内容有过学习应该知道,这个常数的取值是所有真实值的均值,也就是说我们在初始的预测中预测所有的样本观测值为真实值的均值。这样的结果只是说明预测值在总体上和真实值误差最小,但是从单个样本的角度来说,某些样本的统一均值的预测其实是与真实值差距较大的,因此我们需要一步一步向着梯度最小的方向去不断接近真实值。
接下来,我们进行了M轮的训练,分别对n个特征求偏导,得到一组梯度向量,在得到梯度向量之后,我们还需要一个沿着梯度向量走的步长,这个步长怎么计算呢?就是通过第二步中的三式,该式子的含义是选择一个使得真实值与(上一个模型预测值加上沿着梯度方向变化值的和)也就是这一轮沿着梯度方向下降之后的结果与真实值的平方误差最小的步长,后面会给大家一个事例展示,同时大家如果对损失函数求偏导可以得到,负的损失函数的偏导就是真实值与预测值的“残差”,因此,大家可以理解,后续子模型h(x)是对真实值和预测值之间“残差”不断优化调整,使得预测值和真实值不断逼近。
对于梯度下降逼近我们可以使用一个简单案例进行展示
大家可以从这张图中看到,我们假设损失函数,损失函数最小的点是在(-1,0),但是我们目前是在(1,4)的位置,因此我们需要沿着梯度下降的方向不断逼近最小值,首先,我们对损失函数进行了求导,这代表了梯度,紧接着我们进行了下降之后的值更新,在原来值的基础上加上轮一个负的梯度方向4*
,这里
代表步长,我们怎么求得这个步长呢?选择的是使得所有真实值和我们新一轮真实值损失函数最小的步长
,大家看完这一段之后载回头看梯度提升算法应该会比较容易理解。
为了使得模型能够更精确地逼近最优结果,同时为了防止模型出现过拟合的倾向,提升模型的泛化能力,我们通常不会让模型下降太快,因此通常会在步长前面乘以一个学习率,减少模型在每轮梯度下降的步长:
在讲解完梯度提升算法之后,接下来给大家讲解我们经常使用的梯度提升树算法GBDT,GBDT算法是在前面梯度提升算法的基础上将优化残差的子模型采用Cart模型来进行优化,GBDT算法的流程如下:
和梯度提升模型一样,我们首先初始化一个模型,该模型的预测值是所有真实值的均值,然后,我们开始M轮模型的迭代更新,在每一轮子模型构建中,我们采用决策树模型来进行构建,通过决策树模型来不断拟合上一轮中真实值和预测值之间的“残差”,通过决策树子模型,我们可以利用数据的特征将数据划分到不同的叶子结点,再分别计算不同叶子结点中使得损失函数最小化的步长,计算完之后,新的模型就变成了原模型基础上加上一个使得残差不断减小的决策树子模型的结合,我们接下来将会使用实际案例进行展示。
Holiday_Flag | Temperature | Fuel_Price | CPI | Unemployment | Weekly_Sales |
0 | 42.31 | 2.572 | 211.0963582 | 8.106 | 1643690.9 |
1 | 38.51 | 2.548 | 211.2421698 | 8.106 | 1641957.44 |
0 | 39.93 | 2.514 | 211.2891429 | 8.106 | 1611968.17 |
假设我们现在有三条关于销售额的数据,前五列代表会影响销售额的诸多因素,即数据特征,最后一列代表实际的销售额,接下来,我们将会使用这部分数据来模型提升树算法的流程,算法的第一步是初始化模型,模型的初始化是采用与所有真实值残差平方和最小的常数,易知该常数是所有真实值的均值,即(1643690.9+1641957.44+1611968.17) /3 = 1632538.837,这是第一次预测的结果。
Holiday_Flag | Temperature | Fuel_Price | CPI | Unemployment | Weekly_Sales | first_prediction |
0 | 42.31 | 2.572 | 211.0963582 | 8.106 | 1643690.9 | 1632538.837 |
1 | 38.51 | 2.548 | 211.2421698 | 8.106 | 1641957.44 | 1632538.837 |
0 | 39.93 | 2.514 | 211.2891429 | 8.106 | 1611968.17 | 1632538.837 |
那么,根据第一次的预测值与真实值之间的残差是多少呢?结果如下:
Holiday | Tem | Fuel | CPI | Unemploy | Weekly_Sales | first_prediction | first_residual |
0 | 42.31 | 2.572 | 211.0963582 | 8.106 | 1643690.9 | 1632538.837 | 11152.06333 |
1 | 38.51 | 2.548 | 211.2421698 | 8.106 | 1641957.44 | 1632538.837 | 9418.603333 |
0 | 39.93 | 2.514 | 211.2891429 | 8.106 | 1611968.17 | 1632538.837 | -20570.66667 |
大家可以看见预测值与真实值之间还是有比较大的差距,因此我们接下来将使用决策树对残差进行优化,使得预测值更加逼近真实值,我们假设从Fuel_Price特征开始构建决策树,也就是从Fuel_Price特征将数据进行划分,假设决策时以Fuel_Price特征对2.53为划分标准,将不同数据按照该标准划分到不同的叶子结点,分别计算不同叶子结点预测的残差,决策树子模型对不同叶子结点的残差预测如下,展示如下:
以上是经过 Fuel_Price特征对数据经过划分之后,所得出的使得不同叶子结点损失最小的残差,大家可能会比较好奇是怎么来的,计算公式如下,该公式表示经过决策树划分之后,使得决策树各个叶子结点真实值与(上一轮预测值+决策树对残差预测值)的残差平方和最小的残差预测值。
例如,在第一轮预测中为,我们预测所有的数据都是均值,按照特征 Fuel_Price进行划分之后,第三条数据被划分到了左边,前两条数据被划分到了右边,对于左边叶子结点决策树的预测值为:
右边叶子结点决策树的预测值为:
,其中
字母第一个下标代表第几个叶子结点,后一个下标代表第几个决策树子模型,非常容易得到左边叶子结点的预测值为
,右边叶子结点的预测值为
,该值是通过不同叶子结点数据残差的均值求得,对于子模型决策树构建之后的预测结构如下:
通常我们为了保证模型的鲁棒性、准确率、泛化能力等,我们会设置一个学习率,防止模型出现过拟合,假设我们设置学习率为0.1,第一条数据的预测结果为1632538.837+(0.1*10285.3333)=1633567.37,第二条数据预测结果为1632538.837+(0.1*10285.3333)=1633567.37,第三条数据预测结果为1632538.837+(0.1*-20570.66667)=1630481.77那么第二次的预测结果如下:
Sales | first_pred | first_res | second_pred |
1643690.9 | 1632538.837 | 11152.06333 | 1633567.37 |
1641957.44 | 1632538.837 | 9418.603333 | 1633567.37 |
1611968.17 | 1632538.837 | -20570.66667 | 1630481.77 |
大家可以看出,对于第二次的预测与真实值结果更加接近,后面树的构建依次类推,最终梯度提升树的结构类似于以下结构: