机器学习实战(七)——利用AdaBoost元算法提高分类性能

机器学习实战(七)——利用AdaBoost元算法提高分类性能

概述

元算法:处理问题是不是单靠一个算法的结果而是对多个算法综合考虑

一、基于数据集多重抽样的分类器

元算法/集成方法:将不同的分类器进行组合

1.1、bagging:基于数据随机重抽样的分类器构建方法

自举汇聚法(bagging)方法

  1. 构建数据集:假设原始数据集有T个数据,我们要利用该数据集构建S个新数据集,具体的构建方法为:每一次构建都是从原始数据集中有放回的抽样T次(因此可能出现相同的样本),重复S次构建。
  2. 学习分类器:基于这S个数据集的每一个去训练一个基学习器
  3. 将S个基学习器进行组合
  4. 在对预测输出进行结合时,Bagging通常对分类任务使用简单投票法,对回归任务使用简单平均法。

特点是串行训练,每一个新分类器都是根据已训练处的分类器的性能来进行训练

1.2、boosting

boosting方式每次使用的是全部的样本,每轮训练改变样本的权重。

bagging和boosting的主要区别为

  • 样本选择:bagging是在原始样本集上有放回的选取样本,从原始集中选出的各轮训练集之间是独立的;而boosting是每一轮的训练样本不变,都是同一个,但是样本的权重发生改变,该轮分类错误的样本权重增大,正确的样本权重减少
  • 权重:bagging各个样本的权重一样,boosting各个样本的权重不断变化
  • 预测函数:bagging各个弱分类器的权重是相等的,boosting各个分类器的权重是不等的
  • 并行与串行:bagging各个弱分类器可以并行生成,而boosting不行,必须串行

二、训练算法:基于错误提升分类器的性能

Adaboost的基本流程

训练集中的每一个样本都有一个权重来象征其重要程度,初始时权重都相等,而在第一个弱分类器训练之后计算错误率,并且重新训练该弱分类器,而此时权重将会调整,那些错误分类的样本权重会增加,正确分类的样本权重会降低

具体的计算与更新流程可以查看《统计学习方法》中的Adaboost章节

三、基于单层决策树构建弱分类器

单层决策树:就是根据一个特征然后直接进行分类,相当于只有一个根节点

简单数据绘图

def loadSimpData():
    dataMat = matrix([[1.0,2.1],
                      [2.0,1.1],
                      [1.3,1.0],
                      [1.0,1.0],
                      [2.0,1.0]])
    classLabels = [1.0,1.0,-1.0,-1.0,1.0]
    return dataMat,classLabels
fig = plt.figure()
ax = fig.add_subplot(111)
dataMat,classLabels = Adaboost.loadSimpData()
ax.scatter(dataMat[[0,1,4],0].tolist(),dataMat[[0,1,4],1].tolist(),marker='o')
ax.scatter(dataMat[2:4,0].tolist(),dataMat[2:4,1].tolist(),marker='s')
plt.show()

书中绘图好像有错误,并没有坐标为[1.5,1.6]左右的1类坐标点

在这里插入图片描述

那么从上述图像中我们可以得知如果要用一个单层决策树,从某一个特征(即某一个x)选择一个值(用一个与对应坐标轴垂直的曲线)来划分两种类别是无法实现的

构建单层决策树代码

def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
    retArray = ones((shape(dataMatrix)[0], 1))
    if threshIneq == 'lt':
        retArray[dataMatrix[:, dimen] <= threshVal] = -1.0
        # 所有样本的第dimen维度的数据取出来,然后如果元素是小于就为1否则为0
        # 通过一个01序列去索引retArray这个数组,1的取出来命为-1
        # 如果是It,那么大于临界值为正类,小于为负类
    else:
        retArray[dataMatrix[:, dimen] > threshVal] = -1.0
    return retArray

def buildStump(dataArr, classLabels, D):
    dataMartix = mat(dataArr)
    labelMat = mat(classLabels).T
    m, n = shape(dataMartix)
    numSteps = 10.0  # 将区间除以10,修改可决定步长
    bestStump = {}  # 用于存放错误率最低时的各种信息
    bestClassEst = mat(zeros((m, 1)))  # 用于存放错误率最低时的分类结果
    minError = inf  # 存放最低错误率
    for i in range(n):
        rangeMin = dataMartix[:, i].min()  # 当前特征对应的最小值
        rangeMax = dataMartix[:, i].max()  # 当前特征对应的最大值
        stepSize = (rangeMax - rangeMin) / numSteps
        for j in range(-1, int(numSteps) + 1):  # 对每一个可能的间距都遍历
            # 这里取-1还有到范围外(+1)是为了有两种情况,即全部归属于正类或者全部归属于负类
            # 尽管对于样本来说,好像这样会重复,但是对于未知的新样本来说并不一样
            for inequal in ['lt', 'gt']:  # 对当前间距的左边和右边分别试一次+1-1和与一次-1+1
                threshVal = (rangeMin + float(j) * stepSize)
                predictedVals = stumpClassify(dataMartix, i, threshVal, inequal)
                # 这里返回的是分类的结果
                errArr = mat(ones((m, 1)))
                errArr[predictedVals == labelMat] = 0
                weightedError = D.T * errArr  # 权重乘以错误的分类再求和
                if weightedError < minError:
                    minError = weightedError
                    bestClassEst = predictedVals.copy()  # 必须要copy()
                    # 否则进入下一次循环对predictedVals赋值的时候bestClassEst也就变了
                    bestStump['dim'] = i  # 错误率最低时的分类维度
                    bestStump['thresh'] = threshVal  # 错误率最低时的间隔值
                    bestStump['ineq'] = inequal  # 错误率最小时+-1在哪一边
    return bestStump, minError, bestClassEst

四、完成AdaBoost算法的实现

伪代码如下

对每次迭代:

  • 利用前述构建单层决策树的代码找到当前最佳的单层决策树
  • 将此单层决策树加入到单层决策树数组中
  • 计算对应alpha
  • 更新权重向量D
  • 更新累计类别估计值
  • 如果错误率为0就结束迭代

基于单层决策树的AdaBoost训练过程

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)
        print("D:", D.T)
        print("bestStump:", bestStump, "\terror:", error, "\tclassEst:", classEst)
        if (error == 0):
            alpha = float(0.5 * log((1.0 - error) / 1e-16))
        else:
            alpha = float(0.5 * log((1.0 - error) / error))
        #  这里如果直接max(error,1e-16)会报错,因此np.max不支持浮点数的比较,python2就没问题
        bestStump['alpha'] = alpha
        weakClassArr.append(bestStump)
        print("alpha:", alpha)
        print("classEst:", classEst.T)
        expon = multiply(-1 * alpha * mat(classLabels).T, classEst)
        # 如果分类结果相同,两个矩阵对应元素相乘为1,再前面一个负一,那就和更新公式对应了
        D = multiply(D, exp(expon))
        D = D / D.sum()
        aggClassEst += alpha * classEst
        # AdaBoost就是每一个分类器的分类结果(正负1)乘上权重然后加起来再去sign
        print("aggClassEst: ", aggClassEst)
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m, 1)))
        errorRate = aggErrors.sum() / m
        print("total error:", errorRate, "\n")
        if errorRate == 0.0: break

    return weakClassArr

五、测试算法:基于AdaBoost的分类

训练好模型后,输入样本即可输出类别的函数

#用来预测新样本的函数
def AdaClassify(dataToClass, classifierArr):
    # 第一个参数是我们要用来进行分类的样本
    # 第二个参数是我们已经训练好的模型
    dataMatrix = mat(dataToClass)
    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)

七、非均衡分类问题

核心问题就是:样本正类但被误判为负类,以及样本负类但被误判为正类,在之前我们都认为是相同的代价,就是错误次数+1,但是在现实生活中这种问题而产生的误判代价是不一样的。

2、基于代价函数的分类器决策控制

可以考虑设置其两者产生误判的代价不同,例如:

预测结果预测结果
+1-1
真实结果+1-51
真实结果-1500

那么在学习的时候就会更倾向于将误分类代价大的样本正确分类

八、处理非均衡问题的数据抽样方法

非均衡的数据即正负类样本数目的差距很大,主要方法是对训练数据进行改造,可以通过欠抽样过抽样实现。

  • 欠抽样:用于数据量更大的那一类,从其他随机抽取部分样本然后剔除掉
  • 过抽样:用于数据量更小的那一类,从其他随机抽取部分样本然后进行复制

那么在学习的时候就会更倾向于将误分类代价大的样本正确分类

八、处理非均衡问题的数据抽样方法

非均衡的数据即正负类样本数目的差距很大,主要方法是对训练数据进行改造,可以通过欠抽样过抽样实现。

  • 欠抽样:用于数据量更大的那一类,从其他随机抽取部分样本然后剔除掉
  • 过抽样:用于数据量更小的那一类,从其他随机抽取部分样本然后进行复制
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值