机器学习笔记(13)-XGBoost

机器学习笔记(13)-XGBoost

XGBoost陈天奇等人开发的一个开源机器学习项目,高效地实现了GBDT算法并进行了算法和工程上的许多改进,被广泛应用在Kaggle竞赛及其他许多机器学习竞赛中并取得了不错的成绩。可以说在深度学习热门前和当年SVM一样属于比赛中的明星算法了。

Bagging和Boosting

介绍XGBoost之前,首先简单介绍下Bagging和Boosting的区别,我们知道这两个都是集成学习的框架,主要针对一系列弱分类器,使它们在集成后成为一个效果比较好的强分类器。比如随机森林就是一个采用bagging的学习算法,而我们这次介绍的XGBoost就是一个Boosting算法。

Bagging:是由多个过拟合的弱分类器组合而成,通过每个弱分类器的权重来判断结果。通俗的理解就是Bagging算法是由多个领域专家(弱分类器)组成,单个专家只在该领域(数据分布)下时预测准确率高,当符合某个领域时,会挑选出该领域的专家(权重最高)来判断(加权组合)。

Boosting:与Bagging相同的时它也是由多个弱分类器组成,不同点在于每个弱分类器都是欠拟合的,同样是协同所有弱分类器一起判断结果。

XGBoost顾名思义,采用的是Boosting的思想,训练多棵树模型,来组合判断结果,但是不同于随机森林,它的每一个分类器采用残差的方式来训练每棵树,使得每棵树的结果之和为预测结果,并且在每棵树的建立算法上也和传统的决策树分枝算法(C4.5)不同。

举个例子就是,比如有一个预测样本的值为10:

  1. 训练第一个弱分类器预测的结果为6,得到残差为:10-6=4;
  2. 接下来训练第二个弱分类器预测的结果为2,得到残差为:4-2=2;
  3. 再训练第三个弱分类器预测的结果为1,得到残差为:2-1=1;
  4. 最后训练第四个弱分类器预测的结果为1;
  5. 我们把四个弱分类器的预测结果累加就是我们真实的预测值10。

这就是XGBoost利用Boosting算法来集成的强学习器。

XGBoost算法推导

上一节讲了XGBoost采用了Boosting通过残差的方式来求和拟合结果。XGBoost的每个弱分类器都是一棵决策树,分枝算法先放到之后再说,通过训练一棵树来预测结果,得到残差后再训练第二棵树,依此类推,训练若干个弱分类器后,模型收敛完成训练。

这就是XGBoost的算法思想,真的非常简单,下面我们来推导过程。

残差损失

之前说了XGBoost是根据每棵树的预测结果和样本真实值的残差来迭代优化的,假设有:

  1. 数据样本\(X=\{(x_{1},y_{1}),(x_{2},y_{2}),\cdots,(x_{n},y_{n})\}^N\),其中\(x_{i}\in\mathbb{R}^p,y_{i}\in\mathbb{R}\)
  2. 模型总共需要构建K棵树,每棵树预测值表示为:\(f_{k}(x_{i})\)

于是我们得到单个样本的预测值为:

\[\hat y_{i}=\sum_{k=1}^{K}f_{k}(x_{i}) \]

那么我们就可以进一步得到目标函数:

\[Obj=\sum_{i=1}^{N}\mathcal{L}(y_{i},\hat y_{i})+\sum_{k=1}^{K}\Omega(f_{k}) \]

其中\(\mathcal{L}(y_{i},\hat y_{i})\)为样本真实值和预测值的损失函数,\(\Omega(f_{k})\)为每棵树的复杂度(可以理解为正则项)。

事实上,对于一棵树,复杂度一般采用以下几项来表示:

  1. 树的深度
  2. 叶节点个数
  3. 叶节点值

树的深度很好理解,树越深表示节点越多,也就是复杂度越高,越容易过拟合;

叶节点个数和深度表示的含义基本一样;

叶节点值表示如果我的预测值是100,原来每棵树叶节点值为50,那么我用两棵树就可以完成,当我们设置每棵树的叶节点值不超过10,那么我们至少需要10棵树才能拟合真实值。而树越多,越不容易过拟合。

训练第k棵树

有了目标函数后,我们需要进一步来简化问题,XGBoost是根据我们每次预测值和真实值的残差来提升模型的,也就是假设我们已知前k-1棵树后,我们通过模型迭代训练来得到第k棵树,依次把所有k棵树全部训练完成的。

于是我们令:

  1. 第0棵树\(\hat y^{(0)}_{i}=0\)
  2. 第1棵树\(\hat y^{(1)}_{i}=f_{1}(x_{i})=\hat y^{(0)}_{i}+f_{1}(x_{i})\)
  3. 第2棵树\(\hat y^{(2)}_{i}=f_{1}(x_{i})+f_{2}(x_{i})=\hat y^{(1)}_{i}+f_{2}(x_{i})\)
  4. 第k棵树\(\hat y^{(k)}_{i}=\sum_{k=1}^{K}f_{k}(x_{i})=\hat y^{(k-1)}_{i}+f_{k}(x_{i})\)

我们把结论代入到目标函数中,就得到:

\[\begin{aligned} Obj&=\sum_{i=1}^{N}\mathcal{L}(y_{i},\hat y_{i})+\sum_{k=1}^{K}\Omega(f_{k})\\ &=\sum_{i=1}^{N}\mathcal{L}(y_{i},\hat y^{(k-1)}_{i}+f_{k}(x_{i}))+\sum_{j=1}^{K-1}\Omega(f_{j})+\Omega(f_{k}) \end{aligned} \]

观察上式,我们因为已知前k-1棵树,求第k棵树,所以前k-1棵树的项都应该是已知常数,我们令:

  1. \(\hat y^{(k-1)}_{i}=C_{1}\)
  2. \(\sum_{j=1}^{K-1}\Omega(f_{j})=C_{2}\)

得到:

\[Obj=\sum_{i=1}^{N}\mathcal{L}(y_{i},C_{1}+f_{k}(x_{i}))+C_{2}+\Omega(f_{k}) \]

泰勒级数

大学高等数学课中,我们知道当一个函数为连续函数时(函数处处可导),我们可以采用泰勒展开式近似该函数,XGBoost正是采用了泰勒展开式中的二阶导数来近似表示函数的。引用下百度百科:

事实上当到二阶导数时,已经非常接近原函数了。于是有二阶泰勒展开式(Taylor Expansion)近似:

\[f(x+\Delta x)=f(x)+f'(x)\cdot \Delta x+\frac{1}{2}f''(x)\cdot \Delta x^2 \]

XGBoost利用了该思想,它把前k-1棵树预测的值看成时\(f(x)\),加上第k棵树预测的值看成\(f(x+\Delta x)\)

也就是:

\[\hat y^{(k-1)}_{i}=C_{1}\rightarrow f(x)\\ f_{k}(x)\rightarrow \Delta x \]

代入到目标函数也就是:

\[\begin{aligned} Obj &=\sum_{i=1}^{N}\mathcal{L}(y_{i},C_{1}+f_{k}(x_{i}))+C_{2}+\Omega(f_{k})\\ &=\sum_{i=1}^{N}[\mathcal{L}(y_{i},C_{1})+\frac{\partial \mathcal{L}(y_{i},C_{1})}{\partial \hat y^{(k-1)}_{i}}f_{k}(x_{i})+\frac{\partial^2 \mathcal{L}(y_{i},C_{1})}{\partial \hat y^{(k-1)}_{i}}\cdot \frac{1}{2}\cdot f^2_{k}(x_{i})]+C_{2}+\Omega(f_{k}) \end{aligned} \]

上式同样有几个已知常数项,我们简化一下令:

\[l_{i}=\mathcal{L}(y_{i},C_{1})\\ g_{i}=\frac{\partial \mathcal{L}(y_{i},C_{1})}{\partial \hat y^{(k-1)}_{i}}\\ h_{i}=\frac{\partial^2 \mathcal{L}(y_{i},C_{1})}{\partial \hat y^{(k-1)}_{i}}\cdot \frac{1}{2} \]

目标函数再次简化形式:

\[Obj=\sum_{i=1}^{N}[l_{i}+g_{i}f_{k}(x_{i})+h_{i}f^2_{k}(x_{i})]+C_{2}+\Omega(f_{k}) \]

上式目标函数,我们要令该函数的值最小,只保留和\(f_{k}\)有关的项,求得:\(argmin\;Obj\)

\[argmin\;Obj=argmin\;\sum_{i=1}^{N}[g_{i}f_{k}(x_{i})+h_{i}f^2_{k}(x_{i})]+\Omega(f_{k}) \]

定义树的表示

下面我们要想一个办法来表示我们的\(f_{k}(x_{i})\)\(\Omega(f_{k})\),最好可以用一种统一的参数形式来表示。

现在考虑在一棵树中,我们尝试使用样本在树中的叶节点位置叶节点的值来定义\(f_{k}(x_{i})\)\(\Omega(f_{k})\)

我们令:

  1. \(I\):叶节点总个数
  2. \(q_{x_{i}}\):每个样本\(x_{i}\)在树中的位置为
  3. \(W_{q_{x_{i}}}\):每个样本在叶节点上的值
  4. \(\gamma T\):其中\(T\)表示树的高度,\(\gamma\)是超参数,用于调节高度的权重

先来看复杂度项\(\Omega(f_{k})\),我们采用树的高度加上叶节点的值作为复杂度项,就有:

\[\Omega(f_{k})=\gamma T+\lambda\sum_{i=1}^{I}\frac{1}{2}W^2_{i} \]

其中\(\lambda\)是叶节点的值的超参数,同样用于控制权重。定义每个叶节点的值的平方作为复杂度项。

再来看树的预测函数\(f_{k}(x_{i})\)

\[f_{k}(x_{i})=W_{q_{x_{i}}} \]

我们这么幸苦地采用这个形式来改变形式,其实核心思想就是原本目标函数是通过数据样本的个数来表示的,我们现在想采用数的叶节点个数来表示目标函数,其中多个数据样本可能落在同一个叶子节点上。

也就是说:所有的N个数据样本分布在\(I\)个叶节点上,每个叶节点中假设有M个样本,即:

\[\sum_{i=1}^{N}g_{i}W_{q_{x_{i}}}=\sum_{j=1}^{I}(\sum_{m=1}^{M}g_{m})W_{j}\\ \sum_{i=1}^{N}h_{i}W^2_{q_{x_{i}}}=\sum_{j=1}^{I}(\sum_{m=1}^{M}h_{m})W^2_{j} \]

代入到目标函数中得到:

\[\begin{aligned} argmin\;Obj &=argmin\;\sum_{i=1}^{N}[g_{i}f_{k}(x_{i})+h_{i}f^2_{k}(x_{i})]+\Omega(f_{k})\\ &=\underset{W}{argmin}\;\sum_{j=1}^{I}[(\sum_{i=1}^{M}g_{i})W_{j}+(\sum_{i=1}^{M}h_{i})W^2_{j}]+\gamma T+\lambda\sum_{i=1}^{I}\frac{1}{2}W^2_{i}\\ &=\underset{W}{argmin}\;\sum_{j=1}^{I}[(\sum_{i=1}^{M}g_{i})W_{j}+(\sum_{i=1}^{M}h_{i}+\frac{1}{2}\lambda)W^2_{j}]+\gamma T \end{aligned} \]

我们再把常数项简化表示,令:

\[\sum_{i=1}^{M}g_{i}=G\\ \sum_{i=1}^{M}h_{i}=\frac{1}{2}H \]

代入得:

\[argmin\;Obj=\underset{W}{argmin}\;\sum_{j=1}^{I}[G_{j}W_{j}+\frac{1}{2}(H_{j}+\lambda)W^2_{j}]+\gamma T \]

\(W\)求导得:

\[\sum_{j=1}^{I}[G_{j}+(H_{j}+\lambda)W_{j}]=0 \]

\[W_{j}^*=-\frac{G_{j}}{H_{j}+\lambda} \]

把最优解代入目标函数得到:

\[Obj^*=\sum_{j=1}^{I}-\frac{G^2_{j}}{H_{j}+\lambda}+\gamma T \]

这里我们就得到了我们要得最小化目标函数值最优解。

每棵树得构建

前面我们其实是得到了一个结论:当我们已知前k-1棵树预测值时,可以很方便地计算出第k棵树预测值。现在来思考每棵树的构建方式。

前面的章节我已经介绍过决策树的构建流程,依赖于分枝算法,我们以信息增益(ID3)为例回顾下流程:

\[Gain(D,a)=Ent(D)-\sum_{V=1}^{V}\frac{|D^v|}{|D|}Ent(D^v) \]

通过原来的信息熵减去分枝后的熵就是信息增益,我们需要求它的最大值作为分枝点。XGBoost也是这个思想,不过采用的不是信息增益,而是我们之前的目标函数\(Obj^*\)最优解。

假设数据集为

  1. 数据集\(D=\{(x_{1},y_{1}),(x_{2},y_{2}),\cdots,(x_{n},y_{n})\}\)
  2. 属性集A=\(\{a_{1},a_{2},\cdots,a_{p}\}\)其中每个数据样本\(x_{i}\)有p个属性

\[a^*=\underset{a\in A}{argmax}\;Obj^*_{old}-Obj^*_{new} \]

构造流程和决策树一样,只是分枝算法进行了替换。

总结

可以看到XGBoost算法主要依赖:

  1. 利用Boost残差的思想构造多个若分类器逐步迭代优化来逐渐逼近目标值;
  2. 采用泰勒二阶展开式来近似弱分类器;
  3. 利用已知前k-1棵树,可以计算第k棵树的思想,作为树的分枝算法来建树。

最后说一下如果是分类问题的话,那么拟合的就是概率值,也就是要把预测值和真实值转换为类别的概率,迭代过程就是让预测概率不断接近真实概率。\(\mathcal{L}(y_{i},\hat y_{i})\)转化为对数损失函数来做,回归就采用最小二乘。

posted @ 2020-07-04 02:28  Epir  阅读(277)  评论(0编辑  收藏  举报