《机器学习实战》学习笔记:利用Adaboost元算法提高分类性能

一. 关于boosting算法的起源

boost 算法系列的起源来自于PAC Learnability(直译过来称为:PAC 可学习性)。这套理论主要研究的是什么时候一个问题是可被学习的。

我们知道,可计算性在计算理论中已经有定义,而可学习性正是PAC Learnability理论所要定义的内容。另外,在计算理论中还有很大一部分精力花在研究问题是可计算的时候,其复杂度又是什么样的。因此,在计算学习理论中,也有研究可学习的问题的复杂度的内容,主要是样本复杂度 (Sample Complexity) 。

最后,在可计算的时候,得到实现计算的具体算法也是计算理论中的一个重要部分;而更多的在“机器学习”这个领域中,我们往往会探讨针对可学习的问题的具体的学习算法。

听起来很复杂,简而言之,就是:PAC 模型的作用相当于提供了一套严格的形式化语言来陈述以及刻画这里所提及的可学习性 Learnability 以及(样本)复杂度 (Sample) Complexity 问题。

这套理论是由Valiant提出来的,作者曾获得了2010年的图灵奖。

《机器学习实战》学习笔记:利用Adaboost元算法提高分类性能_第1张图片

PAC 定义了学习算法的强弱:

弱学习算法:识别错误率小于1/2(即准确率仅比随机猜测略高的学习算法);
强学习算法:识别准确率很高并能在多项式时间内完成的学习算法。

更为严格的定义:

弱学习算法:一个概念如果存在一个多项式的学习算法能够学习它,并且学习的正确率仅比随机猜测略好(高于50%),那么,这个概念是弱可学习的;

强学习算法:一个概念如果存在一个多项式的学习算法能够学习它,并且正确率很高,那么,这个概念是强可学习的。

同时 ,Valiant和Kearns还提出了PAC学习模型中弱学习算法和强学习算法的等价性问题,即任意给定仅比随机猜测略好的弱学习算法 ,是否可以将其提升为强学习算法 ? 如果弱学习算法和强学习算法二者等价 ,那么只需找到一个比随机猜测略好的弱学习算法就可以将其提升为强学习算法 ,而不必寻找很难获得的强学习算法。 也就是这种猜测,让无数研究人员去设计算法来验证PAC理论的正确性。

不过很长一段时间都没有一个切实可行的办法来实现这个理想。细节决定成败,再好的理论也需要有效的算法来执行。终于功夫不负有心人, Schapire在1996年提出一个有效的算法真正实现了这个夙愿,它的名字叫AdaBoost。AdaBoost把多个不同的决策树用一种非随机的方式组合起来,表现出惊人的性能和优点:

  1. 把决策树的准确率大大提高,可以与SVM媲美;
  2. 当使用简单分类器时,计算出的结果是可以理解的。而且弱分类器构造极其简单
  3. 速度快,且基本不用调参数;
  4. 简单,无需做特征筛选;
  5. 不用担心Overfitting。

“我估计当时Breiman和Friedman肯定高兴坏了,因为眼看着他们提出的CART正在被SVM比下去的时候,AdaBoost让决策树起死回生!Breiman情不自禁地在他的论文里赞扬AdaBoost是最好的现货方法(off-the-shelf,即“拿下了就可以用”的意思)。”(这段话摘自统计学习那些事)

二. 基于数据集多重抽样的分类器

前面我们已经尝试设计多种分类器,如果我们尝试将不同的分类器组合在一起,这种组合的结果就是集成方法(或称为元算法)。使用集成方法时会有多种形式,它可以是不同算法的集成,也可以是同一算法在不同设置下的集成,还可以是数据集的不同部分分配给不同分类器后的集成。通常的集成方法有bagging方法和boosting方法。

1.bagging:基于数据随机重抽样的分类器构建方法

bagging方法,又称为自举汇聚法(bootstrap aggregating),是在从原始数据集重选择(有放回,可以重复)得到S个新数据集的一种技术,新数据集与原数据集大小相等,每个数据集都是通过在原始数据集中随机选择一个样本来进行替换而得到。

建立好S个新数据集后,将某个学习算法分别作用于每一个数据集,就得到S个分类器。对这S个分类器进行叠加,他们的权重都相等(当然这里S个分类器采用的分类算法不一样的话,可以考虑使用投票),这样就可以得到一个强学习器。

以下给出bagging方法的主要步骤:

  1. 重复地从一个样本集合D中采样n个样本
  2. 针对每次采样的子样本集,进行统计学习,获得假设Hi
  3. 将若干个假设进行组合,形成最终的假设Hfinal
  4. 将最终的假设用于具体的分类任务

2.boosting方法

书中给出以下解释:boosting是一种与bagging很类似的技术。不论是在boosting还是bagging方法中,所使用的多个分类器的类型都是一致的。不同的是,bagging方法通过串行训练获得不同的分类器,每个新分类器都根据以训练出的分类器性能来进行训练;boosting则是通过集中关注被已有分类器错分的那些数据来获得新的分类器。

boosting方法的分类结果是基于所有分类器的加权求和结果,每个分类结果的权重并不相等,每个权重代表的是其对应分类器在上一轮迭代中的成功度。

boosting方法拥有多个版本,Adaboost就是属于其中一种。

三. Adaboost:基于错误提升分类器的性能

Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器,即弱分类器,然后把这些弱分类器集合起来,构造一个更强的最终分类器,比起弱分类器,这个“强”分类器的错误率会低很多。

Adaboost算法本身是改变数据分布实现的,它根据每次训练集之中的每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改权值的新数据送给下层分类器进行训练,然后将每次训练得到的分类器融合起来,作为最后的决策分类器。以下给出 Adaboost算法的运行过程:

  1. 训练数据中的每个样本,并赋予其一个权重,这些权重构成向量D,一开始时权重D初始化为相等的值;
  2. 先在训练样本上训练得到第一个弱分类器并计算分类器的错误率
  3. 在同一数据集上再次训练弱分类器,在分类器的二次训练中,会重新调整每个样本的权重,其中第一次分类正确的样本的权重将会降低,而分类错误的样本权重将会提高 ;
  4. 为了从所有弱分类器中得到最终的分类结果,Adaboost为每个分类器都分配了一个权重值alpha,这一组值是基于每个弱分类器的错误率进行计算的。

其中,错误率由以下公式定义:

这里写图片描述

而alpha的计算公式如下:

这里写图片描述

Adaboost算法的流程图如下:

《机器学习实战》学习笔记:利用Adaboost元算法提高分类性能_第2张图片

图中的左边表示数据集,其中直方图的不同宽度表示每个样例上的不同权重。在经过一个分类器之后,加权的预测结果会通过三角形中的alpha值进行加权,每个三角形中输出的加权结果在圆形中求和,从而得到最终的输出结果。

计算出alpha值后,可以对权重向量D进行更新,使得那些正确分类的样本的权重降低而错分样本的权重升高。计算方法如下:

对于正确分类的样本,其权重更改为:

这里写图片描述

对于错误分类的样本,其权重更改为:

这里写图片描述

在计算出权重向量D后,Adaboost方法开始进入下一轮的迭代。Adaboost方法会不断地重复训练和调整权重的过程,知道训练错误率为0(或达到用户指定的条件)为止。

一个博客给出一种容易理解的解释:Adaboost的训练过程有如一个学生学习的过程:我们把每个训练样例看做一道练习题,所有的训练样本看做一本习题集。第一次做题的时候,由于每道题都没有做过,不知道哪些难哪些简单,所以一视同仁,做完了对照答案,可能会有很多题目做的不对,那么对于做错的题目,我们就重点标记,给予更高的重视程度,这个用权重w来标示,到第二轮做题的时候就重视这些没做对的“难题”,对于第一次就做对的题目,可以认为是比较简单的,那么第二次的时候稍微看下就可以了,可以降低他的权重。并且,对于第一轮做完以后的效果给一个整体的评分,评价这轮做题的能力,这个就是alpha。在第二轮做题的时候,就按照上一轮调整过的权重对不同的题目给予不同的重视程度和时间分配。如此不断练习,几轮下来,难题就逐渐被攻克了。每轮做题都是有收获的,只不过每次收获的知识权重不同(alpha),这样,我们最后就得到m个分类器,综合每个分类器的权重,我们就能得到一个“学习成绩很好”的分类器了。

四. 基于单层决策树构建分类器

使用Python实现:

def loadSimDat():
    dataMat = matrix([[1, 2.1],
                      [2.0, 1.1],
                      [1.3, 1.0],
                      [1.0, 1.0],
                      [2.0, 1.0]])
    classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
    return dataMat, classLabels

# 单层决策树生成函数
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):#just classify the data
    retArray = ones((shape(dataMatrix)[0],1))
    if threshIneq == 'lt':
        retArray[dataMatrix[:,dimen] <= threshVal] = -1.0
    else:
        retArray[dataMatrix[:,dimen] > threshVal] = -1.0
    return retArray


def buildStump(dataArr, classLabels, D):
    dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
    m,n = shape(dataMatrix)
    numSteps = 10.0; bestStump = {}; bestClassEst = mat(zeros((m,1)))
    minError = inf
    for i in range(n):
        rangeMin = dataMatrix[:,i].min(); rangeMax = dataMatrix[:,i].max();
        stepSize = (rangeMax - rangeMin)/numSteps
        for j in range(-1, int(numSteps)+1):
            for inequal in ['lt','gt']:
                threshVal = (rangeMin + float(j)*stepSize)
                predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)
                errArr = mat(ones((m,1)))
                errArr[predictedVals == labelMat] = 0
                weightedError = D.T * errArr           #这里的error是错误向量errArr和权重向量D的相应元素相乘得到的即加权错误率
                #print "split: dim %d, thresh %.2f, thresh inequal: %s, the weighted error is %.3f" %(i, threshVal, inequal, weightedError)
                if weightedError < minError:
                    minError = weightedError
                    bestClassEst = predictedVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump, minError, bestClassEst

下一节将应用Adaboost算法,处理非均衡的分类问题。

参考链接:
http://blog.csdn.net/lu597203933/article/details/38666303
http://blog.csdn.net/lskyne/article/details/8425507

你可能感兴趣的:(模式识别与机器学习,Python,《机器学习实战》笔记)