这部分主要补充一些cs229没涉及到,但是实际上非常重要,而且是实际中真正会用的一些算法,即集成学习。
集成学习
问题背景
既然我们已经知道了很多学习算法,这些算法最终会输出一个结果。能不能把这些结果进行结合。构造一个性能更好的学习器呢。
首先要明确集成学习和单个基学习器的学习有什么区别。
我们定义分歧为各个基学习器与集成学习器的差距的加权均值:
再定义基学习器和集成学习器的泛化误差:
所以有:
整理一下得:
解释一下就是,基学习器的准确性越高,多样性越好,那么集成学习器的表现也会越好。简而言之就是基学习器要做到好而不同。
那么如上图所示:
集成学习最终转化为两个问题:
- 如何得到让基学习器好而不同
- 如何结合基学习器
顺便补充一下基学习器的定义,我们的基学习的表现要比随机瞎猜好一点就行了。即只要判断样本正确率大于一半即可。
决策树
在讲集成学习之前先介绍一种新的基学习器。这个基学习器的表达能力非常强,比较容易在集成学习中构建更强的分类器。
基本形式
我们的决策树可以写成递归的形式:
其中:
- (H(x))为完整的树
- (b(x))为分支条件
- (h_c())子树
那么我们的决策树训练算法就可以写成:
所以决策树算法有四个基本的要素:
- 分支个数,对数据集切分个数
- 分支条件,对数据切分的规则
- 终止算法,子树递归过程中的种终止条件
- 基本算法,递归中子树的生成算法
C&R决策树
这里简单介绍一种可以用于决策和回归的C&R决策树。
C&R决策树其实就是在通用的决策树规则上面做了一些限定:
- 分支个数为2
- 根据纯度来对数据集切分
纯度在回归问题中的定义为:
纯度在分类问题中的定义为:
如果用分类问题来理解的话,其实就就是让样本集尽可能分开的那个特征。比如有一个特征能让左子树全为正样本,右子树全为负样本,那么这个分支的纯度是最高的。
于是训练算法就是:
这里省略了大量细节,有兴趣请翻阅参考。
bagging
bagging即对基学习器h以任意函数进行结合的算法。
bootstrap
在对集成学习的误差分解中我们提到了要让基学习器的经验误差尽可能小也要让基学习器尽可能不同。那么我们先从让基学习器尽可能不同出发组合基学习器。
那么我们如何得到不同的基学习器呢,这里就用到了统计学上一种叫bootstrap的工具。
bootstrap即我们可以从样本集中选取一些点,然后再放回去。重复这样的操作多次,就能一个样本集构造出很多不同分布的样本子集。他们中的样本可能重复也可能不重复。
而且bootstrap还有一个很重要的有点,因为这是有放回的采样,所以其实大概有36%的样本是不会被抽中的,可以做完我们的验证集,或者叫包外估计。
通过bootstrap得到(h_t)之后我们就可以对其进行结合了
结合
于是我们怎么确定(h_t)的权重(alpha(x))呢。这就要用的我们bootstrap有验证集的特性了。我们可以在验证集上使得求误差最小即可得到我们想要的(alpha(x)),如果权重是一个任意函数的话我们一般称之为Stacking。
这里提一句,如果我们假定基学习器之间用线性关系来结合。即(alpha(x)=alpha)然后把(h_t(x))看做样本特征x。那么(sumalpha h(x))是不是有点像线性回归?
随便提一句,以决策树为基学习的bagging算法就叫做随机森林。
图像
以线性结合的感知机为例:
最终得到的决策边界,颜色淡一点是是基学习器的决策边界。
对于bagging我们可以从大数定理的角度去理解,对于我们训练尽可能不同的基学习器,其实也就是满足了独立同分布条件,当n变大时方差也会减小。
boosting
与bagging相对的就是所谓的boosting算法。bagging简单理解就是我们一下子训练出很多个基学习器,然后通过一种方式结合这些基学习器就行了。bagging是基于组合的,而boosting是基于提升的。基于提升的意思就是,基学习器并不是独立,而是有关联的。
adaboost
boosting可以理解为错题本学习法。这种错误在机器学习中一般称之为残差。bagging只关注了降低方差,并没有专注于经验风险下降。于是boosting对基学习器的组合就专注于降低经验误差,即降低偏差。
adaboost对残差拟合的方法在于样本集的处理。我们让那些学习错误的样本在下一轮学习中有更大的权重。简单理解的话就是做对的题你可以不管了,但是做错的题你要多做几遍。
即这是个对样本集赋权的集成学习算法。
符号说明:
- 给定样本集:((x,y)in D, xin R^n, yin {+1,-1})
- (t) 迭代轮数
- (h_t) 表示第t轮生成的基学习器,这里的基学习器可以是之前我们提到的任意一个学习算法。而且基学习器一定要满足我们之前提到的条件。
- (w_{ti}) 第t轮的第i个样本集权重
- (alpha_t) 第t轮的基学习器权重
- (e_t) 第t论基学习器的误差
以下是迭代过程:
- 初始化样本权值(w_1=frac1N)
- 在权重(w_i)上训练得到(h_t),基学习器不满足条件直接终止循环。
- 计算误差:$$e _ { t } = P left( h _ { t } left( x _ { i } ight) eq y _ { i } ight) = sum _ { i = 1} ^ { N } w _ { ti } 1 left( h _ { t } left( x _ { i } ight) eq y _ { i } ight)$$即被误分类样本的权重之和。
- 计算基学习器在最终假设函数中的权重:$$alpha _ { t } = frac { 1} { 2} ln left( frac { 1- e _ { t } } { e _ { t } } ight)$$这个公式的由来翻阅参考。
- 更新样本集权重:$$w _ { t + 1} = frac { w _ { ti } exp left( - alpha _ { t } y _ { i } {h} _ { t } left( x _ { i } ight) ight) } { 2sqrt { e _ { t } left( 1- e _ { t } ight) } }$$这里分母是一个归一化常数。具体由来也请翻阅参考。
- 回到步骤2直到完成t轮迭代
- 最终得到假设函数为:$$H(x)=sign(sum_{i=1}^{t}alpha_th_t(x))$$
图像
如果我们以一个非常简单的基学习器,即一条垂直坐标轴的直线来分割以下样本集。
可以看到五轮就已经完全分割了。颜色淡一点的线是基学习的决策边界。
GradientBoosting
在adaboost中,我们的残差是定义在样本集中的,而这个算法的残差定义在梯度中。于是才叫做梯度提升算法,并不是梯度上升,而是基于梯度的提升算法。
这里以回归问题为例,假设我们的假设函数为(h(x)),那么我们定义残差就为:
和之前一样使用均方误差:
然后求偏导:
这表示什么意思呢:
即求残差就是求负的梯度,我们最终要求残差最小,也就是让负梯度最小。让负梯度最小不就是我们的梯度下降算法了吗。
问题拓展
即我们把求残差的过程转化成了求负梯度的过程。这样我们就把我们的所谓的错题定义在了误差函数之中。
但是有一个很重要的问题,那就是其实负梯度并不等于残差。
如果我们换一个函数衡量误差:
求负梯度:
也就是说其实只有在用平方来衡量误差的时候,负梯度才等于残差。比如用这个L1距离的时候,负梯度就不等于残差了。但是我们仍然用负梯度最小来使得残差最小。这是为什么呢。因为如果我们把残差都拟合上了,模型能在训练集上达到100%正确率,那不就过拟合了吗。所以说我们只是以负梯度作为残差的一种近似来求解。
求解过程
- 初始化模型 $$H(x)=frac{sum^{n}_{i=1}y_i}{n}$$
- 计算负梯度$$- g left( x _ { i } ight) = - frac { partial J left( y _ { i } ,H left( x _ { i } ight) ight) } { partial H left( x _ { i } ight) }$$
- 利用负梯度拟合出一个基学习器(h)
- 结合基学习器 $$H:=H+αh$$ 并回到第二步迭代至收敛
这里简化处理了,有能力的请务必翻阅一下参考第五条。
bagging&boosting分析
其实从上面的两种算法可以看出,集成学习一般分为两类。即bagging和boosting。下面从方差偏差的角度分析一下bagging和boosting的区别。
从方差-偏差角度分析:
bagging是并行的,每个基学习器可以单独训练。基学习器独立性很强,所以说bagging关注的是降低方差。
boosting是串行的,后一个学习器要在前一个学习器训练好之后才能训练,即学习器之间独立性没那么强,且boosting关注残差,残差就是训练集中没拟合好的数据。于是boosting对样本集会拟合的更好,所以说boosting关注的是降低偏差。