基于Python的机器学习实战:AadBoost

转载 2015年11月17日 22:40:32

http://www.cnblogs.com/90zeng/p/adaboost.html

目录:

1. Boosting方法的简介

2. AdaBoost算法

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

4.完整的AdaBoost的算法实现

5.总结

1. Boosting方法的简介 返回目录

Boosting方法的基本思想:对于一个复杂的任务来说,将多个专家的判断进行适当的综合所得出的判断,要比其中任何一个专家单独的判断好. 实际上就是“三个臭皮匠顶个诸葛亮的道理。”(参考:李航 《统计学习方法》)

对于分类问题而言, 给定一个训练集,求比较粗糙的分类规则(弱分类器)要比求精确的分类规则(强分类器)容易得多。Boosting方法就是从弱学习算法出发,反复学习,得到一系列弱分类器(又称基本分类器),然后组合这些弱分类器,构成一个强分类器。

对于Boosting方法来说,需要回答两个问题:

  • 每一轮如何改变训练数据的权值或者概率分布
  • 如何将若分类器组合成一个强分类器

2. AdaBoost算法 返回目录

boosting 方法拥有多个版本,其中最流行的一个版本就是AdaBoost,即adaptive boosting.

对与上面提到的两个问题,AdaBoost的做法分别是:

  • 对于第一个问题:提高那些被前一轮弱分类器错误分类的样本的权值,而降低那些被正确分类样本的权值.
  • 对于第二个问题:采取加权多数表决的方法,具体就是,加大分类误差率较小的弱分类器的权值,使其在表决中起较大的作用,减小分类误差率大的弱分类器的权值,使其在表决中起较小的作用.

具体算法流程描述如下:

假定给定一个二分类的训练数据集

T={(x1,y1),(x2,y2),,(xN,yN)}

其中,每个样本点由实例与标记组成. 实例 xiXRn ,标记 yiYRn, X 是实例空间,Y 是标记集合. 

输入:训练数据集 T={(x1,y1),(x2,y2),,(xN,yN)},其中 xiXRn, yiY={1,+1};弱分类器;

输出:最终分类器 G(x).

(1) 初始化训练数据的权值分布

D1={w11,,w1i,,w1N},w1N=1N,i=1,2,,N

初始化的时候让每个训练样本在基本分类器的学习中作用相同

(2) 对 m=1,2,,M

(a) 使用具有权值分布 Dm 的训练数据学习,得到基本分类器

Gm(x):X{1,+1}

(b) 计算 Gm(x) 在训练数据集上的分类误差

em=P(Gm(xi)yi)=Ni=1wmiI(Gm(xi)yi) (1)

(c) 计算 Gm(x) 的系数

αm=12log1emem (2)

这里对数是自然对数. αm 表示 Gm(x) 在最终分类器中的重要性,由该式可知,当 em12时,αm0,并且 αm 随着 em 的减小而增大,所以误差率越小的基本分类器在最终分类器中的作用越大.

(d) 更新训练数据集的权值分布

Dm+1={wm+1,1,,wm+1,i,,wm+1,N} (3)

wm+1,i=wmiZmexp(αmyiGm(xi)),i=1,2,,N (4)

这里 Zm 是归一化因子.

Zm=Ni=1wmiexp(αmyiGm(xi))

它使 Dm+1 成为一个概率分布. 式 (4) 还可以写成:

wm+1,i=wmiZmeαm,Gm(xi)=yiwmiZmeαm,Gm(xi)yi

由此可知,被基本分类器 Gm(x) 误分类样本的权值得以扩大,而被正确分类样本的权值却得以缩小,因此误分类样本在下一轮学习中起更大作用.

(3) 构建基本分类器的线性组合

f(x)=Ni=1αmGm(x)

得到最终分类器

G(x)=sign(f(x))=sign(Mm=1αmGm(x))

线性组合 f(x) 实现 M 个基本分类器的加权表决. f(x) 的符号决定了实例 x 的类别,f(x) 的绝对值表示分类的确信度.

3.基于单层决策树构建弱分类器 返回目录

所谓单层决策树(decision stump, 也称决策树桩)就是基于简单的单个特征来做决策,由于这棵树只有一次分裂过程,因此实际上就是一个树桩。

首先通过一个简单的数据集来确保在算法实现上一切就绪.

复制代码
def loadSimpData():
    dataMat = np.matrix( [ [ 1., 2.1],
                           [ 2., 1.1],
                           [ 1.3, 1.],
                           [ 1., 1. ],
                           [ 2., 1. ] ] )
    classLabels = [ 1.0, 1.0, -1.0, -1.0, 1.0 ]                           
    return dataMat, classLabels
复制代码

 

下图给出了上面数据集的示意图

 

如果使用上面所述的单层决策树来对上面的样本点进行分类,即试着从某个坐标轴选择一个值(选择一条与坐标轴平行的直线)来将所有蓝色样本和褐色样本分开,这显然不可能。但是使用多棵单层决策树,就可以构建出一个能对该数据集完全正确的分类器.

首先给出单层决策树生成函数

复制代码
def stumpClassify( dataMatrix, dimen, threshVal, threshIneq ):
    '''
    通过阈值比较对数据进行分类,所有在阈值一边的数据会分到类别-1,而在
    另外一边的数据分到类别+1.    
    '''
    retArray = np.ones( ( np.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 = np.mat(dataArr)
    labelMat = np.mat(classLabels).T
    m,n = np.shape(dataMatrix)
    numSteps = 10.0 #用于在特征的所有可能值上进行遍历
    bestStump = {} #存储给定权重向量 D 时所得到的最佳单层决策树的信息
    bestClassEst = np.mat( np.zeros( (m, 1) ) )
    minError = np.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 = np.mat( np.ones( ( m, 1 ) ) )
                errArr[ predictedVals == labelMat ] = 0
                weightedError = D.T * errArr
#                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
复制代码

 

上面两个函数作用是对于给定的数据集选出最佳的单层决策树.

4.完整的AdaBoost的算法实现 返回目录

下面给出完整的AdaBoost的算法实现

复制代码
def adaBoostTrainDS( dataArr, classLabels, numIt = 40 ):
    '''
    基于单层决策树的AdaBoost训练过程    
    '''
    weakClfArr = []
    m = np.shape( dataArr )[ 0 ]
    D = np.mat( np.ones( ( m, 1 ) ) / m )
    aggClassEst = np.mat( np.zeros( ( m, 1 ) ) )
    for i in range( numIt ):
        # 每一次循环 只有样本的权值分布 D 发生变化
        bestStump, error, classEst = buildStump( dataArr, classLabels, D )
        print " D: ", D.T
        
        # 计算弱分类器的权重
        alpha = float( 0.5 * np.log( ( 1 - error ) / max( error, 1e-16 ) ) )
        bestStump[ 'alpha' ] = alpha
        weakClfArr.append( bestStump )
        print "classEst: ", classEst.T
        
        # 更新训练数据集的权值分布
        expon = np.multiply( -1 * alpha * np.mat( classLabels ).T, classEst )
        D = np.multiply( D, np.exp( expon ) )
        D = D / D.sum()
        
        # 记录对每个样本点的类别估计的累积值
        aggClassEst += alpha * classEst
        print "aggClassEst: ", aggClassEst.T
        
        # 计算分类错误率
        aggErrors = np.multiply( np.sign(aggClassEst) != 
            np.mat( classLabels ).T, np.ones( ( m, 1 ) ) )
        errorRate = aggErrors.sum() / m
        print "total error: ", errorRate, "\n"
        
        # 如果完全正确,终止迭代
        if errorRate == 0.0:
            break
    return weakClfArr
    
if __name__ == '__main__':
    print __doc__
    datMat, classLabels = loadSimpData()
#    plt.scatter(datMat[:, 0], datMat[:, 1], c=classLabels, markers=classLabels, s=200, cmap=plt.cm.Paired)
    print adaBoostTrainDS( datMat, classLabels, 9 )
复制代码

 

 

运行结果

 

复制代码
 D:  [[ 0.2  0.2  0.2  0.2  0.2]]
classEst:  [[-1.  1. -1. -1.  1.]]
aggClassEst:  [[-0.69314718  0.69314718 -0.69314718 -0.69314718  0.69314718]]
total error:  0.2 

 D:  [[ 0.5    0.125  0.125  0.125  0.125]]
classEst:  [[ 1.  1. -1. -1. -1.]]
aggClassEst:  [[ 0.27980789  1.66610226 -1.66610226 -1.66610226 -0.27980789]]
total error:  0.2 

 D:  [[ 0.28571429  0.07142857  0.07142857  0.07142857  0.5       ]]
classEst:  [[ 1.  1.  1.  1.  1.]]
aggClassEst:  [[ 1.17568763  2.56198199 -0.77022252 -0.77022252  0.61607184]]
total error:  0.0 

[{'dim': 0, 'ineq': 'lt', 'thresh': 1.3, 'alpha': 0.6931471805599453}, {'dim': 1, 'ineq': 'lt', 'thresh': 1.0, 'alpha': 0.9729550745276565}, {'dim': 0, 'ineq': 'lt', 'thresh': 0.90000000000000002, 'alpha': 0.8958797346140273}]
复制代码

 

 

可以看到错误率逐步被降到 0.0, 最终的分类器包含 3 个基本分类器.

下面基于AdaBoost进行分类,需要做的就只是将弱分类器的训练过程从程序中抽取出来,然后应用到某个具体实例上去。每个弱分类器的结果以其对应的 alpha 值作为权值. 所有这些弱分类器的结果加权求和就得到了最后的结果.

AdaBoost分类函数

adaClassify

 

测试

复制代码
if __name__ == '__main__':
    print __doc__
    datMat, classLabels = loadSimpData()
#    plt.scatter(datMat[:, 0], datMat[:, 1], c=classLabels, markers=classLabels, s=200, cmap=plt.cm.Paired)
    classifierArr = adaBoostTrainDS( datMat, classLabels, 9 )
    print adaClassify( [ 0, 0 ], classifierArr )
复制代码

 

测试结果

[[-0.69314718]]
[[-1.66610226]]
[[-2.56198199]]
[[-1.]]

 

可以发现,随着迭代进行,数据点 [0,0] 的分类确信度越来越强.

5.总结 返回目录

AdaBoost的优点:泛化错误率低,可以用在大部分分类器上,无参数调整(自适应).

缺点:对离群点敏感.

相关文章推荐

机器学习 鲁棒的基于高斯概率密度的异常点检测(novelty detection) ellipticalenvelope算法

异常点检测分为novelty detection 与 outlier detection鲁棒性的高斯概率密度是novelty detection, 就是在给出的数据中, 找出一些与大部分数据偏离较远的...

主成分分析法及特征值的含义

主成分分析法是一种非常适用,又相对简单的数据处理的方法。它是利用降维的方法,将数据表示的信息的主要成分提取出来,所以叫做主成分分析法。  从它的作用可以看出来,它的运用非常的广泛:  1. ...

Python2《机器学习实战》及源代码

  • 2017年10月28日 21:44
  • 44.07MB
  • 下载

python3实现《机器学习实战》遇到的问题:range函数

最近在看学习《机器学习实战》这本书。这本书上用的python2的语法,和python3的语法不太一样。由于本人python小白,看了python3的语法,准备自己实现一下代码,遇到了一些问题,故开贴记...
  • cjbct
  • cjbct
  • 2017年05月24日 09:19
  • 683

python机器学习实战 书籍+源码

  • 2017年05月16日 10:58
  • 40.7MB
  • 下载

基于Python的机器学习实战:Apriori

1.关联分析   关联分析是一种在大规模数据集中寻找有趣关系的任务。这种关系表现为两种形式: 1.频繁项集(frequency item sets):经常同时出现的一些元素的集合; ...

免费 机器学习实战 Python实现.pdf

  • 2017年08月16日 13:35
  • 9.83MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于Python的机器学习实战:AadBoost
举报原因:
原因补充:

(最多只允许输入30个字)