机器学习实战【8】(AdaBoost)

本博客记录《机器学习实战》(MachineLearningInAction)的学习过程,包括算法介绍和python实现。

AdaBoost算法

Adaboost,即Adaptive Boosting(自适应增强),是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器组合起来,构成一个更强的分类器(强分类器)。

算法原理

算法训练出的每个分类器都有一个权重,最终分类时根据权重大小来决定每个分类器的话语权,即对最终分类结果的影响力。这个权重的大小则根据每个分类器的错误率来决定,错误率小的分类器拥有更大的权重。需要注意的是,这里提到的错误率并不是错分样本占总样本的比例,而是依据每个样本的权值算出的(没错,每个样本也有权值,而且每个分类器中的样本权值还不一样)。

算法步骤

1.给所有m个训练样本赋予相同的权重: wi=1m
2.使用这组数据及权重训练弱分类器,使得错误率尽量小,其中错误率是每个错分样本权重的总和。
3.计算训练出的弱分类器的权值,其中e代表错误率:

α=121ee

4.更新样本权值,其中 yi 为样本类别, f(xi) 为分类器的输出结果,两者都是1或-1,Z是归一化参数,使得最终的权值总和为1,从式中也可以看出错分样本的权值会增加,正确分类样本的权值会降低:
wnexti=wiZeαyif(xi)

5.使用新的样本权值继续训练新的分类器,以此往复,直到达到要求。

分类方式

最终训练出了n个弱分类器,并且得到了每个分类器对应的权值 α ,分类时计算每个分类器分类结果的加权和即可:

F(x)=sign(i=1nαif(xi))

弱分类器

书中的弱分类器采用的是单层决策树(Stump)分类器,分类器选择一个阈值以及某一个特征,该特征大于阈值的样本分为一类,小于阈值的样本分为另一类。在训练时需要遍历所有特征,并且取很多的阈值,来计算出使错误率最小的一组参数。

python实现

# 使用stump分类器分类数据,dimen为特征下标,threshVal为阈值
# threshIneq的两个值表示小于阈值的样本是分类为正集或负集
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
    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 = {}
    bestClasEst = np.mat(np.zeros((m, 1)))
    minError = np.inf  # init error sum to +infinity
    # 遍历每个特征
    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
                # 保存使错误率最小的决策树参数
                if weightedError < minError:
                    minError = weightedError
                    bestClasEst = predictedVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump, minError, bestClasEst

# 训练函数
def adaBoostTrainDS(dataArr, classLabels, numIt=40):
    # 存放所有的弱分类器
    weakClassArr = []
    m = np.shape(dataArr)[0]
    # 初始化权值向量D
    D = np.mat(np.ones((m, 1)) / m)
    aggClassEst = np.mat(np.zeros((m, 1)))
    for i in range(numIt):
        # 计算得到错误率最低的弱分类器
        bestStump, error, classEst = buildStump(dataArr, classLabels, D)
        # 计算alpha(需要防止错误率为0时除以0的问题)
        alpha = float(0.5 * np.log((1.0 - error) / max(error, 1e-16)))
        # 保存弱分类器
        bestStump['alpha'] = alpha
        weakClassArr.append(bestStump)
        # 计算新的数据权值
        expon = np.multiply(-1 * alpha * np.mat(classLabels).T, classEst)
        D = np.multiply(D, np.exp(expon))
        D = D / D.sum()
        # 用当前训练出的所有弱分类器进行分类得出结果
        aggClassEst += alpha * classEst
        # 计算错误率,达到0之后停止迭代
        aggErrors = np.multiply(np.sign(aggClassEst) != np.mat(classLabels).T, np.ones((m, 1)))
        errorRate = aggErrors.sum() / m
        print("total error: ", errorRate)
        if errorRate == 0.0:
            break
    return weakClassArr, aggClassEst

# 分类函数
def adaClassify(datToClass, classifierArr):
    dataMatrix = np.mat(datToClass)
    m = np.shape(dataMatrix)[0]
    aggClassEst = np.mat(np.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
    return np.sign(aggClassEst)

# 测试函数,数据集从文件读取
def AdaboostTest():
    dataMatTrain, classLabelTrain = loadDataSet("horseColicTraining2.txt")
    dataMatTest, classLabelTest = loadDataSet("horseColicTest2.txt")
    weakClassArr, aggClassEst = adaBoostTrainDS(dataMatTrain, classLabelTrain, numIt=50)
    classEst = adaClassify(dataMatTest, weakClassArr)
    mTest = np.shape(classLabelTest)[0]
    error = np.ones((mTest, 1))
    error[classEst != np.mat(classLabelTest).T] = 0
    errorRate = sum(error) / mTest
    print("total error: ", 1 - errorRate)

总结

Adaboost是一种提升(boosting)方法,把若干个弱分类器组合成一个强分类器,迭代的过程中,不断提高错分样本的权值,在总体上又使错误率低的样本具有更大的话语权,使得整体分类效果很好。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值