机器学习-AdaBoost元算法

一、AdaBoost元算法简介

元算法(也叫集成算法)是对其他算法进行组合的一种方式。Boosting是通过集中关注被已有分类器错分的那些数据来获得新的分类器,并且Boosting分类器中的权重并不相等,每个权重代表的是其对应分类器在上一轮迭代中的成功度。Boosting有多个版本,博客讨论其中最流行的版本AdaBoosting。

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

AdaBoosting(adaptive boosting)的运行过程如下:
  
  1、训练数据集中的每个样本,并赋予其中一个权重,这些权重构成一个向量 D D ,一开始,这些权重都初始化成相等的值。
  
  2、首先在训练数据集训练处一个弱分类器,并计算该分类器的错误率
  
  3、然后在同一数据集上再次训练弱分类器。在第二次训练分类器中,将会重新调整每个样本的权重,其中第一次分类正确样本的权重会降低,第一次分类错误的样本的权重会提高。

  
  为了从所有弱分类器中得到最终的分类结果,AdaBoosting为每个分类器都分配了一个权重值alpha,这些权重alpha的值都是基于每个弱分类器的错误率进行计算的。其中错误率的定义为: ε = / \varepsilon =未正确分类的样本数目/所有样本数目 ,而alpha的计算公式为:
                         
                          α = 1 2 l n ( 1 ε ε ) \alpha =\frac{1}{2}ln(\frac{1-\varepsilon }{\varepsilon })

AdaBoost的流程图如下所示:
在这里插入图片描述

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

如果某个样本被正确分类,那么该样本的权重更改为:
              
                          D i ( t + 1 ) ) = D i ( t ) e α S u m ( D ) D_{i}(t+1))=\frac{D_{i}(t)e^{-\alpha }}{Sum(D)}

如果某个样本被错分,那么该样本的权重更改为:
                         
                          D i ( t + 1 ) ) = D i ( t ) e α S u m ( D ) D_{i}(t+1))=\frac{D_{i}(t)e^{\alpha }}{Sum(D)}
在计算出D之后,AdaBoost又开始进行下一轮迭代。AdaBoost算法会不断地重复训练和调整权重过程,知道训练出错误率为0或者弱分类器的数目达到用户指定的值为止。

三、AdaBoost训练过程代码


"""
机器学习-AdaBoost算法
姓名:pcb
日期:2019.1.2
"""
from numpy import *
import matplotlib.pyplot as plt
#创建一个简单的数据集
def loadSimpData():
    datMat=matrix([[1.,2.1],[2.,1.1],[1.3,1.],[1.,1.],[2.,1.]])
    classLabel=[1.0,1.0,-1.0,-1.0,1.0]
    return datMat,classLabel


def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
    retArray=ones((shape(dataMatrix)[0],1))                    #将数组中的元素全部设为1
    if threshIneq=='lt':
        retArray[dataMatrix[:,dimen]<=threshVal]=-1.0          #将所有不满足不等式要求的的元素设置为-1
    else:
        retArray[dataMatrix[:,dimen]>threshVal]=-1.0
    return retArray

"""
程序的伪代码:
    将最小的错误率minError设为+无穷大
    对数据集中的每一个特征(第一层循环):
        对每个步长(第二层循环):
            对每个不等号(第三层循环):
                建立一棵单层决策树,并利用加权数据集对它进行测试
                如果错误率低于minError,则将当前单层决策树设为最佳单层决策树
    返回最佳单层决策树
"""
#将遍历stumpClassify函数中所有可能的输入值,找到数据集上最佳的单层决策树
def buildStump(dataArr,classLabels,D):
    dataMatrix=mat(dataArr);labelMat=mat(classLabels).T
    m,n=shape(dataMatrix)
    numSteps=10.0                                            #用于在特征所有可能值上遍历
    bestStump={}                                             #空字典,用于存储给定权重的向量D时所得到最佳单层
    bestClasEst=mat(zeros((m,1)))                            #
    minError=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']:                      #最后一个循环在在大于和小于之间切换不等式
                thresVal=(rangeMin+float(j)*stepSize)
                predictedVal=stumpClassify(dataMatrix,i,thresVal,inequal)
                errArr=mat(ones((m,1)))                      #构建一个列向量,判断
                errArr[predictedVal==labelMat]=0
                weightedError=D.T*errArr
                #print('split:dim %d,thresh %.2f,thresh ineqal:%s,the weighted error is %.3f'
                      #%(i,thresVal,inequal,weightedError))
                if weightedError<minError:
                    minError=weightedError
                    bestClasEst=predictedVal.copy()
                    bestStump['dim']=i
                    bestStump['thresh']=thresVal
                    bestStump['ineq']=inequal
    return bestStump,minError,bestClasEst

#基于单层决策树的AdaBoost训练过程
def adaBoostTrianDS(dataArr,classLabels,numIt=40):
    weakClassArr=[]
    m=shape(dataArr)[0]
    D=mat(ones((m,1))/m)                  #D是一个概率分布向量,所有元素之和是1.0
    aggClassEst=mat(zeros((m,1)))         #记录每个数据点的类别估计累计值
    for i in range(numIt):
        bestStump,error,classEst=buildStump(dataArr,classLabels,D) #返回则是利用D而得到的具有最小错误率的单层决策树
        #print("D:",D.T)
        alpha=float(0.5*log((1.0-error)/max(error,1e-16)))
        bestStump['alpha']=alpha
        weakClassArr.append(bestStump)
        #print("classEst:",classEst.T)
        expon=multiply(-1*alpha*mat(classLabels).T,classEst)
        D=multiply(D,exp(expon))
        D=D/D.sum()
        aggClassEst+=alpha*classEst
        #print("aggClassEst:",aggClassEst.T)
        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,aggClassEst

#基于adaBoost分类算法的测试函数
def adaclassify(datToClass,classifierArr):
    dataMatrix=mat(datToClass)
    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)


#加载数据
def loadDataSet(fileName):
    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):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat

#1.ROC(接收者操作特征,receiver operating characteristic)曲线的绘制
#2.AUC(曲线下的面积,Area Unser the Curve,AUC)计算函数
#3.分类器需要提供每个样例被判为阳性或者阴性的可信程度值
def plotROC(predStrengths,classLabels):
    cur=(1.0,1.0)                                #构建一个浮点数的二维元组,该元组保留的是绘制光标的位置
    ySum=0.0                                     #用于计算AUC的值
    numPosClas=sum(array(classLabels)==1.0)      #通过数组过滤方式计算正例的数目,并将该值赋给numPosClas
    yStep=1/float(numPosClas)                    #确定坐标轴上的步长
    xStep=1/float(len(classLabels)-numPosClas)
    sortedIndicies=predStrengths.argsort()       #对分类器预测的强度进行排序(从小到大)得到排序的索引,

    #构建画笔
    fig=plt.figure()
    fig.clf()
    ax=plt.subplot(111)
    for index in sortedIndicies.tolist()[0]:     #调用tolist,产生一个表进行迭代循环
      if classLabels[index]==1.0:                #每得到一个标签为1.0的类,则沿着y轴的方向下降一个步长,即不断降低真阳率
          delX=0
          delY=yStep
      else:
          delX=xStep                             #对于其他类别则需要在x轴上倒退一个步长
          delY=0
          ySum+=cur[1]                           #所有的高度和(ySum)随着x轴的每次移动而增加,计算总的AUC=ySum*xStep

      #一旦决定了在X轴或者Y轴方向进行移动,则可以在当前点和新点之间画一条线段,然后跟新当前点
      ax.plot([cur[0],cur[0]-delX],[cur[1],cur[1]-delY],c='r')
      cur=(cur[0]-delX,cur[1]-delY)
    ax.plot([0,1],[0,1],'b--')
    plt.xlabel('False Positive Rate')
    plt.ylabel('True positive Rate')
    ax.axis([0,1,0,1])
    plt.show()
    print('the Area Under the curve is :',ySum*xStep)




def main():

# #1.-----------测试算法------------------------------------------
#     D=mat(ones((5,1))/5)
#     datMat,classLabels=loadSimpData()
#     #buildStump(datMat,classLabels,D)
#     classifierArr=adaBoostTrianDS(datMat,classLabels,9)
#     classifierResult=adaclassify([[0,0],[5,5]],classifierArr)
#     print(classifierResult)

# #2.----------在大的数据集上使用AdaBoost算法-----------------------
#     dataArr,labelArr=loadDataSet('horseColicTraining2.txt')
#     classifierArry,aggClassEst=adaBoostTrianDS(dataArr,labelArr,50)
#     testArr,testLabelArr=loadDataSet('horseColicTest2.txt')
#     prediction10=adaclassify(testArr,classifierArry)
#     errArr=mat(ones((67,1)))
#     errCount=errArr[prediction10!=mat(testLabelArr).T].sum()
#     print(errCount/67)

#3.绘制ROC曲线以及AUC计算函数

    dataArr, labelArr = loadDataSet('horseColicTraining2.txt')
    classifierArry,aggClassEst=adaBoostTrianDS(dataArr,labelArr,10)
    plotROC(aggClassEst.T,labelArr)



if __name__=='__main__':
    main()

在一个复杂数据集上应用AdaBoost分类结果:

在这里插入图片描述
基于AdaBoost马疝病检测系统的ROC曲线
在这里插入图片描述

打包代码:

猜你喜欢

转载自blog.csdn.net/pcb931126/article/details/85805126