AdaBoost

写在开头
  最近在学习一些关于机器学习的基础算法,结合学习Peter Harrington的《机器学习实战》和李航老师的《统计学习方法》两本书以及网上前辈的笔记,写下了以下的学习过程。
  代码环境:Pytharm/Python3.7
  内容有参考也有自己的想法,由于自己的理解不足,文章肯定存在很多错误,还恳请各位批评指正。

1. 个人对算法的理解
  这张图片清晰的给出了AdaBoost算法的思想,首先构建弱分类器,并且计算出该分类器的错误率。然后再在同一数据集上再次训练弱分类器,在分类器的第二次训练当中,将会重新调整每个样本的权重,其中第一次分对的样本的权重将会降低,而第一次分错的样本的权重将会提高,这样分类结果会逐步提高。然后AdaBoost为每一个分类器都分配一个权重值alpha,就是图中三角框中的值,这些alpha值是基于每个弱分类器的错误率进行计算的。越大说明错误率越低,分类结果越可信。最后就根据这些弱分类器的分类结果及所占权重得到最后的分类结果。
在这里插入图片描述

2. AdaBoost算法实现源码(简单数据测试)

import numpy
import math


# -----整个就是在构建一个单层决策树,构建弱分类器---------
def loadSimpData():
    datMat = numpy.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


# --------函数将用于测试是否有某个值小于或者大于我们正在测试的阈值-----
# 四个参数分别是(输入矩阵,第几列,阈值,lt或gt)threshIneq决定了不等号是大于还是小于
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
    predictedVals = numpy.ones((numpy.shape(dataMatrix)[0], 1))
    if threshIneq == "lt":
        predictedVals[dataMatrix[:, dimen] <= threshVal] = -1.0  # 注意比较元素大小,符合不等式条件则赋值
    else:
        predictedVals[dataMatrix[:, dimen] > threshVal] = -1.0
    return predictedVals


def buildStump(dataArr, classLabels, D):
    dataMatrix = numpy.mat(dataArr)
    labelMat = numpy.mat(classLabels).T
    row, column = numpy.shape(dataMatrix)
    numSteps = 10.0  # 变量numSteps用于在特征的所有可能值上进行遍历
    bestStump = {}  # 字典用于存储给定权重向量D时所得到的最佳单层决策树的相关信息
    bestClasEst = numpy.mat(numpy.zeros((row, 1)))
    minError = math.inf  # 一开始就初始化成正无穷大,之后用于寻找可能的最小错误率
    for i in range(column):  # 在数据集的所有特征上遍历1/2
        # 通过计算最小值和最大值来了解应该需要多大的步长
        rangeMin = dataMatrix[:, i].min()  # 第i列全部元素最小值
        rangeMax = dataMatrix[:, i].max()  # 第i列全部元素最大值
        stepSize = (rangeMax - rangeMin) / numSteps  # 步长
        for j in range(-1, int(numSteps) + 1):  # J:-1-10?
            for inequal in ['lt', 'gt']:
                threshVal = (rangeMin + float(j) * stepSize)  # 阈值
                predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)
                errArr = numpy.mat(numpy.ones((row, 1)))  # 列向量
                errArr[predictedVals == labelMat] = 0  # 难道真的能够通过这种方式比较数组内部元素嘛?是的!
                weightedError = D.T * errArr  # calc total error multiplied by D
                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 = []
    row = numpy.shape(dataArr)[0]
    D = numpy.mat(numpy.ones((row, 1)) / row)
    aggClassEst = numpy.mat(numpy.zeros((row, 1)))
    for i in range(numIt):
        bestStump, error, classEst = buildStump(dataArr, classLabels, D)
        print("D:{}".format(D.T))
        alpha = float(0.5 * numpy.log((1 - error) / max(error, 1e-16)))  # alpha的计算公式,《机器学习实战》136页
        bestStump['alpha'] = alpha
        weakClassArr.append(bestStump)
        print("classEst:{}".format(classEst.T))
        # 《机器学习实战》137页公式不是直接用alpha吗?
        # 为下一次迭代,计算D
        expon = numpy.multiply(-1 * alpha * numpy.mat(classLabels).T, classEst)
        # 正常相乘都是没有问题的,问题在于进行exp()操作时,必须使用vectorize矢量化
        # 因为指数,不能直接对矩阵进行指数操作,我们想当然的认为是对每个矩阵,但是其实不是
        # 所以,必须vectorize矢量化,才能认为对每个元素进行指数操作
        # 但是刚刚试了直接exp居然成功了
        D = numpy.multiply(D, numpy.exp(expon))
        D = D / D.sum()
        aggClassEst += alpha * classEst
        print("aggClassEst:{}".format(aggClassEst.T))
        aggErrors = numpy.multiply(numpy.sign(aggClassEst) != numpy.mat(classLabels).T, numpy.ones((row, 1)))
        errorRate = aggErrors.sum() / row
        print("total error:{}".format(errorRate))
        if errorRate == 0.0:
            break
    return weakClassArr


# AdaBoost分类函数
def adaClassify(datToClass, classiferArr):
    dataMatrix = numpy.mat(datToClass)
    row = numpy.shape(dataMatrix)[0]
    aggClassEst = numpy.mat(numpy.zeros((row, 1)))
    for i in range(len(classiferArr)):
        classEst = stumpClassify(dataMatrix, classiferArr[i]["dim"], classiferArr[i]["thresh"], classiferArr[i]["ineq"])
        aggClassEst += classiferArr[i]['alpha'] * classEst
        print(aggClassEst)
    return numpy.sign(aggClassEst)


def main():
    datMat, classLabels = loadSimpData()
    weakClassArr = adaBoostTrainDS(datMat, classLabels, numIt=40)
    print(weakClassArr)
    #输入[0,0]测试数据,输出分类结果
    print(adaClassify([0, 0], weakClassArr))


if __name__ == '__main__':
    main()

参考文档:
[1]《机器学习实战》第七章
[2]《统计学习方法》李航

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值