《机器学习实战》chapter 07利用AdaBoosting元算法提高分类性能

第一部分:集成方法介绍

集成方法通过组合多个分类器的分类结果,获得了比简单分类器更好的分类结果

1、bagging,通过随机抽样的替换方式,得到了与原始数据集规模一样的数据集。

    在S个数据集建好以后,将某个学习算法分别作用于每个数据集就得到了S个分类器。当我们对新数据进行分类时,就可以应用这S个分类器进行分类。与此同时,选择分类投票结果中最多的类别作为最后的分类结果。

2、boosting,在bagging的思路上更进一步,它在数据集上顺序应用了多个不同的分类器

    boosting中,不同的分类器是通过穿行训练而获得的,每个新分类器都根据已训练出的分类器的分类性能来进行训练。boosting是通过集中关注被已有分类器错分的那些数据来获得新的分类器。

    运行过程:训练数据中的每个样本,并赋予其一个权重,这些权重构成了向量D。一开始,这些权重都初始化成相等值。首先在训练数据上训练出一个弱分类器并计算该分类器的错误率,然后在同一数据集上再次训练弱分类器。在分类器的第二次训练当中,将会重新调整每个样本的权重,其中第一次分类正确的样本的权重会降低,而第一次分错的样本的权重将会提高。为了从所有弱分类器中得到最终的分类结果,AdaBoosting为每一个分类器都分配了一个权重值alpha,这些alpha值是基于每个弱分类器的错误率来计算的。错误率的计算方法如下:


计算出alpha值之后可以对权重向量D进行更新,以使得那些正确分类的样本的权重降低而错分样本的权重升高。D的计算方法如下:

如果某个样本被正确分类,那么该样本的权重更改为:


而如果耨个样本被错分,那么该样本的权重更改为:


3、随机森林(后补。。。)

第二部分:基于单层决策树的AdaBoost方法

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

# 加载一个简单的数据集
def loadSimpleData():
    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


# 利用单层决策树(树桩)分类
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
    # 创建一个与数据集样本数量相同的列向量,初始化为1
    retArray = ones((shape(dataMatrix)[0], 1))
    if threshIneq == 'lt':
        # <= threshVal的归为-1类, 其余为1类
        retArray[dataMatrix[:, dimen] <= threshVal] = -1.0
    else:
        # 》 threshVal的归为-1类, 其余为1类
        retArray[dataMatrix[:, dimen] > threshVal] = -1.0
    return retArray


# 构建单层决策树(数据集,类别标签,迭代次数)
def buildStump(dataArr, classLabels, D):
    """
    将最小错误率minError设为正无穷
    对数据集中的每一个特征(第一层循环):
        对每个步长(第二层循环):
            对每个不等号(第三层循环):
                建立一棵单层决策树并加以利用加权数据集对他进行测试
                如果错误率低于minError,则将当前单层决策树设为最佳单层决策
    返回最佳单层决策树
    """
    dataMat = mat(dataArr)
    labelMat = mat(classLabels).T
    m, n = shape(dataMat)
    # 步数(所有可能值范围)
    numSteps = 10.0
    # 保存给定权重向量D所得到的最佳单层决策树
    bestStump = {}
    # 最佳分类获得的类别向量(列向量)
    bestClassEst = mat(zeros((m, 1)))
    # 初始化最小错误率为正无穷
    minError = inf
    # 对数据集中的每一个特征,按列循环
    for i in range(n):
        rangeMin = dataMat[:, i].min()
        rangeMax = dataMat[:, i].max()
        # 步长
        stepSize = (rangeMax - rangeMin) / numSteps
        # 对每个步长
        for j in range(-1, int(numSteps) + 1):
            # 对每个不等号,lt: less than; gt: great than
            for inequal in ['lt', 'gt']:
                # 计算阈值,初值 + 步数 * 步长
                threshVal = (rangeMin + float(j) * stepSize)
                # 利用单层决策树返回预测分类结果
                predictedVals = stumpClassify(dataMat, i, threshVal, inequal)
                # 分类结果的正误,1分类错误,0正确,初始化为全1
                errArr = mat(ones((m, 1)))
                # 把正确分类的置为0
                errArr[predictedVals == labelMat] = 0
                # 计算加权错误率,错误向量 dot* 权重向量,weightedError是一个值:[[ 0.57142857]]
                weightedError = D.T * errArr
                # print("weightedError : ", weightedError)
                # 更新最小加权错误率
                if weightedError < minError:
                    minError = weightedError
                    bestClassEst = predictedVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump, minError, bestClassEst

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

# 基于单层决策树的AdaBoost训练过程
def adaBoostTrainDS(dataArr, classLabels, numIt=40):
    """
    对每次迭代:
        利用buildStump()函数找到最佳的单层决策树
        将最佳单层决策树加入到单层决策树组
        计算alpha
        计算新的权重向量D
        更新累计类别估计值
        如果错误率等于0.0,则退出循环
    """
    # 声明单层决策树组保存每一次迭代的最佳DS(decision stump)
    weakClassArr = []
    m = shape(dataArr)[0]
    # 初始化权重向量(列),保存每个数据的权重,初始时每个数据点的权重相同
    D = mat(ones((m, 1)) / m)
    # 初始化aggClassEst(列向量),保存每个数据点的类别累计估计值
    aggClassEst = mat(zeros((m, 1)))
    # 训练numIt次或者直到错误率为0
    for i in range(numIt):
        """利用buildStump()函数找到最佳的单层决策树"""
        # 用buildStump获得最小错误率的单层决策树,最小错误率以及估计的类别向量
        bestStump, error, classEst = buildStump(dataArr, classLabels, D)
        print("D : ", D.T)
        """计算alpha,表示本次单层决策树输出结果的权重"""
        # max(error, 1e-16)确保在没有错误时不会发生除零溢出
        alpha = float(0.5 * log((1.0 - error) / max(error, 1e-16)))
        # 把alpha值加入到bestStump字典中
        bestStump['alpha'] = alpha
        """将最佳单层决策树加入到单层决策树组"""
        weakClassArr.append(bestStump)
        print("classEst : ", classEst.T)
        """计算新的权重向量D"""
        # 如果当前样本被正确分类((1 * 1)or(-1 * -1)) = 1,乘参数-1 = -alpha,权重下降
        # 如果当前样本被错分((1 * -1)or(-1 * 1)) = -1,乘以参数-1 = alpha,权重升高
        expon = multiply(-1 * mat(classLabels).T, classEst) * alpha
        # 其实是一个迭代的过程D_i+1 = D_i * exp(expon)
        D = multiply(D, exp(expon))
        D = D / D.sum()
        # 运行时类别估计值
        aggClassEst += alpha * classEst
        print("aggClassEst : ", aggClassEst.T)
        # 使用sign进行二分类
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m, 1)))
        errorRate = aggErrors.sum() / m
        print("total error : ", errorRate)
        """在训练错误率达到0,提前结束循环"""
        if errorRate == 0.0:
            break
    return weakClassArr

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

# adaBOost分类函数
def adaClassify(dataToClass, classifierArr):
    dataMat = mat(dataToClass)
    m = shape(dataMat)[0]
    aggClassEst = mat(zeros((m, 1)))
    for i in range(len(classifierArr)):
        classEst = stumpClassify(dataMat, classifierArr[i]['dim'], classifierArr[i]['thresh'], classifierArr[i]['ineq'])
        aggClassEst += classifierArr[i]['alpha'] * classEst
        print(aggClassEst)
    return sign(aggClassEst)


# test
dataMat, classLabels = loadSimpleData()
classifierArr = adaBoostTrainDS(dataMat, classLabels, 30)
print(adaClassify([[5, 5], [0, 0]], classifierArr))

4、示例:在一个难数据集上应用AdaBoost,数据集采用第4章给出的马疝病数据集。

  • 加载数据
# 加载数据
def loadDataSet(fileName):
    # 计算特征个数(如果用下面的fr来读,那么训练集和测试集中就少了一个样本数据)
    numFeat = len(open(fileName).readline().split('\t'))
    dataMat = []
    labelMat = []
    fr = open(fileName)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat - 1):
            # 不能split()后直接append,应该先用float格式化数据,统一数据类型
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat, labelMat
  • 测试
# test
dataMat, classLabels = loadDataSet("horseColicTraining2.txt")
testMat, testLabels = loadDataSet('horseColicTest2.txt')
classifierArr = adaBoostTrainDS(dataMat, classLabels, 50)
predicted = adaClassify(testMat, classifierArr)
errArr = mat(ones((67, 1)))
errCount = errArr[predicted != mat(testLabels).T].sum()
print("错误率: ", errCount / 67)


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值