Boosting 推导
<< python 机器学习基础教程>>:第二章——监督学习算法。介绍了梯度提升决策树(GBDT)。
<< sklearn 与 tf 机器学习实用指南>>:第七章——集成学习。介绍了适应性增强(Adaboost)和 GBDT。
<< python 机器学习经典实例>>:第一章——监督学习。介绍了 Adaboost。
<<统计学习方法>>:第八章——提升方法。介绍了 Adaboost 和 GBDT。
<<机器学习>>:第八章——集成学习。介绍了 Adaboost。
<<深度学习>>:第七章——深度学习中的正则化。介绍了 Dropout Boosting 的方法。
迭代过程
机器学习 -> 统计学习方法 -> 实践补充
理论基础
名词解释
集成学习:通过构建并结合多个学习器来完成学习任务。
同质 homogeneous:决策树集成中全是决策树,神经网络集成中全是神经网络。
基学习器 base learner:同质集成中的个体学习器。
基学习算法 base learning algorithm:基学习器所使用的学习算法。
异质 heterogenous:集成包含不同类型的个体学习器。
组件学习器 component learner:和基学习器对应,它们统称为个体学习器。
集成学习的可行性证明
假设二分类问题 $y \in \{ - 1 , + 1 \}$ 和真实函数 $f$ ,假定基分类器的错误率是 $\epsilon$ ,即对每个基分类器 $h_{i}$ 有:
假设集成通过投票结合 $T$ 个基分类器,若有超过半数的基分类器正确,则集成分类就正确:
根据 Hoeffding 不等式,得到集成后的错误率:
$P ( H ( n ) \leqslant k )$ 是另一种写法,含义相同。
由这条表达式,我们有:
第一个等号表示 $n$ 个基学习器中分类正确的个数小于 $k$ 的概率。若假定集成通过简单投票法结合 $n$ 个分类器,超过半数的基学习器正确,则集成分类就正确,即临界值 $k=0.5*n=(1−ϵ−\delta)n$ 。
第二个等号的 Hoeffding 不等式的定义,$δ > 0$ :
其中 $\left( \begin{array} { l } { T } \\ { k } \end{array} \right)$ 表示 $C_{T} ^{k}$ ,$\delta = 0.5-\epsilon$ 。
Ps: n 和 T 等价。
当 $\epsilon >=0.5$ 时,上式不成立。随着集成中个体分类器数目 $T$ 的增大,集成的错误率将指数级下降,最终趋向于零。
在现实中,个体学习器是解决同一个问题训练出来的,它们不可能相互独立,如何生成不同的个体学习器,是集成学习研究的核心。
根据个体学习器的生成方式,目前集成学习方法大致分为两大类:个体学习期之间存在强依赖关系、必须串行生成的序列化方法—— Boosting;个体学习器之间不能存在强依赖关系、可同时生成的并行化方法—— Bagging。
Boosting
先从初始训练集训练出一个基学习器,再根据基学习器的表现对训练样本进行调整,使得先前基学习器出错的训练样本在后续受到更多关注,然后基于调整后的样本分布来训练下一个基学习器。
AdaBoost
只适用二分类任务,比较容易理解的是基于“加性模型” additive model ,即基学习器的线性组合:
最小化指数损失函数:
$f(x)$ 只有两个结果,1 或 -1 :
若 $H(x)$ 可以将损失函数最小化,那么对它求偏导:
显然,令上式为0,可以解出:
因此:
我们发现,因为本身是二分类问题,特性非常优秀,指数损失函数最小化,则分类错误率也将最小,即达到了贝叶斯最优错误率。
因为我们的基分类器前面还有参数,当基分类器得到以后,该基分类器的权重 $a_{t}$ 应该使得 $a_{t}h_{t}$ 最小化指数损失函数:
其中 $\epsilon _ { t } = P _ { x \sim \mathcal { D } _ { t } } \left( h _ { t } ( \boldsymbol { x } ) \neq f ( \boldsymbol { x } ) \right)$ ,考虑指数损失函数的导数:
上式为0,可以得到权重更新公式:
AdaBoost 算法在下一轮基学习中纠正错误,那么:
它可以进行泰勒展开,同时注意到 $f ^ { 2 } ( x ) = h _ { t } ^ { 2 } ( x ) = 1$ :
理想的基学习器:
因为 $\mathbb { E } _ { \boldsymbol { x } \sim \mathcal { D } } \left[ e ^ { - f ( \boldsymbol { x } ) H _ { t - 1 } ( \boldsymbol { x } ) } \right]$ 是一个常数,令 $\mathcal { D } _ { t }$ 表示一个分布:
这等价于令:
由于 $f ( x ) , h ( x ) \in \{ - 1 , + 1 \}$ ,有:
那么理想的基学习器:
在分布 $D_{t}$ 下最小化分类误差,样本分布更新公式:
重赋权法:根据样本分布为每个样本重新赋予一个权重。
重采样法:根据样本分布对训练集重新采样,再用采样样本集对基学习器进行训练。
Boosting 主要关注降低偏差,因此 Boosting 能基于泛化性能相当弱的学习器构建很强的集成。
AdaBoost 算法的误差分析
AdaBoost 能够在学习过程中不断减少训练误差,即在训练数据集上的分类误差,所以,有以下定理,AdaBoost 算法最终分类器的训练误差界(定理1:AdaBoost 的训练误差界)为:
这里的 $G(x)$ 就是我们的 $h_{i}(x)$ ,$f(x)$ 是正确结果,$Z_{m}$ 是规范化因子。
首先,我们知道:
我们使 $D_{m+1}$ 成为一个概率分布,通过:
所以可以推出:
上面式子的前半部分是显然的,当 $G(x_{i}) ≠ y_{i},y_{i}f(x_{i})<0$ 所以后面的结果一定大于 1 。然后的等号推导如下:
现在每一轮选取适当 $G_{m}$ 使得 $Z_{m}$ 最小,从而使训练误差下降最快,对二分类问题,有如下结果(定理2:二分类问题 AdaBoost 的训练误差界):
这里,$\gamma _ { m } = \frac { 1 } { 2 } - e _ { m }$ 。
前两个等号:
然后,对于最后的不等号:
可以通过 $e^{x}$ 和 $\sqrt { 1 - x }$ 在点 $x=0$ 处泰勒展开得到。
推论:如果存在 $ \gamma > 0$ ,对所有 m 有 $\gamma _ { m } \geqslant \gamma$,则:
AdaBoost 的训练误差以指数速率下降。
AdaBoost 算法的解释
考虑加法模型:
这里,$b(x;\gamma _{m})$ 是基函数, $\gamma_{m}$ 是基函数的参数,$\beta _{m}$ 是基函数的系数,显然,这是一个加法模型。
在给定训练数据和损失函数 $L(y,f(x))$ 的条件下,学习加法模型 $f(x)$ 成为经验风险极小化即损失函数极小化问题:
给定训练数据集 $T = \left\{ \left( x _ { 1 } , y _ { 1 } \right) , \left( x _ { 2 } , y _ { 2 } \right) , \cdots , \left( x _ { N } , y _ { N } \right) \right\}$ ,学习加法模型 $f(x)$ 的前向分布算法如下:
- 初始化 $f _ { 0 } ( x ) = 0$
- 循环开始 $m = 1… M$
- 极小化损失函数:$\left( \beta _ { m } , \gamma _ { m } \right) = \arg \min _ { \beta , \gamma } \sum _ { i = 1 } ^ { N } L \left( y _ { i } , f _ { m - 1 } \left( x _ { i } \right) + \beta b \left( x _ { i } ; \gamma \right) \right)$
- 得到参数 $\beta_{m}$ 和 $\gamma_{m}$ ,更新:$f _ { m } ( x ) = f _ { m - 1 } ( x ) + \beta _ { m } b \left( x ; \gamma _ { m } \right)$
- 最终,得到加法模型: $f ( x ) = f _ { M } ( x ) = \sum _ { m = 1 } ^ { M } \beta _ { m } b \left( x ; \gamma _ { m } \right)$
现在,前向分布算法,将问题简化为逐次求解各个参数 $\beta_{m}$ 和 $\gamma_{m}$ 。
定理:AdaBoost 算法是前向分布加法算法的特例,这时,模型是由基本分类器组成的加法模型,损失函数是指数函数。
AdaBoost 小结
训练数据中每个样本赋予一个权重,这个权重构成了向量 D ,之后分对的样本权重降低,分错的样本权重增高,构成新的 D ,同时 AdaBoost 为每个分类器都分配一个权重值 alpha:
而分布 D :
进行下一轮迭代。
提升树
以决策树为基函数的提升方法被称为提升树,对分类问题决策树是二叉分类树,对回归问题决策树是二叉回归树。提升树可以表示为决策树的加法模型:
其中 $T \left( x ; \Theta _ { n } \right)$ 表示决策树;$\Theta _ { n }$ 表示决策树的参数; $M$ 是树的个数。
提升树算法采用前向分步算法。首先确定初始提升树 $f_{0}(x)=0$ ,第 m 步的模型是:
通过经验风险极小化确定下一棵决策树的参数:
这里的 $T$ 指的就是下一棵决策树。
不同问题的提升树学习算法,主要区别在于使用的损失函数不同,平方误差损失函数的回归问题,指数损失函数的分类问题。下面叙述回归问题的提升树:
x 是输入, y 是输出,c 是输出常量,J 是回归树的复杂度即叶节点的个数,$\Theta = \left\{ \left( R _ { 1 } , c _ { 1 } \right) , \left( R _ { 2 } , c _ { 2 } \right) , \cdots , \left( R _ { J } , c _ { J } \right) \right\}$ 表示树的区域划分和各区域上的常数。
回归问题提升树使用以下前向分布算法:
在前向分布算法的第 m 步,给定当前模型 $f_{m-1}(x)$ ,需求解:
当使用平方误差损失函数时:
其损失变为:
这里, $r = y - f _ { m - 1 } ( x )$ ,是当前模型拟合数据的残差。
所以,对回归问题的提升树来说,只需要简单地拟合当前模型的残差,这样,算法就相当简单。
回归问题的提升树算法:
输入:训练数据集 $T={(x1,y1),(x2,y2),…(xn,yn)}, xi, yi$
输出:提升树 $f_{M}(x)$
- 初始化 $f_{0}(x)=0$
- 开始循环 m = 1,2,…M
- 计算残差:$r _ { m i } = y _ { i } - f _ { m - 1 } \left( x _ { i } \right) , \quad i = 1,2 , \cdots , N$
- 拟合残差 $r_{mi}$ 学习一个回归树,得到 $T \left( x ; \Theta _ { m } \right)$
- 更新 $f _ { m } ( x ) = f _ { m - 1 } ( x ) + T \left( x ; \Theta _ { m } \right)$
- 对第 3 步到第 5 步进行循环
- 得到回归问题提升树 $f _ { M } ( x ) = \sum _ { m = 1 } ^ { M } T \left( x ; \Theta _ { m } \right)$
梯度提升
提升树利用加法模型和前向分布算法实现学习的优化过程,当损失函数是平方损失和指数损失的时候,每一步优化是很简单的,但一般损失函数而言,往往每一步优化并不容易,针对这一问题,出现了梯度提升。
这是利用最速下降法的近似方法,其关键是利用损失函数的负梯度在当前模型的值,主要不同就是残差的计算方式:
作为回归问题提升树算法中的残差的近似值。
输入:训练数据集 $T={(x1,y1),(x2,y2),…(xn,yn)}, xi, yi$ ;损失函数 $L(y,f(x))$
输出:回归树 $\hat { f } ( x )$
- 初始化:$f _ { 0 } ( x ) = \arg \min _ { c } \sum _ { i = 1 } ^ { N } L \left( y _ { i } , c \right)$
- 开始循环 m 从 1 到 M
- 对于 i 从 1 到 N ,计算: $r _ { m l } = - \left[ \frac { \partial L \left( y _ { i } , f \left( x _ { i } \right) \right) } { \partial f \left( x _ { i } \right) } \right] _ { f ( x ) = f _ { m- 1 } ( x ) }$
- 对 $r_{mi}$ 拟合一个回归树,得到第 m 棵树的叶节点区域 $R_{mj}$
- 对 j 从 1 到 J ,计算:$c _ { m j } = \arg \min _ { c } \sum _ { x _ { i } \in R _ { mj } } L \left( y _ { i } , f _ { m - 1 } \left( x _ { i } \right) + c \right)$
- 更新 $f _ { m } ( x ) = f _ { m - 1 } ( x ) + \sum _ { j = 1 } ^ { J } c _ { m j } I \left( x \in R _ { m j } \right)$
- 得到回归树 $\hat { f } ( x ) = f _ { M } ( x ) = \sum _ { m = 1 } ^ { M } \sum _ { j = 1 } ^ { J } c _ { m j } I \left( x \in R _ { m j } \right)$
XGBoost
原始的 GBDT 算法基于经验损失函数的负梯度来构造新的决策树,只是在决策树构建完成后再进行剪枝,而 XGBoost 在决策树构建阶段就加入了正则化:
对于上面的式子,我们可以发现,除去正则项以外,就是我们传统的决策树。对于决定下一棵树:
现在我们使用泰勒展开, $x$ 取值 $\hat { y } _ { i } ^ { ( t - 1 ) } + f _ { t } \left( x _ { i } \right)$ ,来逼近:
其中:
删除常数项,那么 t 目标函数就变成了:
我们需要定义树的复杂度 $\Omega ( f )$ ,首先我们定义一棵树:
这里 w 是树叶上的分数向量,q 是将每个数据点分配给叶子的函数,T 是树叶的数量。正则化定义:
注意,当正则项系数为 $\gamma$ 为 0 时,整体目标就退化回了 GBDT 。
我们可以用第 t 棵树来编写目标值如:
其中 $I _ { j } = \{ i | q \left( x _ { i } \right) = j \}$ 是分配给第 j 个叶子的数据点的索引的集合。 请注意,在第二行中,我们更改了总和的索引,因为同一叶上的所有数据点都得到了相同的分数。 我们可以通过定义 $G _ { j } = \sum _ { i \in I _ { j } } g _ { i }$ 和 $H _ { j } = \sum _ { i \in I _ { j } } h _ { i }$ 来进一步压缩表达式 :
我们可以得到最好的客观规约:
将预测值带入损失函数可以得到损失函数的最小值,同时也在度量一个树有多好:
既然我们有了一个方法来衡量一棵树有多好,理想情况下我们会列举所有可能的树并挑选出最好的树。 在实践中,这种方法是比较棘手的,所以我们会尽量一次优化树的一个层次。 具体来说,我们试图将一片叶子分成两片,并得到分数:
这个公式可以分解为 1) 新左叶上的得分 2) 新右叶上的得分 3) 原始叶子上的得分 4) additional leaf(附加叶子)上的正则化。 我们可以在这里看到一个重要的事实:如果增益小于 γ,我们最好不要添加那个分支。这正是基于树模型的 pruning(剪枝) 技术!通过使用监督学习的原则,我们自然会想出这些技术工作的原因 :)
另外,在分割的时候,这个系统还能感知稀疏值,我们给每个树的结点都加了一个默认方向,当一个值是缺失值时,我们就把他分类到默认方向,每个分支有两个选择,具体应该选哪个?这里提出一个算法,枚举向左和向右的情况,哪个 gain 大选哪个,这些都在这里完成。
总结一下,XGBoost 就是最大化这个差来进行决策树的构建,XGBoost 和 GDBT 的差别和联系:
- GDBT 是机器学习算法, XGBoost 是该算法的工程实现。
- XGBoost 加入了正则化,支持多种类型的基分类器,支持对数据采样(和 RF 类似),能对缺省值处理。
ps: 论文第二章里提到了shrinkage 和 column subsampling,就是相当于学习速率和对于列的采样骚操作。调低 eta 能减少个体的影响,给后续的模型更多学习空间。对于列的重采样,根据一些使用者反馈,列的 subsampling 比行的 subsampling 效果好,列的 subsampling 也加速了并行化的特征筛选。
XGBoost 的调参
- 过拟合:
直接控制模型的复杂度:
- 这包括
max_depth
,min_child_weight
和gamma
增加随机性,使训练对噪声强健:
- 这包括
subsample
,colsample_bytree
- 你也可以减小步长
eta
, 但是当你这么做的时候需要记得增加num_round
。
- 不平衡的数据集
如果你只关心预测的排名顺序:
- 通过
scale_pos_weight
来平衡 positive 和 negative 权重。- 使用 AUC 进行评估
如果你关心预测正确的概率:
- 在这种情况下,您无法重新平衡数据集
- 在这种情况下,将参数
max_delta_step
设置为有限数字(比如说1)将有助于收敛
Bagging
给定包含 m 个样本的数据集,随机取出一个样本放到采样集中,再把样本放回初始数据集,使得下次采样时仍有可能被选中,经过 m 次随机采样,我们得到含 m 个样本的采样集,初始训练集中有的样本在采样集有多次出现,有的则从未出现。
Bagging 可以不经修改用于多分类、回归等任务。
因为 Bagging 只使用了部分数据,剩下的可以用作验证集,称为包外估计 out-of-bag estimate :
则泛化误差的包外估计是:
Bagging 主要关注降低方差,因此它在不剪枝决策树、神经网络等易受样本扰动的学习器上效用更明显。
随机森林
在 Bagging 的基础上,进一步引入随机属性选择,假定决策树有 d 个属性,现在我们只随机选择 k 个属性的子集,然后在这个子集中选择一个最优属性进行划分,推荐 $k = log_{2}d$ 。
随机森林通常会训练效率优于 Bagging ,且随着学习器数目的增加,通常会收敛到更低的泛化误差。
算法实现
AdaBoost 伪码
1 | """ |
最终返回 $H(x) = \operatorname { sign } \left( \sum _ { t = 1 } ^ { T } \alpha _ { t } h _ { t } ( \boldsymbol { x } ) \right)$ 。
sign 表达符号函数。
Bagging 伪码
1 | """ |
最终返回 $H(x) = \underset { y \in \mathcal { Y } } { \arg \max } \sum _ { t = 1 } ^ { T } \mathbb { I } \left( h _ { t } ( \boldsymbol { x } ) = y \right)$ 。
Stacking 伪码
1 | """ |
输出 $H ( \boldsymbol { x } ) = h ^ { \prime } \left( h _ { 1 } ( \boldsymbol { x } ) , h _ { 2 } ( \boldsymbol { x } ) , \ldots , h _ { T } ( \boldsymbol { x } ) \right)$ 。
算法例子
AdaBoost 例子
假设存在3个分类器,对每一个分类器:
- 初始化权值 Di。
- 取阈值来分类,得到基分类器 hi。
- 计算误差率 ei。
- 得到分类器系数 ai。
- 更新权值 Di+1。
最后我们将三个分类器按照各自的系数 a 来进行预测,得到整体 H 。
如果没看懂我们再来一次:
输入数据集 $T = \left\{ \left( x _ { 1 } , y _ { 1 } \right) , \left( x _ { 2 } , y _ { 2 } \right) , \cdots , \left( x _ { N } , y _ { N } \right) \right\}$ 。
输出最终分类器 $G(x)$ 。
Ps:刚才我们用 $H$ 来表示分类器。
- 初始化训练数据的权值分布:$D _ { 1 } = \left( w _ { 11 } , \cdots , w _ { 1 i } , \cdots , w _ { 1 N } \right) , \quad w _ { 1 } = \frac { 1 } { N } , \quad i = 1,2 , \cdots , N$
- 循环开始,对于 $m=1,2,…M$
- 使用具有权值分布 $D_{m}$ 的训练数据学习,得到基本分类器:$G _ { m } ( x ) : \mathcal { X } \rightarrow \{ - 1 , + 1 \}$
- 计算 $G_{m}(x)$ 在训练数据集上的分类误差率:$e _ { m } = P \left( G _ { m } \left( x _ { i } \right) \neq y _ { i } \right) = \sum _ { i = 1 } ^ { N } w _ { m i } I \left( G _ { m } \left( x _ { i } \right) \neq y _ { i } \right)$
- 计算 $G_m(x)$ 的系数:$\alpha _ { m } = \frac { 1 } { 2 } \log \frac { 1 - e _ { m } } { e _ { m } }$
- 更新训练集的权值分布:$D _ { m + 1 } = \left( w _ { m + 1,1 } , \cdots , w _ { m + 1 , l } , \cdots , w _ { m + 1 , N } \right)$ $w _ { m + 1 , i } = \frac { w _ { m i } } { Z _ { m } } \exp \left( - \alpha _ { m } y _ { i } G _ { m } \left( x _ { i } \right) \right) , \quad i = 1,2 , \cdots , N$
- 这里的 $Z_{m}$ 是规范化因子:$Z _ { m } = \sum _ { i = 1 } ^ { N } w _ { m } \exp \left( - \alpha _ { m } y _ { i } G _ { m } \left( x _ { i } \right) \right)$ ,它使 $D_{m+1}$ 成为一个概率分布
- 构建基本分类器的线性组合:$f ( x ) = \sum _ { m = 1 } ^ { M } \alpha _ { m } G _ { m } ( x )$
- 得到最终分类器:$G ( x ) = \operatorname { sign } ( f ( x ) ) = \operatorname { sign } \left( \sum _ { m = 1 } ^ { M } \alpha _ { m } G _ { m } ( x ) \right)$
经典题目
- XGBoost 与 GBDT 的联系与区别有哪些?
GBDT 是机器学习算法;XGBoost 是工程实现。
传统 GBDT 采用 CART 作为基分类器, XGBoost 支持多种类型的基分类器,比如线性分类器。
XGBoost 增加了正则项,防止过拟合。
XGBoost 支持对数据进行采样,对缺失值有处理。
从方差和偏差的角度解释 Boosting 和 Bagging 的原理?
算法总结
- 提升算法是将弱学习算法提升为强学习算法的统计学习算法,通过反复修改训练数据的权值分布,构建一系列基本分类器,并将这些基本分类器线性组合,构成一个强分类器。
- AdaBoost 将分类误差小的基本分类器以大的权值,给误差大的基本分类器以小的权值。
- 提升树是以分类树或回归树为基本分类器的提升方法。