Adaboost提升方法

下面的均来自与李航老师的这本书。在这根据自己的理解做下记录。该算法是Adaptive Boosting的缩写,算法思想:
三个臭皮匠,顶个诸葛亮,也就是说对于一个复杂的任务来说,将多个专家的判断进行适当的综合所得出的判断,要
比其中任何一个专家的判断好。从软学习算法出发,反复学习,得到一系列若分类器(基本分类器),然后组合这些
弱分类器,构成一个强分类器(为什么要这样呢?因为对于分类问题而言,给定一个训练样本集,求比较粗糙的分类器
(弱分类器)要比求精确的分类规则(强分类器)容易得多)。大多数的提升方法都是改变训练数据的概率分布
(训练数据的权值分布),针对不同的训练数据分布调用若学习算法学习一系列弱分类器。对于AdaBoost方法,有两个问题:
1、 在每一轮如何改变训练数据的权值或概率分布?提高被前一轮弱分类器错误分类的权值,降低那些被正确分类的权值。
这样一来,那些没有被正确分类的数据,因为权值的加大而受到下一轮的弱分类器更大的关注。于是,分类问题被一系列弱
分类器”分而治之”.2、  如何将弱分类器组合成一个强分类器。采用加权多数表决的方法,具体为:加大分类误差率小的
弱分类器的权值,使其在表决中起较大的作用,减少分类误差率大的弱分类器的权值,使其在表决中起较小的作用。在这算法
原理我就不说了(我自己也没看),讲一个例子,什么都明白了。该例子来自李航的统计学习方法:






经过以上三次的分类后,分类器在训练数据集上误分点就没有了,训练数据集上的误分点个数为0或者弱分类器的数目达到用户指
定的值为止。此时就停止分类所以得出了最终分配率为:G(x)。下面我们用python代码对其进行实现:1、首先我们要有数据,
我们先写一个loadSimData()函数来加载数据,并且返回其分类
2、下面我们根据创建单层决策树函数buildStump(dataArr,classLabels,D).dataArr和classLabels是从loadSimData函数返回的
数据和分类标签。D是一个权重向量,开始值为所有数据的权重相等。这个函数通过一系列的操作,对每一个特征进行遍历,找
到能使错误率最小的那个特征和阈值。并返回这个估计的类别向量bestClassEst,最小错误率minError和最小错误率的单层决策树
bestStump。
3、在这个函数中用到了函数stumpClassify(dataMatrix,dimen,threshVal,threshIneq)这个函数根据数据,特征,阈值,根
据他们,返回一个估计的类别向量,在buildStump函数中用这个类别向量和真正的类别作比较,得出错误率,返回错误率最小的那
个类别向量。上面三个函数的实现:


<pre name="code" class="python"># -*- coding: cp936 -*-

from numpy import *
def loadSimData():
    datMat = matrix([[1.0,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 datMat,classLabels

#用于测试是否有某个值小于或者大于我们正在测试的阈值
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
    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 = {};bestClasEst = 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
                #print("split: dim %d,thresh %.2f,thresh inequal:%s,the weighted error is %0.3f" % (i,threshVal,inequal,weightedError))
                if weightedError < minError:
                    minError = weightedError
                    bestClasEst = predictedVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump,minError,bestClasEst

运行结果:

>>> D = nu.mat(nu.ones((5,1))/5)
>>> D
matrix([[ 0.2],
        [ 0.2],
        [ 0.2],
        [ 0.2],
        [ 0.2]])

>>> datMat,classLabels=adaboost.loadSimData()
>>> adaboost.buildStump(datMat,classLabels,D)
({'dim': 0, 'ineq': 'lt', 'thresh': 1.3}, matrix([[ 0.2]]), array([[-1.],
       [ 1.],
       [-1.],
       [-1.],
       [ 1.]]))

通过以上代码我们就有了一个单层决策树了,也就是一个弱分类器,adaboost的思想是弱弱联合变为强,我们现在就去看看他是怎么变为强的。

1、函数adaBoostTrainDS(dataArr,classLabels,numIt = 40),这个函数中实现了上面的一些公式,计算alpha和向量D,都是实现上面的公式。在这个函数里面,通过迭代,对数据进行分类,知道错误率为0或者达到一定的迭代次数。返回值为每次迭代中的一些值:

函数实现:

#基于单层决策树的AdaBoost训练过程
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
    weakClassArr = []
    aaa = []
    m = shape(dataArr)[0]
    D = mat(ones((m,1))/m)
    aggClassEst = mat(zeros((m,1)))
    for i in range(numIt):
        bestStump,error,classEst = buildStump(dataArr,classLabels,D)
        print("D:",D.T)
        alpha = float(0.5*log((1.0-error)/max(error,1e-16)))
        bestStump['alpha'] = alpha
        weakClassArr.append(bestStump)
        print("classEst:",classEst.T)
        expon = multiply(-1*alpha*mat(classLabels).T,classEst)
        D = multiply(D,exp(expon))
        D = D/D.sum()
        aggClassEst += alpha*classEst#这里求的就是f(x)
        print("aggClassEst: ",aggClassEst.T)
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
        errorRate = aggErrors.sum()/m
        print("total error: ",errorRate,"\n")
        aaa.append(errorRate)
    #print(errorRate/numIt)
        if errorRate == 0.0: break
    #print(mat(aaa).sum()/numIt)
    return weakClassArr

运行结果:

>>> classifierArray = adaboost.adaBoostTrainDS(datMat,classLabels,9)
('D:', matrix([[ 0.2,  0.2,  0.2,  0.2,  0.2]]))
('classEst:', array([[-1.,  1., -1., -1.,  1.]]))
('aggClassEst: ', matrix([[-0.69314718,  0.69314718, -0.69314718, -0.69314718,  0.69314718]]))
('total error: ', 0.20000000000000001, '\n')
('D:', matrix([[ 0.5  ,  0.125,  0.125,  0.125,  0.125]]))
('classEst:', array([[ 1.,  1., -1., -1., -1.]]))
('aggClassEst: ', matrix([[ 0.27980789,  1.66610226, -1.66610226, -1.66610226, -0.27980789]]))
('total error: ', 0.20000000000000001, '\n')
('D:', matrix([[ 0.28571429,  0.07142857,  0.07142857,  0.07142857,  0.5       ]]))
('classEst:', array([[ 1.,  1.,  1.,  1.,  1.]]))
('aggClassEst: ', matrix([[ 1.17568763,  2.56198199, -0.77022252, -0.77022252,  0.61607184]]))
('total error: ', 0.0, '\n')
>>> classifierArray
[{'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}]
>>> 

上面就是一个adaboost分类算法,我们下面对这个算法进行测试:

#弱分类器有了,我们现在就可以使用这些弱分类器构造一个AdaBoost分类函数
def adaClassify(datToClass,classifierArr):
    dataMatrix = mat(datToClass)
    #print(dataMatrix)
    m = shape(dataMatrix)[0]
    aggClassEst = mat(zeros((m,1)))
    for i in range(len(classifierArr)):
        classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],\
                                 classifierArr[i]['thresh'],\
                                 classifierArr[i]['ineq'])
        aggClassEst += classifierArr[i]['alpha']*classEst
        #print("mxt:" ,classifierArr[i]['alpha'])
        print(aggClassEst)
    return sign(aggClassEst)
代码运行:

>>> adaboost.adaClassify([[5,5],[0,0]],classifierArr)
[[ 0.69314718]
 [-0.69314718]]
[[ 1.66610226]
 [-1.66610226]]
[[ 2.56198199]
 [-2.56198199]]
matrix([[ 1.],
        [-1.]])
>>> 

示例:在一个难数据集上的应用Adaboost。

函数loadDataSet函数是一个自适应数据加载函数,他通过加载文件中的数据,返回dataMat和labelMat,在这个数据文件中的每一条数据的前面是特征,最后一条是类别

#示例:在一个难数据集上应用AdaBoost
def loadDataSet(filename):
    numFeat = len(open(filename).readline().split('\t'))
    dataMat = [];labelMat = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat-1):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat

运行代码:

 reload(adaboost)
<module 'adaboost' from 'C:\Python27\adaboost.py'>
>>> datArr,labelArr = adaboost.loadDataSet('horseColicTraining2.txt')
>>> classifierArray = adaboost.adaBoostTrainDS(datArr,labelArr,10)
('total error: ', 0.28428093645484948, '\n')
('total error: ', 0.28428093645484948, '\n')
('total error: ', 0.24749163879598662, '\n')
('total error: ', 0.24749163879598662, '\n')
('total error: ', 0.25418060200668896, '\n')
('total error: ', 0.24080267558528429, '\n')
('total error: ', 0.24080267558528429, '\n')
('total error: ', 0.22073578595317725, '\n')
('total error: ', 0.24749163879598662, '\n')
('total error: ', 0.23076923076923078, '\n')
>>> testArr,testLabelArr = adaboost.loadDataSet('horseColicTest2.txt')
>>> prediction10 = adaboost.adaClassify(testArr,classifierArray)<pre name="code" class="python">>>> len(prediction10)
67
>>> errArr = nu.mat(nu.ones((len(prediction),1)))
>>> errArr[prediction10 != nu.mat(testLabelArr).T].sum()
16.0 #测试错误的个数,错误率为16//67
>>> 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值