python机器学习之adaboost元算法

本文深入探讨Adaboost元算法,一种通过组合多个弱分类器以提高预测精度的方法。Adaboost通过调整样本权重,重点关注错误分类的数据,训练一系列弱分类器并加权求和得到最终分类结果。文章还展示了使用单层决策树作为弱分类器的代码实现,并通过马疝病数据集的实际应用,分析了不同弱分类器数量对训练和测试错误率的影响,揭示了过拟合现象以及如何选择合适的弱分类器个数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在做一些决定的时候,我们往往需要吸取多个专家的意见,这就是元算法背后的思路,这里的专家就相当于前几个博文的分类器一样,结合多个分类器的结果得出的结果往往比单一一个分类器的结果要精准一些。

adaboost是boosting方法多个版本中最流行的一个版本,它是通过构建多个弱分类器,通过各个分类器的结果加权之后得到分类结果的。这里构建多个分类器的过程也是有讲究的,通过关注之前构建的分类器错分的那些数据而获得新的分类器。这样的多个分类器在训练时很容易得到收敛。

本文主要介绍了通过单层决策树构建弱分类器,同理,也可以用其他的分类算法构建弱分类器。

adaboost全称是adaptive boosting(自适应boosting),为什么是自适应呢,首先,先介绍一下它的原理:首先,对训练数据中每一个样本附上一个权重,这些权重构成向量D,一开始给这些权重初始化为相同的值。第一次训练时,权重相同,和原先的训练方法一样,训练结束后,根据训练的错误率,重新分配权重,第一次分对的样本的权重会降低,分错的样本权重会增大,这样再对第二个分类器进行训练,每一个分类器都对应一个alpha权重值,这里的alpha是对于分类器而言,前面的D是对于样本而言。最后训练出一系列的弱分类器,对每一个分类器的结果乘以权重值alpha再求和,就是最终的分类结果。自适应就体现在这里,通过对D的一次次的优化,最后的结果往往可以快速收敛。

这里错误率的定义如下:


alpha定义如下:


权重D的更新函数如下:

这里分为两种情况

1.该样本被正确分类:




2.该样本没有被正确分类:


这里的i代表的是第i个样本,t代表的是第t次训练。

下面介绍基于单层决策树构建弱分类器的代码实现:

首先加载训练数据

def loadSimpData():
    datMat = 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 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=dataArr[:,i].min()
        rangeMax=dataArr[:,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 ineqal: %s, the weighted error is %.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

上面是建立一个单层决策树的函数,为了实现adaboost,我们需要根据决策结果构建一系列的弱分类器,函数如下:

def adaBoostTrainDS(dataArr,classLabels,numIt=40):
    weakClassArr = []
    m = shape(dataArr)[0]
    D = mat(ones((m,1))/m)   #初始化矩阵D,为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)))#计算alpha,max项是为了防止error为0
        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()#计算D
        
        aggClassEst += alpha*classEst#计算累积错误率
        print "aggClassEst: ",aggClassEst.T
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
        errorRate = aggErrors.sum()/m
        print "total error: ",errorRate
        if errorRate == 0.0: break
    return weakClassArr,aggClassEst


这样,就构建好了多个弱分类器。

分类函数如下:

def adaClassify(datToClass,classifierArr):#adaboost分类函数
    dataMatrix = mat(datToClass)
    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 aggClassEst
    return sign(aggClassEst)

下面,我随机生成了500组数据对分类进行测试,并通过pylab库对结果进行可视化

def test():#测试函数,随机生成100组测试样本,进行分类测试
    datMat,classLabels=loadSimpData()
    xMax=datMat[:,0].max()+1
    xMin=datMat[:,0].min()-1
    yMax=datMat[:,1].max()+1
    yMin=datMat[:,1].min()-1
    pl.xlim((xMin,xMax))
    pl.ylim((yMin,yMax))
    weakClassArr,aggClassEst=adaBoostTrainDS(datMat,classLabels,9)
    m=shape(datMat)[0]
    
    for i in range(m):
        if classLabels[i]==1.0:
            pl.plot(array(datMat[i])[0][0],array(datMat[i])[0][1],'ro')
        else:
            pl.plot(array(datMat[i])[0][0],array(datMat[i])[0][1],'r*')
    testdata=[]
    #testdata.append([5,5])
    for i in range(100):
        testdata.append(list(2*random.random(2)))
    classResult=adaClassify(testdata,weakClassArr)
    m=shape(testdata)[0]
    for i in range(m):
        if classResult[i]==1.0:
            pl.plot(testdata[i][0],testdata[i][1],'bo')
        else:
            pl.plot(testdata[i][0],testdata[i][1],'b*')
    print classResult
    pl.show()



红色是训练数据,只有5个点,可以通过测试结果大致看出分类的间隔。

下面给出一个根据adaboost元算法的一个实际应用的例子,通过在给出的马疝病数据集,训练分类器,最后来预测患有马疝病的马是否能存活。这个例子在书中的logistic回归中进行预测过,那里的平均错误率为35%,那么我们看看这里用adaboost元算法的错误率是多少。

首先给出将txt文本转换为训练矩阵的函数:

def loadDataSet(fileName):      #将txt文本转换为训练矩阵
    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

训练函数如下:

def testHorse():
    dataMat,labelMat=loadDataSet('horseColicTraining2.txt')
    weakClassArr,aggClassEst,listErrRate=adaBoostTrainDS(dataMat,labelMat,100)
    n=len(listErrRate)
    x=range(n)
    pl.plot(x,listErrRate)
    pl.show()
    print listErrRate


上图反映了采用不同弱分类器数目的训练错误率,可见,弱分类器越多,训练错误率总体是减少的,下面我们看看不同的弱分类器,测试错误率怎么样。

def testHorse2():
    dataMat,labelMat=loadDataSet('horseColicTraining2.txt')
    count=[1,10,50,100,300,500,700]
    testArr,testLabel=loadDataSet('horseColicTest2.txt')
    errRate=[]
    for i in count:
        weakClassArr,aggClassEst,listErrRate=adaBoostTrainDS(dataMat,labelMat,i)
        predict=adaClassify(testArr,weakClassArr)
        errArr=mat(ones((67,1)))
        errnum=errArr[predict!=mat(testLabel).T].sum()
        errRate.append(errnum/67.0)
    pl.plot(count,errRate)
    pl.show()
    print errRate


如图所示,显示了不同的弱分类器个数对应的测试识别率,结合之前的训练识别率,可以看出来,并不是弱分类器个数越多,识别效果越好,而是在弱分类器个数为50个左右有一个极小值。之后的错误率上升也就是过拟合的情况了。所以在实际应用中,应根据不同的情况选择不同的弱分类器个数。不难发现,adaboost算法的测试错误率可以达到0.21左右,对于采用logistic回归对本例的预测而言,识别效果确实好上很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值