机器学习实战第7章——利用AdaBoost元算法提高分类性能

将不同的分类器组合起来,这种组合结果被称为集成方法或元算法(meta-algorithm)。

使用集成方法时会有多种形式:(1)可以是不同算法的集成(2)可以是同一种算法在不同设置下的集成(3)数据集不同部分分配给不同分类器之后的集成,等等

接下来介绍基于同一种分类器多个不同实例的两种不同计算方法bagging和boosting

1. bagging

  原理:从原始数据集选择S次后得到S个新数据集的一种技术。新数据集和原数据集的大小相等。每个数据集都是通过在原始数据集中随机选择一个样本来进行替换而得到的。这里的替换就意味着可以多次地选择同一样本,允许重复。(取出,放回)。将某个学习算法分别作用于每个数据集就得到S个分类器。每个分类器的权值相同

2. boosting

  原理:集中关注被已有分类器错分的那些数据来获得新的分类器。是所有分类器加权求和结果,每个分类器的权值不同。

  从弱学习算法出发,反复学习,得到一系列弱分类器(又称为基本分类器),然后组合这些弱分类器,构成一个强分类器。大多的boosting方法都是改变训练数据的概率分布(训练数据的权值分布),针对不同的训练数据分布调用弱学习算法学习一系列弱分类器。

  那么对于boosting方法,有两个问题需要回答:(1) 在每一轮如何改变训练数据的权值或者概率分布?

                       (2)如何将弱分类器组合成一个强分类器?

  接下来介绍boosting中一个最流行的算法AdaBoost,在AdaBoost是如何解决上面两个问题的呢?对于第一个问题,AdaBoost的做法是,提高那些被前一轮弱分类器错误分类样本的权值,而降低被正确分类样本的权值。对于第二个问题,AdaBoost采取加权多数表决的方法,加大分类误差率小的弱分类器的权值,减小分类误差率大的弱分类器的权值

3. AdaBoost算法

    

下面是具体的算法:

    

  

  对于(2)中的(d)根据下式得到

      

具体代码如下:

import numpy as np
from math import log

def loadSimpData():
    datMat = np.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

def loadDataSet(fileName):      #general function to parse tab -delimited floats
    numFeat = len(open(fileName).readline().split(‘\t‘)) #get number of fields
    dataMat = []; labelMat = []
    fr = open(fileName)
    for line in fr.readlines():
        lineArr =[]
        curLine = line.strip().split(‘\t‘)
        for i in range(numFeat-1):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat

"""
    函数说明:通过阈值比较对数据进行分类
    Parameters:
        dataMatrix -输入数据
        dimen -第几列
        threshVal -阈值
        threshIneq -不等号
    return:
        分类结果
"""
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

"""
    函数说明:建立单层决策树
    Parameters:
        dataArr     -输入数据集
        classLabels -分类
        D           -权重向量
    return:
        bestStump   -最佳单层决策树字典
        minError    -最小错误率
        bestClassEst    -最佳类别估计值
"""
def buildStump(dataArr, classLabels, D):
    dataMatrix = np.mat(dataArr)
    labelMat = np.mat(classLabels).T
    m, n = np.shape(dataMatrix)
    #numSteps:步数; bestStump:保存最佳单层决策树的相关信息; bestClassEst:最佳预测结果
    numSteps = 10.0; bestStump = {}; bestClassEst = np.mat(np.zeros((m, 1)))
    minError = np.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)
                predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)
                errArr = np.mat(np.ones((m, 1)))
                errArr[predictedVals == labelMat] = 0
                weightError = D.T * errArr    #计算加权错误率
                print("split:dim %d,thresh %.2f,thresh inequal: %s,the weighted error is %.3f"%(i,threshVal,inequal,weightError))
                # 找到最小错误率的最佳单层决策树,并保存相关信息
                if weightError < minError:
                    minError = weightError
                    bestClassEst = predictedVals.copy()
                    bestStump[‘dim‘] = i
                    bestStump[‘thresh‘] = threshVal
                    bestStump[‘ineq‘] = inequal
    return bestStump, minError, bestClassEst

"""
    函数说明:基于单层决策树的AdaBoost训练过程
    Patameters:
        dataArr     -数据集
        classLabels -数据标签
        numIt       -迭代次数
    return:
        weakClassArr    -所有的最佳分类器决策树
        aggClassEst     -累计分类估计
"""
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
    weakClassArr = []
    m = np.shape(dataArr)[0]
    D = np.mat(np.ones((m,1))/m)   #init D to all equal
    aggClassEst = np.mat(np.zeros((m,1)))
    for i in range(numIt):
        bestStump,error,classEst = buildStump(dataArr,classLabels,D)#build Stump
        print("D:",D.T)
        # alpha公式:alpha=1/2*ln((1-error)/error)
        # max(error, 1e-16)是为了防止error=0的情况
        alpha = float(0.5 * log((1.0 - error) / max(error, 1e-16)))
        bestStump[‘alpha‘] = alpha
        weakClassArr.append(bestStump)                  #保存最优单层决策树
        print("classEst: ",classEst.T)
        #更新D,D是一个概率分布向量,总和为1
        # D=(D*exp(-alpha*classLabels*classEst))/D.sum()
        # classEst是分类器预测的分类结果,classEst是
        # np.multiply是矩阵对应元素相乘,返回和矩阵大小一样,classLabels是m*1,classEst是1*m
        expon = np.multiply(-1 * alpha * np.mat(classLabels).T,classEst) #exponent for D calc, getting messy
        D = np.multiply(D, np.exp(expon))                              #Calc New D for next iteration
        D = D / D.sum()
        #更新累计估计类别
        #aggClassEst记录每个类别的累计估计值,最终分类函数为f(x) = sign(aggClassEst)
        aggClassEst += alpha*classEst
        print("aggClassEst: ",aggClassEst.T)
        #计算错误率
        aggErrors = np.multiply(np.sign(aggClassEst) != np.mat(classLabels).T,np.ones((m,1)))
        errorRate = aggErrors.sum() / m
        print("total error: ",errorRate)
        #误差为0时退出循环
        if errorRate == 0.0: break
    return weakClassArr,aggClassEst

"""
    函数说明:测试算法,AdaBoost分类函数
    Parameters:
        datToClass      -待分类样例
        classifierArr   -多个弱分类器组成的数组
    return:
        类别
"""
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)):
        #基于每个分类器得到一个类别值
        print(classifierArr[i])
        classEst = stumpClassify(dataMatrix,classifierArr[i][‘dim‘],                                 classifierArr[i][‘thresh‘],                                 classifierArr[i][‘ineq‘])#call stump classify
        aggClassEst += classifierArr[i][‘alpha‘]*classEst
        print(aggClassEst)
    return np.sign(aggClassEst)
if __name__ == ‘__main__‘:
    datMat, classLabels = loadSimpData()
    D = np.mat(np.ones((5,1)) / 5)
    buildStump(datMat, classLabels, D)
    classifierArr, aggClassEst = adaBoostTrainDS(datMat, classLabels)
    print(adaClassify([0,0],classifierArr))
    print(adaClassify([[0,0],[1,0],[2,2]],classifierArr))
    #将第5章的马疝病数据应用到AdaBoost算法中
    datArr, labelArr = loadDataSet(‘horseColicTraining2.txt‘)
    classifierArr,aggClassEst = adaBoostTrainDS(datArr, labelArr, 10)
    testArr, testLableArr = loadDataSet(‘horseColicTest2.txt‘)
    prediction = adaClassify(testArr, classifierArr)
    errArr = np.mat(np.ones((67,1)))
    errRate = errArr[prediction!= np.mat(testLableArr).T].sum() / 67
    print(errRate)

4. 非均衡分类问题

  非均衡分类问题是指,在很多情况下不同类别的分类代价并不相等。例如对于垃圾邮件过滤的例子,如果我们把所有的邮件都预测为垃圾邮件,则用户可能会错过重要的合法邮件,如果我们把所有的邮件都预测为合法邮件,则会影响到用户体验,但是这两种代价是不一样的。

性能度量

  性能度量是指衡量模型泛化能力的评价标准。在回归问题中常用的性能度量是“均方误差”(mean squared error)。而在分类问题中错误率是一种常用的性能度量,错误率是指分类错误的样本占样本总数的比例,实际上这样的度量错误掩盖了样例如何被错分的事实。在机器学习中,有一个普遍使用的称为混淆矩阵的工具,它可以帮助人们更好的了解分类中的错误。

   正确率/查准率(precision):预测为正例的样本中真正正例的比例

            

   召回率/查全率(recall):预测为正例的真正例占所有正例的比例

            

  通常查准率和查全率是一对矛盾的度量。一般来说查准率高的时候,查全率会偏低;而查全率高的时候,查准率会偏低。通常只有在一些简单任务中查准率和查全率都很高。

  P-R图能直观的显示出学习器在样本总体上的查全率、查准率。

        

  图中的平衡点(BEP)是查准率=查全率时的取值,BEP高则更优,对于图中的三个学习器,A优于B优于C。

  但BEP还是过于简化了,通常使用的是F1度量:

      

  对于有偏好的情况:

      

  其中ß>O 度量了查全率对查准率的相对重要性. ß = 1时退化为标准的F1; ß> 1 时查全率有更大影响; ß < 1 时查准率有更大影响

  

  接下来介绍ROC曲线

      

  纵坐标为真阳率(真正例率):

        

  横坐标为假阳率(假正例率):

        

  AUC(area under the curve):ROC曲线下的面积,对不同的ROC曲线进行比较的一个指标,给出的是分类器的平均性能值。一个完美的分类器的AUC是1,而随机猜测的AUC则为0.5。若一个学习器的ROC曲线能把另一个学习器的ROC曲线完全包住,则这个学习器的性能比较好。

  实现代码如下,书中是以(1.0,1.0)点为起点来画曲线的,我改成了以(0.0,0.0)为起点,这样更好理解一些。

  绘制过程:给定m+个正例,m-个反例,将分类器的预测强度进行排序,然后把分类阈值设为最大,即把所有的样例都预测为反例,此时真阳率和假阳率均为0,在坐标(0,0)处标记一个点。然后将分类阈值依次设置为每个样例的预测值,即依次将每个样例划分为正例。设前一个坐标点为(x,y),若当前点为真正例,则它的坐标为(x,y+1/m+),真阳率变大;若当前点为假正例,则坐(x+1/m-,y),假阳率变大。

"""
    函数说明:ROC曲线绘制及AUC计算函数
    Parameters:
        predStrengths   -分类器的预测强度,马疝病数据集中为1*299
        classLabels     -分类标签
"""
def plotROC(predStrengths, classLabels):
    import matplotlib.pyplot as plt
    # cur = (1.0,1.0) #绘制光标的位置
    cur = (0.0,0.0) #绘制光标的位置
    ySum = 0.0 #用于计算AUC的值
    numPosClas = sum(np.array(classLabels)==1.0)    #保存正例的数目
    yStep = 1/float(numPosClas); xStep = 1/float(len(classLabels)-numPosClas)   #y轴的步长、x轴的步长
    sortedIndicies = predStrengths.argsort()#获取排好序的索引,从小到大
    fig = plt.figure()
    fig.clf()
    ax = plt.subplot(111)
    #loop through all the values, drawing a line segment at each point
    for index in sortedIndicies.tolist()[0][::-1]:  #改为从大到小
        if classLabels[index] == 1.0:   #标签为1修改真阳率
            delX = 0; delY = yStep;
        else:                           #标签不为1,修改假阳率
            delX = xStep; delY = 0;
            ySum += cur[1]              #保存纵坐标为之后计算面积
        #draw line from cur to (cur[0]-delX,cur[1]-delY)
        # ax.plot([cur[0],cur[0]-delX],[cur[1],cur[1]-delY], c=‘b‘)
        ax.plot([cur[0],cur[0]+delX],[cur[1],cur[1]+delY], c=‘b‘)
        # cur = (cur[0]-delX,cur[1]-delY)
        cur = (cur[0]+delX,cur[1]+delY)
    ax.plot([0,1],[0,1],‘b--‘)
    plt.xlabel(‘False positive rate‘); plt.ylabel(‘True positive rate‘)
    plt.title(‘ROC curve for AdaBoost horse colic detection system‘)
    ax.axis([0,1,0,1])
    plt.show()
    print("the Area Under the Curve is: ",ySum*xStep)   #AUC,小矩形面积之和

if __name__ == ‘__main__‘:
    datArr, labelArr = loadDataSet(‘horseColicTraining2.txt‘)
    classifierArr,aggClassEst = adaBoostTrainDS(datArr, labelArr, 50)
    #testArr, testLableArr = loadDataSet(‘horseColicTest2.txt‘)
    #prediction = adaClassify(testArr, classifierArr)
    #errArr = np.mat(np.ones((67,1)))
    #errRate = errArr[prediction!= np.mat(testLableArr).T].sum() / 67
    #print(errRate)
    plotROC(aggClassEst.T, labelArr)

结果如下:

    

参考:

《机器学习实战》

《机器学习》周志华

《统计学习方法》

原文地址:https://www.cnblogs.com/weiququ/p/9502065.html

时间: 2024-12-25 04:56:43

机器学习实战第7章——利用AdaBoost元算法提高分类性能的相关文章

机器学习实战笔记-利用AdaBoost元算法提高分类性能

做重要决定时,大家可能都会考虑吸取多个专家而不只是一个人的意见.机器学习处理问题时又何尝不是如此?这就是元算法(meta-algorithm ) 背后的思路.元算法是对其他算法进行组合的一种方式 7.1 基于数据集多重抽样的分类器 ??我们自然可以将不同的分类器组合起来,而这种组合结果则被称为集成方法(ensemblemethod)或者元算法(meta-algorithm).使用集成方法时会有多种形式:可以是不同算法的集成,也可以是同一算法在不同设置下的集成,还可以是数据集不同部分分配给不同分类

《机器学习实战》学习笔记:利用Adaboost元算法提高分类性能

一. 关于boosting算法的起源 boost 算法系列的起源来自于PAC Learnability(直译过来称为:PAC 可学习性).这套理论主要研究的是什么时候一个问题是可被学习的. 我们知道,可计算性在计算理论中已经有定义,而可学习性正是PAC Learnability理论所要定义的内容.另外,在计算理论中还有很大一部分精力花在研究问题是可计算的时候,其复杂度又是什么样的.因此,在计算学习理论中,也有研究可学习的问题的复杂度的内容,主要是样本复杂度 (Sample Complexity)

机器学习(利用adaboost元算法提高分类性能)

元算法背后的思路是对其他算法进行组合的一种方式,A from numpy import * def loadSimpData(): datMat = 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 def loadDataSet(fileName): #gener

第七章:利用AdaBoost元算法提高分类性能

本章内容□ 组合相似的分类器来提髙分类性能□应用AdaBoost算法□ 处理非均衡分类问题 7.1基于数据集多重抽样的分类器

利用AdaBoost元算法提高分类性能

当做重要决定时,大家可能都会吸取多个专家而不只是一个人的意见.机器学习处理问题时又何尝不是如此?这就是元算法背后的思路.元算法是对其他算法进行组合的一种方式. 自举汇聚法(bootstrap aggregating),也称为bagging方法,是从原始数据集选择S次后得到S个新数据集的一种技术.新数据集和原数据集的大小相等.每个数据集都是通过在原始数据集中随机选择一个样本来进行替换而得到的.在S个数据集建好之后,将某个学习算法分别作用于每个数据集就得到了S个分类器.当我们要对新数据进行分类时,就

第九篇:使用 AdaBoost 元算法提高分类器性能

前言 有人认为 AdaBoost 是最好的监督学习的方式. 某种程度上因为它是元算法,也就是说它会是几种分类器的组合.这就好比对于一个问题能够咨询多个 "专家" 的意见了. 组合的方式有多种,可能是不同分类算法的分类器,可能是同一算法在不同设置下的集成,还可以是数据集在不同部分分配给不同分类器之后的集成等等. 本文将给出的 AdaBoost 分类器实现基于第二种 (另外几种实现在此基础上稍作改动即可). 一种原始的元算法 - bagging (自举汇聚法) 这个算法的意思有点像投票系统

使用 AdaBoost 元算法提高分类器性能

前言 有人认为 AdaBoost 是最好的监督学习的方式. 某种程度上因为它是元算法,也就是说它会是几种分类器的组合.这就好比对于一个问题能够咨询多个 "专家" 的意见了. 组合的方式有多种,可能是不同分类算法的分类器,可能是同一算法在不同设置下的集成,还可以是数据集在不同部分分配给不同分类器之后的集成等等. 本文将给出的 AdaBoost 分类器实现基于第二种 (另外几种实现在此基础上稍作改动即可). 一种原始的元算法 - bagging (自举汇聚法) 这个算法的意思有点像投票系统

机器学习之白话与实战adaboost元算法

作为(曾)被认为两大最好的监督分类算法之一的adaboost元算法(另一个为前几节介绍过的SVM算法),该算法以其简单的思想解决复杂的分类问题,可谓是一种简单而强大的算法,本节主要简单介绍adaboost元算法,并以实例看看其效果如何. 该算法简单在于adaboost算法不需要什么高深的思想,它的基础就是一个个弱小的元结构(弱分类器),比如就是给一个阈值,大于阈值的一类,小于阈值的一类,这样的最简单的结构.而它的强大在于把众多个这样的元结构(弱分类器)组合起来一起发挥功效,所谓人多力量大,就射这

机器学习算法( 七、AdaBoost元算法)

一.概述 当做重要决定时,大家可能都会考虑吸取多个专家而不只是一个人的意见.机器学习处理问题时又何尝不是如此?这就是元算法(meta-algorithm)背后的思路.元算法是对其他算法进行组合的一种方式.接下来我们将集中关注一个称作AdaBoost的最流行的元算法.由于某些人认为AdaBoost是最好的监督学习的方法,所以该方法是机器学习工具箱中最强有力的工具之一. 本章首先讨论不同分类器的集成方法,然后主要关注boosting方法及其代表分类器Adaboost.再接下来,我们就会建立一个单层决