装袋,AdaBoost和随机森林

装袋,AdaBoost和随机森林都属于组合分类方法的例子,用于改善单个分类模型的学习效果。

我们知道,在很多情况下,面对大量复杂的训练元组,如果只使用一种分类模型构造分类器,很可能对于某些元组是有“硬伤”的,预测结果很不准确。所以最直接的思路是将多种分类模型组合起来,通过得到的多个分类器投票判断。好比是有个消息你不知道,去问别人,如果只问一个人,那这个人说的也不一定对吧。但是如果问很多人,以多数人的答案为准,就不太容易出错了。

具体的组合分类方法的例子,一般我们接触较多的是三个:装袋,AdaBoost和随机森林

装袋

工作原理

装袋表示的含义是“自助聚集”,这个含义也比较形象:假设原始的训练集为 D ,我们采用有放回抽样,每次从 D 中随机取出一个元组,经过 N 次有放回抽样( N 也是 D 的大小),生成训练集 D i (就像把训练元祖装进一个袋中),注意这里 D 中的元组可能多次出现在 D i 中,也可能不出现在 D i 中。之后,采用事先设定好的学习方案,使用 D i 中的训练元组生成分类器,记为 M i 。经过 k 轮上述迭代,我们最终可以得到 k 个分类器 { M 1 , M 2 , , M k } 。那么,在对新元组(记为 X )进行分类时,这 k 个分类器都被用来对 X 生成类号,根据“多数投票原则”,选择得票数最高的类作为最终分类结果。

效果分析

就准确率来说,装袋得到的组合分类器的准确率,通常显著高于直接用原始训练集 D 在学习模型上得到单个分类器的准确率,这是因为组合分类器降低了个体分类器的方差。而对于噪声数据和过分拟合的影响,装袋的性能也在可以接受的范围内。

AdaBoost

AdaBoost是Adaptive Boosting的简称,翻译过来就是“适应性提升”,所谓“提升”其实跟上面说的“装袋”基本思想是一致的,都是构造组合分类器,解决单个学习模型对于个别元组误判的问题。与“装袋”不同的是,“提升”的重点在于对每个训练元组赋予一个权重,每一轮迭代学习之后,更新元组的权重,最后经过多轮迭代,获得组合分类器,最后加权投票,得到预测结果。而不像装袋那样:在每轮迭代中,训练元组的权重是等大的,不用加以考虑。

AdaBoost中,元组权重迭代更新的根本目的在于使得下一轮学习过程更加“关注”上一轮迭代中,未被正确分类的元组。(装袋则不同,它的每轮迭代对于所有元组的关注度是一样的)这样做的好处其实很明显:对于单个学习模型来说,有些元组是所谓“难分类”的,我们现在使这些“难分类”的元组在下一轮学习中被“重点照顾”,这样,得到的新分类器会对“难分类”元组效果相对较好,循环往复,最终得到的组合分类器会更加均衡,它对于所有元组的分类效果能够做到都比较好。

据我所知,当前实现AdaBoost主流的方法有两种,一种是韩家炜教授《数据挖掘》中讲到的,每轮迭代采用“自助样本”(即多次有放回抽样生成的元组集合)作为训练集,利用学习方案生成分类器,其中,训练集的选择以元组权重大小为抽样概率依据;另一种是我在网上看到的大多数博客中引用的版本——李航《统计学习方法》中的方法,算法不采取抽样,而是整个训练集参与每轮迭代,每轮迭代根据元组的权重分布设计新的分类器。其实无论是哪一种方法,其基本思想都是一样的:通过迭代学习,更新元组权重,再根据元组权重,生成下一轮迭代的分类器(韩家炜的方法实际上是通过元组权重抽样得到不同的训练数据集,从而实现生成不同的分类器)。最终,得到带权重的组合分类器,加权投票得到预测的分类结果。

韩家炜教授的方法相对公式简单,也更容易理解一些,既然两种方法思想一致,也就没必要分别介绍了。本文中,我简单说明一下韩家炜的方法,至于另外的一种思路,网上有很多大神的博客讲的很详细了,也就不用我多说了。

AdaBoost的其工作原理如下面的伪代码所示:

Input: 训练元组集合D;迭代轮数k;学习方案Learning();
Output: 复合模型(组合分类器)

算法步骤:

将D中所有训练元组的权重初始化为TW_j = 1/N;
# 为不和后面的分类器权重混淆,我用TW_j指代第j个元组(Tuple)的权重;N为原始训练集D的大小

for i in [1, 2, ..., k] do

    根据每个元组的权重$TW_j$抽样取得大小为N的训练集,记为D_i  
    # 权重越大,被抽到的概率越高,$D$中有的元组可能在D_i中出现多次,有的一次都不出现

    M_i = Learning(D_i)  
    # 根据学习方案,使用训练集D_i,计算得到分类器M_i

    根据原始训练集D,计算M_i的错误率:error(M_i) = \sum_{j = 1}^{N}TW_j * err(X_j) 
    # err(X_j) = 1,如果元组X_j被误分类;反之,err(X_j) = 0

    if error(M_i) > 0.5  
        break
    end if
    # 说明这个生成的分类器效果太差,放弃它

    for D 中每个被正确分类的元组 do
        TW_j *= error(M_i) / (1 - error(M_i))
    end for
    # 其实是更新(减小)了每个正确分类的元组的权重,且分类器效果越好,减小幅度越大

    规范化每个元组的权重  
    # 最简单的归一化算法即可
end for


使用组合分类器分类:

    对于待检验的元组x,先假设其对于所有分类的得分都是0  
    # 这里有人用“权重”而不是我说的“得分”,但是我觉得算法中“权重”太多了,用“得分”可能更好理解些

    for i in [1, 2, ..., k] do
       MW_i = log [(1 - error(M_i)) / error(M_i)]  
    end for
    # 符号MW_i为分类器的权重,上面一共生成了k个分类器,每个分类器均对应一个权重       


    return 得分最高的类  # 多数投票原则

通过对上面算法流程的学习,可以观察到,AdaBoost的核心思想在于对于每次没有正确被分类的元组,会在下一次迭代当中被“重点关注”(通过基于元组权重的有放回抽样实现)。这样可以建立出一组“互补”的分类器,使得每个元组都能被尽可能地正确分类。

最后,说一下AdaBoost的缺点。由于关注误分类元组,所以可能导致复合模型对数据过分拟合。这和装袋相比,是一个缺点。但是AdaBoost的优点也是很明显的:在有些情况下,可以获得比装袋更高的准确率。所以具体实现时,也要根据具体情况具体分析。

随机森林

两种基本模式

随机森林,本质上讲就是“决策树+装袋”,当使用决策树作为学习模型时,我们进行 k 轮迭代,每轮通过决策树模型,使用有放回抽样生成的“自助样本”构建分类器,这样一共可以生成 k 棵决策树,就好像一个森林。决策树归纳的相关知识我在之前的博文:决策树归纳中已经有了相对详细的讲解。

随机森林一般情况下有两种最常用的模型:Forest-RI(随机输入选择),Forest-RC(随机线性组合)。我下面简单谈一下。

  1. Forest-RI(随机输入选择):每轮迭代中,构建决策树时,在每个树节点随机选择 F 个属性作为该节点“分裂”的候选属性。我们知道,普通的决策树归纳,在分裂节点时,应该是考虑所有属性并针对每个属性,计算用于选择的标准。比如信息增益,增益率,基尼指数等等,来找到最佳的属性,并确定分裂值。但是随即森林每次却是在可用属性中,随即选择 F 个属性作为候选(当然,为了保证算法是可执行的, F 一般远远小于可用属性数),并且一般采用CART算法来增长树(即采用基尼指数选择分裂属性),树增长到最大规模,且不剪枝。

  2. Forest-RC(随机线性组合):对于属性较少的训练集而言,Forest-RI就显得不可用了。解决办法是Forest-RC,即分裂节点时,首先随机选择 L 个属性,从 [ 1 , 1 ] 中随机选取 L 个数,生成 F 个属性的线性组合,根据这个线性组合和基尼指数找到最佳分裂点。这种随机线性组合是思想是为了降低个体分类器之间的相似度。

效果分析

  1. 随机森林在准确率上与AdaBoost相近,但对于错误和离群点更鲁棒;
  2. 随着森林中树的增加,泛化误差收敛,也能尽量避免过拟合的问题;
  3. 属性选择时,一般 F 的值为 log ( d ) + 1 。考虑较少属性的特点,也为随机森林应用于大型数据库提供了性能方面的优势。

此外,构造随机森林时,应尽量提高个体分类器的能力同时降低它们之间的相关性。

猜你喜欢

转载自blog.csdn.net/guoziqing506/article/details/79980494