機器學習-AdaBoost元算法

一、AdaBoost元算法簡介

元算法(也叫集成算法)是對其他算法進行組合的一種方式。Boosting是通過集中關注被已有分類器錯分的那些數據來獲得新的分類器,並且Boosting分類器中的權重並不相等,每個權重代表的是其對應分類器在上一輪迭代中的成功度。Boosting有多個版本,博客討論其中最流行的版本AdaBoosting。

二、訓練算法:基於錯誤提升分類器的性能

AdaBoosting(adaptive boosting)的運行過程如下:
  
  1、訓練數據集中的每個樣本,並賦予其中一個權重,這些權重構成一個向量DD,一開始,這些權重都初始化成相等的值。
  
  2、首先在訓練數據集訓練處一個弱分類器,並計算該分類器的錯誤率
  
  3、然後在同一數據集上再次訓練弱分類器。在第二次訓練分類器中,將會重新調整每個樣本的權重,其中第一次分類正確樣本的權重會降低,第一次分類錯誤的樣本的權重會提高。

  
  爲了從所有弱分類器中得到最終的分類結果,AdaBoosting爲每個分類器都分配了一個權重值alpha,這些權重alpha的值都是基於每個弱分類器的錯誤率進行計算的。其中錯誤率的定義爲:ε=/\varepsilon =未正確分類的樣本數目/所有樣本數目,而alpha的計算公式爲:
                         
                         α=12ln(1εε)\alpha =\frac{1}{2}ln(\frac{1-\varepsilon }{\varepsilon })

AdaBoost的流程圖如下所示:
在這裏插入圖片描述

計算出alphas的值之後就可以對權重向量DD進行更新,以使得那些正確分類的樣本的權重降低,而那些錯分的樣本的權重升高。D的計算方法如下:

如果某個樣本被正確分類,那麼該樣本的權重更改爲:
              
                         Di(t+1))=Di(t)eαSum(D)D_{i}(t+1))=\frac{D_{i}(t)e^{-\alpha }}{Sum(D)}

如果某個樣本被錯分,那麼該樣本的權重更改爲:
                         
                         Di(t+1))=Di(t)eαSum(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曲線
在這裏插入圖片描述

打包代碼:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章