AdaBoost(自适应增强算法)

Posted Qunar_尤雪萍

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AdaBoost(自适应增强算法)相关的知识,希望对你有一定的参考价值。

AdaBoost(自适应增强算法)

AdaBoost的目标是通过一个弱分类器构建一个强分类器,AdaBoost的大致运行过程:训练数据中的每一个样本,并赋予其一个权重,形成对应的权重向量 D ,一开始所有训练样本具有相同权值,然后使用弱分类器分类并计算出该分类器的错误率,然后再统一数据集上面再次训练弱分类器,在第二次训练中,将会调整每个样本的权值,其中第一次分队的样本的权重将会降低,第一次分错的样本权重将会提高。最终我们能得到一组分类器,通过,并且根据最终每个分类器的错误率为每个分类器赋予一个权重值alpha, alpha 公式如下:

α=12ln(1ϵϵ)1 ,当 alpha 得到后我们对权重向量 D 进行更新,使得正确分类的样本权值降低,错分样本权重升高,计算方法如下:如果某个样本被正确分类则权重值更改为:D(t+1)i=D(t)ieαSum(D)2,如果某个样本被错分,那么样本的权重更改为: D(t+1)i=D(t)ieαSum(D)3 ,通过不断的训练和调整权重产生新的分类器,知道训练错误率为0或者达到指定值为止。

通过单层决策树构建弱分类器

单层决策树是一种简单的决策树,不像之前的介绍的决策树,它只会做一层分裂,例如判断数值大于指定值时归类到class1,否则归类到class2。
构建一个简单的数据集:

dataMat = 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]


AdaBoost需要构建多个单层决策树,多个决策树组合起来实现正确的对数据集进行分类。
单层决策树实现:

#dimen 表示特征下标
#threshVal 表示分隔值
#threshIneq 表示分隔方式
def stumpClassify(dataMat, dimen, threshVal, threshIneq):
    retArray = ones((shape(dataMat)[0],1))
    if threshIneq == 'lt':
        for i in shape(dataMat)[0]:
            if dataMat[i][dimen] <= threshVal: retArray[i] = -1.0
    else:
        for i in shape(dataMat)[0]:
            if dataMat[i][dimen] > threshVal: retArray[i] = -1.0
    return retArray

AdaBoost算法实现:
通过下面的方法可选择出在当前权重 D <script type="math/tex" id="MathJax-Element-9">D</script>下最佳的决策分类信息,返回值分别为当前最优分类器,当前分类器的误差值,最终的分类结果。

#这里的D为每个样本的初始权重,计算方式为 D = ones((shape(dataMat)[0],1))/shape(dataMat)[0]
def buildStump(dataMat, classLabels, D):
    dataMatrix = mat(dataMat);labelMatrix=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)
                predictValue = stumpClassify(dataMatrix, i, threshVal, inequal)
                errArr = mat(ones((m,1)))
                for classIndex in range(0,m):
                    if errArr[classIndex] == labelMatrix[classIndex]:
                        errArr[classIndex]=0
                weightError = D.T * errArr
                if weightError < minError:
                    minError = weightError
                    bestClassEst = predictVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump, minError, bestClassEst

    Example Result:
    >>> bestStump
    'dim': 0, 'ineq': 'lt', 'thresh': 1.3
    >>> minError
    matrix([[ 0.2]])
    >>> bestClassEst
    array([[-1.],
           [ 1.],
           [-1.],
           [-1.],
           [ 1.]])

完整AdaBost Training 算法实现:
算法输出结果为一组弱分类器,每个分类器都有对应的权重值

def adaBoostTrainDS(dataArr, classLables, 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为一个 (m,1)的向量
        expon = multiply(-1*alpha*mat(classLabel).T, classEst)
        ##利用上面的 公式(2) 公式(3)更新 D
        D = multiply(D, exp(expon))
        D = D/D.sum()
        aggClassEst += alpha*classEst
        ##当前所有分类器组合得到的分类结果
        prediction = sign(aggClassEst)
        ##计算误差值
        aggError = ones((m,1))
        for i in range(prediction.shape()[0]):
            if prediction[i] == classLabels.T[i] :
                aggError[i] = 0
        # 上面的for 循环可以简单用下面的语句
        #aggErrors = multiply(sign(aggClassEst)!=mat(classLabels).T, ones((m,1)))

        #计算错误率
        errorRate = aggError.sum()/m
        if errorRate == 0.0: break;

    return weakClassArr

使用AdaBoost分类器进行分类目标数据

def adaClassify(dataToClass, classifierArr):
    dataMatrix = mat(dataToClass)
    m = shape(dataMatix)[0]
    ##现将测试数据的分类结果初始为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+= classifier[i]['alpha']*classEst


    return sign(aggClassEst)

AdaBoost 分类性能调优

不同弱分类数目会存在不同的分类错误率,但并不是说弱分类器的数量越多分类错误率越低,通常情况下,AdaBoost会达到一个稳定的测试错误率,而并不会随分类数目的增多而提高,另外一些情况下弱分类器数量当超过每一个最佳数值后,随着弱分类器数量的增加,错误率也会随之增高,这种现象称之为过拟合,因此在构造我们分类器时我们需要通过不断分类错误率和分类器数目找到一个最佳的分类器数。
这是一个分类器数目和错误率映射case:

分类器数目训练错误率(%)测试错误率(%)
10.280.27
100.230.24
500.190.21
1000.190.22
5000.160.25
10000.140.31
100000.110.33

以上是关于AdaBoost(自适应增强算法)的主要内容,如果未能解决你的问题,请参考以下文章

Python机器学习算法之AdaBoost算法

Adaboost

adaboost算法

GBDT 和 AdaBoost区别?

AdaBoost 和 Real Adaboost 总结

机器学习笔记_PRML_Adaboost 算法的原理与推导