李宏毅机器学习——集成学习

引言

主要讲了集成学习(Ensemble)

集成学习的框架

集成学习体现了一个团队合作的思想。

在这里插入图片描述
(这里我改了一下李宏毅老师的例子,改成了LOL)。
假设你有很多分类器,每个分类器扮演不同的角色,比如在LOL中,有的分类器是ADC,有的是TOP。这些分类器应该具有一定的差异性。

在这里插入图片描述

把这些角色都集合在一起,形成配合,比如SUP控制,TOP抗,ADC输出。

在Ensemble中有很多不同的方法,先来看下Bagging方法。

Bagging

在这里插入图片描述
先来回顾下模型的偏差和方差。

假设有个简单的模型,它有很大的偏差(都没打到靶心),但是方差比较小(比较集中)。就是如上图红框所示;如果是复杂的模型,一般会有小的偏差,但是方差较大。如上图紫框。

上面的趋势图中,横坐标是模型的复杂度,纵坐标是模型的错误率。可以看到,错误率先是随着模型复杂度的增加而减少,随后变成上升。

在这里插入图片描述
假设在不同的宇宙里面都在抓宝可梦,每个宇宙都可以得到一个模型。每个宇宙预测宝可梦的模型都不一样,我们可以把不同的模型都结合起来(输出就均值),得到新的模型 f f^* ,这个新的模型可能就会很接近真实模型。

虽然我们不可能从不同的宇宙取收集数据,但是我们可以创造出不同的数据出来,再用不同的数据集,各自去训练一个复杂的模型,虽然每个模型单独看的话方差很大,但是把不同的模型结合起来后,它的方差就不会那么大。

怎么制造不同的数据呢

在这里插入图片描述
假设你有N笔训练数据,从这N笔训练数据中取样 N N^\prime 笔,通常 N N 可以等于 N N^\prime ,因为Bagging是放回取样,很大的可能会重复取数据。

这里假设我们做4次这样的取样,就可以得到4份训练数据,然后分别训练4个复杂的模型。
在这里插入图片描述
在测试的时候,可以用同一份测试数据对这四个模型进行测试,然后结合它们的输出。这里的方法有投票(分类)或求均值(回归)。

当你的模型很复杂,容易过拟合时,可以做Bagging来减低方差。

那什么样的模型容易过拟合呢,最容易过拟合的其实是决策树
决策树可以在训练数据上拿到100%的正确率。

决策树做Bagging就可以得到随机森林。

初音实验

在这里插入图片描述

初音数据下载地址为: http://speech.ee.ntu.edu.tw/~tlkagk/courses/MLDS_2015_2/theano/miku

这里以初音图像作为决策树分类的应用例子,这个例子输入是二维(图像的坐标),红色部分是初音轮廓的填充,标记为类别1(乘以255后变成了白色),蓝色部分相当于是背景,标记为类别0(0灰度值代表黑色)。 相当于输入是坐标,输出是该点为白色还是黑色。

import pandas as pd
import numpy as np
from PIL import Image

# 1st column: x, 2nd column: y, 3rd column: output (1 or 0) 
miku=pd.read_csv('miku.csv',sep=' ',header=None)

miku = np.array(miku.values)

miku_grayscale = miku[:,2]#得到类别
miku_grayscale = miku_grayscale.reshape((500, 500))#总共250000份数据
miku_grayscale = miku_grayscale.transpose()#这里进行装置,不然图像是倒着的


image = Image.fromarray(miku_grayscale*255)#*255得到灰度值
image.show()

关于sklearn中决策树代码是如何使用的可以参阅机器学习入门——图解集成学习(附代码)

这里我们跟着李宏毅老师来实作下这个例子,加载初音数据并展示的代码如上。

在这里插入图片描述

接下来,用不同深度的决策树来看下分类效果。
先定义显示图像的函数:

def show_image(data):
    data = data.reshape((500, 500))
    data = data.transpose()
    image_show = Image.fromarray(data*255)
    image_show.show()

然后先用一颗深度为5的决策树进行分类:

from sklearn.tree import DecisionTreeClassifier

dt_clf = DecisionTreeClassifier(max_depth=5)
# 拆分输入和输出
miku_data = miku[:,0:2]#输入:坐标
miku_target = miku[:,-1]#输出:黑或白


dt_clf.fit(miku_data, miku_target)
predict = dt_clf.predict(miku_data)
show_image(predict)

在这里插入图片描述

下面分别是深度为5,10,15,20的结果。

在这里插入图片描述
当深度为20的时候,就可以完美的画出初音的样本,其实这也没什么,因为决策树能达到错误率是0。
因为决策树太容易过拟合,所以在测试数据上如果只用一颗决策树,往往很难达到比较好的结果。

所以我们要结合多颗不同的决策树,通过Bagging的方式结合的决策树就是随机森林。
在这里插入图片描述
通常做训练决策树模型的时候,除了采用Bagging的方法,还随机限制了特征,每次只取部分特征(虽然这里只有两个特征),这样得到的模型更具有差异性。

通过采用Bagging的方法会有一些没有被取样的数据,称为Out-Of-Bag。可以通过这份数据进行测试,这样就可以不单独的分出测试数据集,留更多的数据给训练数据。

单一随机树的话,上面我们用一颗深度为20的决策树才能得到最好的结果,那如果是用随机森林呢。
下面通过随机森林的方式来对初音轮廓进行分类:

from sklearn.ensemble import RandomForestClassifier

rnd_clf = RandomForestClassifier(n_estimators=100,max_depth=5,n_jobs=-1) # n_jobs=-1指定cpu核数,可以并行训练

rnd_clf.fit(miku_data, miku_target)
predict = rnd_clf.predict(miku_data)
show_image(predict)

在这里插入图片描述

这里用100颗深度为5的树,得到的结果如上,可以看到,结果也是很差,但是比单独一颗深度为5的树结果更加平滑。因为这里只是将100颗树的分类结果平均起来(投票)。

所以,我们保持100颗树不变,增加深度为10,分类结果:

在这里插入图片描述
可以看到大概的轮廓了,但是怎么少了一只脚。和单独一颗决策树比起来的话,结果很明显更加平滑,也就是不容易过拟合。

深度为15呢?
在这里插入图片描述

最终深度为20:

在这里插入图片描述
可以看到随机森林会让分类的结果更加平滑,也就是可以减少模型的方差,要想得到好的结果,还是要用到较好的模型(比如这里深度为20的决策树)。

下面我们介绍一个牛逼的方法,可以通过一个一般的模型(深度为5的决策树),最终得到一个非常好的模型。

Boosting

通过提升方法可以将多个比较弱(分类准确度不高,但是至少要比随机好)的模型,集成成一个分类性能很好的模型。
在这里插入图片描述

上面说的是只要你能提供分类准确率高于50%的分类器,通过Boosting方法最终就能得到错误率为0的分类器。

要怎么做呢,首先得到第一个分类器 f 1 ( x ) f_1(x) ,这个分类器可能只是高过50%,分类效果不好没关系;
然后Boosting帮你找到另一个分类器 f 2 ( x ) f_2(x) 来提升 f 1 ( x ) f_1(x) 分类不好的部分;
最终,组合所有的分类器。

这里会训练很多个基分类器,每个基分类器都是基于上一个分类其训练的,因此它们是顺序训练的,无法进行并行训练。

关于提升算法《统计学习方法》这本书就写的不错,博主也做了笔记,感兴趣的可以参阅一下。

如何得到不同的分类器

在Bagging中我们学习过可以通过训练不同的训练集来得到不同的分类器。

在提升方法中说过通过分类器 f 1 ( x ) f_1(x) 可以得到分类器 f 2 ( x ) f_2(x) ,通过 f 2 ( x ) f_2(x) 也可以得到 f 3 ( x ) f_3(x)

那是怎么做的呢

这里要给每笔数据一个权重,这了初始化权重为 1 1 ,通过 u u 表示。可以通过改变权重来制造不同的数据集。

在这里插入图片描述
比如这里有3笔数据,初始权重都为 1 1 ,如果我们改变权重,就可以得到不同的训练数据。
在这里插入图片描述
改变权重后,对训练其实也没有太大的影响。在训练时,每笔数据的结果前乘上权重即可。
在这里插入图片描述

如果有笔数据的权重比较大,那么在训练的时候就会多考虑一点。

下面就开始学习提升算法中的经典算法——AdaBoost

AdaBoost的思想

主要思想就是在上一个分类器分类错误的样本中训练新的分类器。
当然你需要提供第一个分类器,只要比随机效果好就行了,比如二分类问题中,高于50%就行。

先来看下如何计算第一个分类器 f 1 ( x ) f_1(x) 的错误率:
在这里插入图片描述
这里的 δ \delta 其实就是指数函数,国内书籍一般是用 I I 表示。这里相当于只是计算了分类错误的样本权重之和,再除以所有权重之和。

这里相当于做了一个归一化。这里错误率要小于50%(这里说的是二分类问题,如果错误率大于0.5,只要把输出反过来就可以了)。

接下来就通过下面的式子更新每笔数据的权重:

在这里插入图片描述

u 2 u_2 作为新数据的权重,使得 f 1 ( x ) f_1(x) 在新的训练数据上的结果为0.5,接下来就用这个权重 u 2 u_2 训练 f 2 ( x ) f_2(x) Z 2 Z_2 的计算方式和 Z 1 Z_1 一样, Z 2 Z_2 计算的是 u 2 u_2 之和。

这里看起来真的不容易理解,下面通过一个例子可以帮助大家理解。

在这里插入图片描述

假设有4笔训练数据,开始时权重都是 1 1 ,然后用这份数据来训练一个模型 f 1 ( x ) f_1(x) ,这里假设它只在第2笔数据上分类错误。所以它的错误率是0.25。

接下来修改权重,使得 f 1 ( x ) f_1(x) 在这些新权重上的错误率为0.5。

要用 f 1 ( x ) f_1(x) 的错误率变大,也就是让分类错误样本的权重变大,让分类正确样本的权重变小。

比如你得罪了一个老师,然后你做的卷子分数还不错,但是还没达到满分,但是这个老师为了整你,故意将你答错题目的分数调高,将你答对题目的分数调低,这样最终你的分数就会变低。
所以还是在绝对的实力面前(你考得满分),任何计谋都没用了。

在这里插入图片描述
这里假设是这样修改了权重,3个正确的权重才等于一个错误的权重,这样使得 f 1 ( x ) f_1(x) 在上面的分类错误率为0.5。

接下来,在这组新的训练数据上面,训练 f 2 ( x ) f_2(x) ,相当于是让它重点考虑上一个分类器分类错误的部分。

上面只是讲了一个思想,那实际上是怎么做的呢

在这里插入图片描述

如果某笔数据 x n x^n f 1 f_1 错误分类,那么就把该笔数据的权重乘上一个值 d 1 d_1 (大于1),使得权重增加;

如果某笔数据 x n x^n f 1 f_1 正确分类,那么就把该笔数据的权重除上一个值 d 1 d_1 (大于1),使得权重减少;

这样就可以得到每笔数据新的权重 u 2 u_2 ,然后基于这个权重来训练 f 2 f_2 ,那 d 1 d_1 的值要怎么取呢

和上面的公式一样,我们要得到 u 2 u_2 使得 f 1 f_1 在上面的错误率为0.5。

在这里插入图片描述
因为上面用了指示函数,分类正确的指示函数结果为 0 0 ,因此实际上考虑的是分类错误的样本权重。上面分子的地方可以写成:
在这里插入图片描述
分母 Z 2 Z_2 还是所有的权重之和,包括分类正确的和错误的,也就可以写成:
在这里插入图片描述
所以整个式子就是下面的样子:
在这里插入图片描述
两边都取倒数得:
在这里插入图片描述
然后可以约掉相同的项,
在这里插入图片描述
也就是:

在这里插入图片描述
(注意求和下面的条件,左边说的是分类正确的样本,右边说的是分类错误的样本)。

接下来分别把 1 d \frac{1}{d} d d 提出来。

在这里插入图片描述
根据之前的式子,错误率可以写成这样:

在这里插入图片描述
它的分子出现在上面倒数第二个图右边。

在这里插入图片描述
把分母乘过去就得到上式,带入之前的等式。而

f 1 ( x n ) = y ^ n u 1 n = Z 1 ( 1 ε 1 ) \sum_{f_1(x^n) = \hat y ^n} u_1^n = Z_1(1 - \varepsilon_1)
就是1减去正确率。
在这里插入图片描述
也就是:
在这里插入图片描述
最终可以算出 d 1 d_1 的式子。

因为错误率是小于0.5的,所以 d 1 d_1 一定大于1。

整个AdaBoost的算法如下:

在这里插入图片描述
这里重点说下上面红框框出来的部分,其实就是我们上面推导的那个式子,不过引入了 α \alpha e x p ( α t ) = d t exp(\alpha_t) = d_t

利用了 e x = 1 e x e^{-x} = \frac{1}{e^x} 来表示除法运算,简化最终的式子。
如果 y ^ n \hat y^n f t ( x n ) f_t(x^n) 同号,就是分类正确,相乘就是 1 1 (基于 y ^ = { + 1 , 1 } \hat y = \{+1,-1\} ),前面有个负号,就变成了除法的形式;反之分类错误,就是直接相乘。这样就写到了一个式子中。

(算法还没完)
经过上面的训练后,可以得到一把分类器,下面如何把它们集合在一起呢

因为我们的分类器有好有差,我们希望它们对最终结果的影响是不同的,因此很容易想到的是要加个权重。其实这个权重上面已经计算过了,就用 α t \alpha_t 即可。
在这里插入图片描述
如果某个分类器的错误率比较低,比如是0.1,那么它得到的权重会是1.1。
在这里插入图片描述
如果错误率较大,比如0.4,得到的权重会是0.2。
因此,错误率小的分类器在最终投票会具有更大的权重。

这里应该有个例子,推荐去看《统计学习方法》——提升算法,博主通过代码实现了书中AdaBoost的例子,可以结合上面的理论和代码很容易的理解AdaBoost的思想。

证明

在这里插入图片描述
这一小节是证明AdaBoost算法在迭代次数(子模型数)越来越多的情况下,最终分类器 H ( x ) H(x) 的错误率越来越小。

在这里插入图片描述
我们先列出这个错误率的计算公式。

在这里插入图片描述

然后用 g ( x ) g(x) 表示上面括号内的这一项。

所以错误率的这一项可以写成:

在这里插入图片描述
这里利用了 y ^ n \hat y^n g ( x n ) g(x^n) 同号(分类正确)为 + 1 +1 ,异号为 1 -1 改成了小于零。

在这里插入图片描述
然后说这个错误率有一个上界。为什么呢,这里通过画图来说明。

在这里插入图片描述
可以看到蓝线始终在绿线上方,所以是它的上界。接下来证明这个上界会越来越小。

我们先来计算 Z t Z_t ,就是 f t f_t 的权重之和。

Z T + 1 Z_{T+1} 是怎样的呢
在这里插入图片描述
我们知道在初始的时候权重都为 1 1

通过AdaBoost的思想这一节我们知道了 u t + 1 u_{t+1} 的计算式子:

在这里插入图片描述

也就是第 t + 1 t+1 个时间点的权重与第 t t 个时间点的权重之间有上面这样的关系,我们就可以得到 u T + 1 u_{T+1} 的式子:

在这里插入图片描述

所以就可以得到 Z T + 1 Z_{T+1} 的表达式:

在这里插入图片描述
我们可以把连乘放到 e x p exp 里面,变成了求和。

在这里插入图片描述
红线标出来的这一项就是 g ( x ) g(x)
在这里插入图片描述

并且篮筐框出来的其实就是一样的,也就是错误率小于等于下面这个

在这里插入图片描述
可以发现权重之和竟然与训练数据的错误率有关。

接下来要证明这个权重之和会越来越小。

我们可以写出 Z t Z_t 的式子。
在这里插入图片描述
带入 α t \alpha_t 的式子得:
在这里插入图片描述
最终化简得到最后一个式子
在这里插入图片描述

它的函数图像是这样的,当错误率等于0.5时,取最大值1。而我们知道错误率是小于0.5的,所以 Z t Z_t 会比 Z t 1 Z_{t-1} 还要小。

Z T + 1 Z_{T+1} 的式子可以写成:
在这里插入图片描述
其中 N N Z 1 Z_1

在这里插入图片描述
所以随着迭代次数 T T 的增加,错误率是越来越小的。

证明完毕。

用AdaBoost对初音进行分类

这里我们保持深度不变,采用一个比较弱的分类器,验证通过增加子模型的数量就可以提升最终分类器的性能。

from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier

miku=pd.read_csv('miku.csv',sep=' ',header=None)

miku = np.array(miku.values)

# 拆分输入和输出
miku_data = miku[:,0:2]#输入:坐标
miku_target = miku[:,-1]#输出:黑或白

forest_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=5), n_estimators=10) 
forest_clf.fit(miku_data, miku_target)
forest_predict = forest_clf.predict(miku_data)
show_image(forest_predict)

在这里插入图片描述
10个看起来结果很差,保持深度不变,将基分类器数量改成20(n_estimators=20):

在这里插入图片描述
20个轮廓很明显了,再试下50个基分类器:

在这里插入图片描述
50个基分类器的时候提升还是很明显了,但是还不是最好的,我们直接改成100看下(训练时间也会相应的增长):
在这里插入图片描述
可以看到,100个深度为5的决策树通过AdaBoost的方式集成起来后,效果已经很接近深度为20的决策树一样好。也就是我们不需要分类效果特别好的模型,直接集成多个具有差异的一般模型就能得到很好的结果。这就是集成学习的威力。

虽然100个深度为5的决策树已经很好,但还不是最好效果,如何达到最好效果呢,这里直接增加基分类器的数量为200:

在这里插入图片描述
除了增加基分类器的数量外,还可以尝试提升基分类器的性能,这里可以通过增加决策树的深度来实现,我就不演示了。

Gradient Boosting

刚才提升算法更通用的版本
在这里插入图片描述
怎么找到比较好的 g ( x ) g(x)

要先设一个目标函数
在这里插入图片描述
这里 l l 是损失函数,可以这样定义:

在这里插入图片描述
这样,我们希望 y ^ n \hat y^n g ( x n ) g(x^n) 要同号,并且相乘的结果越大越好。

我们可以通过梯度下降法来最小化。

在这里插入图片描述
这里函数 g g 如何求 L L 对它的微分呢。可以把它的每个点当成参数,取 x 1 x_1 得到 g ( x 1 ) g(x_1) ,取 x 2 x_2 得到 g ( x 2 ) g(x_2) ,假设 x x 取得很密,那么 g ( x ) g(x) 就是一个向量。

在这里插入图片描述
如果从提升算法的角度来看,我们知道提升算法要找一个 α t \alpha_t f t ( x ) f_t(x) 。我们希望红框这两项表示同一个意思,至少它们的方向要一样。

我们知道 L L 的式子是这样的
在这里插入图片描述
让它对 g g 求导,得到:

在这里插入图片描述
消掉学习率前面的负号就得到
在这里插入图片描述
我们希望 f t ( x ) f_t(x) 和这个式子方向越一致越好。每个函数可以想象成一个无穷多维的向量,上面两个式子都是一个向量。如果我们只考虑训练数据中的那些情况,那么它们的维度就是有限的。

在这里插入图片描述
就是想要上面这个式子的值越大越好,
在这里插入图片描述
我们希望对每笔训练数据来说, y ^ n \hat y^n f t ( x n ) f_t(x^n) 是同号的,并且前面都乘以一个权重。
在这里插入图片描述

g t 1 g_{t-1} 的式子代入,就得到上式。把求和变成连乘。

在这里插入图片描述

可以发现它就是AdaBoost的权重。

在这里插入图片描述
所以我们今天找出来的 f t ( x ) f_t(x) 相当于AdaBoost中的 f t ( x ) f_t(x)
在AdaBoost中找 f t ( x ) f_t(x) 可以想成是做梯度下降一样。

α t \alpha_t 相当于是学习率,给定了 f t ( x ) f_t(x) 后,我们要找到一个 α t \alpha_t 使得 g t ( x ) g_t(x) 的损失最小。

在这里插入图片描述
就是要计算 L L α \alpha 的微分,最终可以得到 α t = l n ( 1 ε t ) / ε t \alpha_t = ln \sqrt{(1-\varepsilon_t) / \varepsilon_t}

所以可以把AdaBoost想象成是在做梯度下降。

参考

1.李宏毅机器学习

原创文章 176 获赞 286 访问量 18万+

猜你喜欢

转载自blog.csdn.net/yjw123456/article/details/105832007
今日推荐