《机器学习实战》代码片段学习5 AdaBoost元算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/s291547/article/details/77842748

svm那一章看的太吃力…先缓缓,回头再收拾它(

简介

基于同一分类器多个不同实例的两种计算方法:bagging与boosting

Bagging:从原始数据集选择S次后得到S个新数据集的一种技术,将某个学习算法串行作用于每个数据集就得到了S个分类器。对新数据进行分类时,用这S个分类器进行分类,并选择分类器投票结果中最多的类别作为最后的分类结果。

Boosting:关注被已有分类器错分的数据来获取新的分类器。分类结果为基于所有分类器的结果进行加权求和。

Adaboost是boosting方法中最为流行的一个版本。

AdaBoost优缺点:
优点:泛化错误率低,易编码,可以应用在大部分分类器上,无参数调整。
缺点:对离群点敏感。
适用数据类型:数值型和标称型数据。

例子中使用的分类器是单层决策树。
单层决策树:仅基于单个特征做分类,只有一次分裂过程(树桩)

数学基础

分类器错误率定义:
这里写图片描述

分类器每次迭代后的权重alpha计算:
这里写图片描述

分类器每次迭代后样本权重的更新:
如果某个样本被正确分类,那么该样本的权重更改为:
这里写图片描述

而如果某个样本被错分,那么该样本的权重更改为:
这里写图片描述

Adaboost算法流程图:
这里写图片描述

代码学习

首先先把作为分类器的单层决策树弄起来。

单层决策树伪代码:

将最小错误率minError设为+∞  
对数据集中的每一个特征(第一层循环):  
    对每个步长(第二层循环):  
      对每个不等号(第三层循环):  
         建立一棵单层决策树并利用加权数据集对它进行测试  
        如果错误率低于minError,则将当前单层决策树设为最佳单层决策树  
返回最佳单层决策树

单层决策树生成函数:

#分类函数,通过数组过滤实现
#传入的参数分别为:dataMatrix数据矩阵,dimen特征类型(维度),threshVal用于作为分类标准的阈值,由(特征值最小值+步长)获得,threshIneq不等号
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
    retArray = ones((shape(dataMatrix)[0],1))  #用于记录dimen特征类型的分类结果
    if threshIneq == 'lt':  #若不等号为<
        retArray[dataMatrix[:,dimen] <= threshVal] = -1.0  #将特征值小于threshVal的置为-1
    else:  #若不等号为>
        retArray[dataMatrix[:,dimen] > threshVal] = -1.0  #将特征值大于threshVal的置为-1
    return retArray

#遍历所有能传给stumpClassify()的数据组合,在其寻找最佳的单层决策树
#传入参数:dataArr数据样本,classLabels数据样本分类结果数组,D为初始权重向量
def buildStump(dataArr,classLabels,D):
    #数组转为numpy矩阵
    dataMatrix = mat(dataArr); labelMat = mat(classLabels).T #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)

                #以threshVal作为标准进行分类
                predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal) 

                errArr = mat(ones((m,1)))  #记录错误情况的列向量
                errArr[predictedVals == labelMat] = 0  #分类结果正确的记为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  #更新最好的作为分类标准的threshVal值
                    bestStump['ineq'] = inequal  #更新最好的用于分类的不等号
    return bestStump,minError,bestClasEst  #返回带有最好单层决策树的字典、错误率,分类结果(类别估计值)

有了单层决策树后,我们就可以实现一个完整的adaboost算法了。

完整adaboost算法伪代码:

对每次迭代:
    利用buildStump()函数找到最佳的单层决策树   
    将最佳单层决策树加入到单层决策树数组 
    计算alpha   
    计算新的权重向量D 
    更新累计类别估计值  
如果错误率等于0.0,则退出循环

基于单层决策树的AdaBoost训练过程,DS代表单层决策树:

#输入参数:dataArr数据样本数组,classLabels样本分类结果数组,numIt迭代次数
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
    weakClassArr = []  #弱分类器的分类结果,是一个二维数组
    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)
        #根据分类错误率计算分类器权重alpha
        alpha = float(0.5*log((1.0-error)/max(error,1e-16)))  
        bestStump['alpha'] = alpha  #字典中加入权重
        weakClassArr.append(bestStump)  #记录最好的分类结果

        #(以下三行)更新样本权重D
        expon = multiply(-1*alpha*mat(classLabels).T,classEst)
        D = multiply(D,exp(expon))  
        D = D/D.sum()

        aggClassEst += alpha*classEst  #累计值
        #记录每个特征错误情况的数组aggErrors,sign(n)获取二值分类结果,若n大于0返回1.0,若小于0返回-1.0,若等于0返回0.0
        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

拥有了复数的分类器与对应的alpha值,我们就可以进行分类操作了。

AdaBoost分类函数:

#输入参数:datToClass待分类数据,classifierArr多个弱分类器组成的数组
def adaClassify(datToClass,classifierArr):
    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)

总结

通常情况下,AdaBoost会得到一个稳定的测试错误率,而不会随着分类器数目增多而提高。但有时候也会发生过拟合现象。

“本章以单层决策树作为弱学习器构建了AdaBoost分类器。实际上,AdaBoost函数可以应用于任意分类器,只要该分类器能够处理加权数据即可。AdaBoost算法十分强大,它能够快速处理其他分类器很难处理的数据集。”

猜你喜欢

转载自blog.csdn.net/s291547/article/details/77842748