从提升树到 XGBoost, 原理简介

Posted shiina922

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从提升树到 XGBoost, 原理简介相关的知识,希望对你有一定的参考价值。

提升树 (Boosting Trees)

提升树是以分类树或回归树为基本分类器的提升方法, 模型表示为决策树的加法模型:

\[ F_M(x) = \sum_m=0^M f(x;\Theta_m), \]

其中 \(M\) 为树的个数, \(f(x;\Theta_m)\) 表示决策树, \(\Theta_m\) 为其参数.

1. 提升树算法

提升树算法采用向前分步 (forward stagewise) 算法 (本质上是一种贪心算法). 对于训练数据集 \(D = \(x_i, y_i) \_i=1^N?\), 首先确定初始提升树 \(F_0(x)=0?\), 然后第 \(m?\) 步的模型是

\[ F_m(x) = F_m-1(x) + f(x;\Theta_m), \]

其中 \(F_m-1\) 为当前模型, 通过经验风险最小化确定下一颗决策树的参数,

\[ \hat\Theta_m = \operatorname*argmin_\Theta_m\sum_i=1^N l(y_i, F_m-1(x_i) + f(x_i;\Theta_m)), \]

其中 \(l\) 为损失函数.

回归问题的提升树可以表示为简单函数

\[ f(x;\Theta) = \sum_j=1^T c_j 1_R_j(x), \]

其中 \(R_j\) 互不相交, \(1_R_j(x)\) 为示性函数, \(c_j\) 为常数, 参数 \(\Theta=\(R_j,c_j)\_j=1^T\), \(T\) 为叶节点个数.

综上,

回归问题的提升树算法

  1. 初始化 \(F_0(x) = 0\).
  2. \(m = 1,\dots,M\): (a) 通过经验风险最小化学习一个回归树 \(f(x;\Theta_m)\). (b) 更新 \(F_m(x) = F_m-1(x) + f(x;\Theta_m)\).
  3. 输出回归问题提升树 \(F_M(x) = \sum_m=1^M f(x;\Theta_m)\).

2. 梯度提升树 (Gradient Boosting Decision Trees)

对于一般的损失函数, 每一步经验风险最小化都不容易. GBDT 是为了便于计算而提出的方法, 它的主要想法来自于梯度下降法.

记损失函数的梯度在当前模型的值为

\[ g_im = \left(\frac\partial l(y_i,F(x_i))\partial F(x_i)\right)_F = F_m-1. \]

则由梯度下降法,

\[ F_m(x_i) = F_m-1(x_i) -\rho_m g_im, \]

其中步长 \(\rho_m\) 可以通过线搜索获得, 即

\[ \rho_m = \operatorname*argmin_\rho \sum_i=1^Nl(y_i, F_m-1(x_i)-\rho g_im). \]

梯度下降法是一个很贪心的算法, 即在当前点取函数下降最快的方向. 但如上这样做的话我们只获得了在训练数据点上的预测, 为了得到可以预测新数据的决策树, 一种可行的做法是, 用 \(f\) 逼近负梯度方向, ESL [2] p. 321 使用了平方误差来度量 \(f\) 与负梯度的距离, 即

\[ \tilde\Theta_m = \operatorname*argmin_\Theta\sum_i=1^N (-g_im - f(x_i;\Theta))^2. \]

注意到对于 \(l(x,y) = \frac12(x-y)^2\) 的情形, \(\tilde\Theta_m\)\(\hat\Theta_m\) 相等.

其余操作同提升树算法, 从略.

3. XGBoost

3.1. 总体框架

XGBoost 的主要想法是, 除了原有的损失函数, 在目标函数中加入正则项, 利用二阶 Taylor 近似代替目标函数再求极值 (回忆之前的梯度提升树只用了一阶导数), 其余操作同提升树算法.

\(F_m(x_i) = \hat y_i^(m)\),
\(\hat y_i^(0)=0\),
\(\hat y_i^(m) = \hat y_i^(m-1) + f_m(x_i)\), \(m=1,\dots,M\).

\(f_m\) 表示第 \(m\) 轮时所得的树, 是由最小化目标函数而得; \(\hat y_i^(m)\) 表示第 \(m\) 轮时 \(y_i\) 的预测值.

\(m\) 轮目标函数为

\[ \mathrmObj^(m) = \sum_i=1^N l\left(y_i, \hat y_i^(m-1) + f_m(x_i)\right) + \Omega(f_m), \]

其中 \(l\) 为损失函数; \(\Omega\) 为正则项, 是人为定义的复杂度, 可以降低模型复杂度, 减小过拟合的风险, 在原论文 [3] 中定义为

\[ \Omega(f) = \gamma T + \frac12 \lambda\sum_j=1^T w_j^2, \]

其中 \(\gamma\), \(\lambda\) 为参数, \(T\)\(f\) 表示的数的叶节点数, \(w_j\) 为第 \(j\) 个叶节点的预测值 (权重).

除了加入正则项外, 还可以通过 shrinkage 来降低过拟合风险, 即 \(F_m = F_m-1 + \nu f_m\), 其中 \(0<\nu<1\), 可以看为学习率, 原来的做法相当于取 \(\nu=1\). 这么做主要的理由是减少每颗树对总模型的影响, 防止前几颗树拟合地太好 (过拟合) 以至于后面的树没有了学习空间.

3.2. 寻找分裂点

对目标函数做二阶 Taylor 展开, 略去更高阶的无穷小量. 记

\[ g_i = \frac\partial l(y_i, \hat y_i^(m-1))\partial\hat y^(m-1),\quad h_i = \frac\partial^2 l(y_i, \hat y_i^(m-1))\partial\left(\hat y^(m-1)\right)^2. \]

例如对于平方损失函数 \((y_i - \hat y_i^(m-1))^2\) 来说, \(g_i = 2(\hat y_i^(m-1) - y_i)\), \(h_i = 2\).

经过简单的推导可得最优权重为

\[ w_j^* = -\frac\sum_i\in I_jg_i\sum_i\in I_j h_i + \lambda, \]

其中 \(I_j\) 表示被归到第 \(j\) 个叶节点的全体实例 (的脚标) 集合.

一般而言, 穷举所有可能的树结构是不可能的, 作为代替, 我们考虑贪心算法. 从一个叶节点开始二分, 假设 \(I_L\)\(I_R\) 分别表示分裂后归为左节点和右节点的实例集合, 记 \(I = I_L \cup I_R\), 则易得分裂后的目标函数减少值 (loss reduction) 为

\[ \frac12\left[\frac(\sum_i\in I_Lg_i)^2\sum_i\in I_L h_i + \lambda + \frac(\sum_i\in I_Rg_i)^2\sum_i\in I_R h_i + \lambda - \frac(\sum_i\in Ig_i)^2\sum_i\in I h_i + \lambda\right] - \gamma \]

把上式第一项视为 gain, 则 \(\gamma\) 相当于设置了分裂所需的最小的 gain, 起到了剪枝的作用.

寻找分裂点的精确贪心算法 (原文 [3] 中本段有一些 typo)
输入: \(I\), 当前节点的实例集; \(d\), 特征维数 (个数).
初始化 \(\mathrmgain \leftarrow 0\)
\(G \leftarrow \sum_i\in Ig_i\), \(H \leftarrow \sum_i\in Ih_i\)
for \(k=1\) to \(d\) do
???? \(G_L \leftarrow 0\), \(H_L \leftarrow 0\)
???? for \(j\) in sorted (\(I\), by \(x_jk\)) do
???????? \(G_L\leftarrow G_L + g_j\), \(H_L\leftarrow H_L + h_j\)
???????? \(G_R \leftarrow G-G_L\), \(H_R \leftarrow H- H_L\)
???????? \(\mathrmgain \leftarrow \max(\mathrmgain, \fracG_L^2H_L + \lambda + \fracG_R^2H_R + \lambda - \fracG^2H + \lambda)\)
输出: 最大 gain 的分裂

精确贪心法是在所有特征上, 对所有可能的分裂点都进行遍历, 在数据量大的时候是不现实的. 一个简单的近似方法是, 排序后 (for \(j\) in sorted (\(I\), by \(x_jk\)) 那步), 取适当的分位数作为分裂候选点进行贪心算法.

3.3. 稀疏数据的分裂点寻找 (sparsity-aware)

主要分为两种情况:

  1. 若数据有缺失值, 则把缺失值都归到同一个节点. 这是处理缺失值的常用方法之一 (另一种常用方法是用适当的方法填补缺失值), 这使得 XGB 可以直接训练和预测带有缺失值的数据.
  2. 若数据稀疏 (比如 one-hot 编码, 使得数据包含大量的 0), 则把 0 当做缺失值处理. 这个做法的关键点在于遍历时只对非缺失 (非零) 数据遍历, 在稀疏数据的情况下会大大提高训练速率.

注: 按照原论文 [3] 的说法, 作者似乎把缺失和稀疏时的 0 都统称为 "稀疏/缺失", 用同样的方式处理, [5] 也证实了这一点.

技术图片

图中 \(m\) 应该为 \(d\), score 应该为 gain.

3.4. XGB 的优点

XGB 把决策树的许多启发式的想法通过最小化目标函数统一起来处理. 除了使用近似算法, 在系统设计上, 通过并行处理, 优化缓存等工程层面上的优化大幅提高了运行速度, 减小了内存使用.

References

[1] 李航. (2012). 统计学习方法 (pp. 55-74, 137-153). 北京: 清华大学出版社.
[2] Friedman, J., Hastie, T., & Tibshirani, R. (2001). The elements of statistical learning (pp. 299-344). New York: Springer series in statistics.
[3] Chen, T., & Guestrin, C. (2016). Xgboost: A scalable tree boosting system. Proceedings of the 22nd acm sigkdd international conference on knowledge discovery and data mining (pp. 785-794). ACM.
[4] Introduction to Boosted Trees. (n.d.). Retrieved from https://xgboost.readthedocs.io/en/latest/tutorials/model.html#
[5] Kodi Arfer. XGBoost, missing values, and sparsity. (2018). Retrieved from http://arfer.net/w/xgboost-sparsity

以上是关于从提升树到 XGBoost, 原理简介的主要内容,如果未能解决你的问题,请参考以下文章

推荐算法与量化交易-A-5-5:XGBoost-lightGBM“集成提升树模型”算法-基于模型算法

XGBoost 极限提升树 (Extreme Gradient Boosting)

深度 | 对比TensorFlow提升树与XGBoost:我们该使用怎样的梯度提升方法

Matlab基于极端梯度提升XGBoost实现分类预测(Excel可直接替换数据)

GBDT与XGBoost

机器学习之路: python 实践 提升树 XGBoost 分类器