天天看點

機器學習實戰(6)--AdaBoost

在機器學習實戰前幾章學習了不同的分類算法,自然會考慮到是否可以将不同的分類器組合起來進行分類。

在這裡,簡單解釋兩種組合的方法。

1,bagging(基于資料随機重抽樣的分類器建構)

從原始資料集中随機選擇S次,得到S個新資料集,新資料集與原始資料集大小相同(随機意味着可以重複選擇)。再用這S個資料集訓練S個分類器,用着S個分類器進行分類,選擇分類器投票數最多的類作為分類結果。

2,boosting

boosting是一種與bagging很類似的技術。但是boosting是通過集中關注已有分類器錯分的那些資料來擷取新的分類器。即增大被錯分資料的權值,然後再用改變權值後的資料訓練新的分類器。最後基于所有的分類器權重求和,這裡的權值不是資料的權值,而是每個分類器的權值,錯誤率小的分類器權值較大。

boosting方法版本較多,這裡隻讨論最流行的版本AdaBoost。

Adaboost的原理

Adaboost是一個有若幹弱分類器組合成的強分類器。

AdaBoost,是英文”Adaptive Boosting”(自适應增強)的縮寫,由Yoav Freund和Robert Schapire在1995年提出。它的自适應在于:前一個基本分類器分錯的樣本會得到加強,權重後的全體樣本再次被用來訓練下一個基本分類器。

AdaBoost是一種疊代算法,在每一輪中加入一個新的弱分類器,直到達到某個預定的足夠小的錯誤率。每一個訓練樣本都被賦予一個權重,表明它被某個分類器選入訓練集的機率。如果某個樣本點已經被準确地分類,那麼在構造下一個訓練集中,它被選中的機率就被降低;相反,如果某個樣本點沒有被準确地分類,那麼它的權重就得到提高。

在具體實作上,最初令每個樣本的權重都相等,對于第k次疊代操作,我們就根據這些權重來選取樣本點,進而訓練分類器。然後就根據這個分類器,來提高被它分錯的的樣本的權重,并降低被正确分類的樣本權重。然後,權重更新過的樣本集被用于訓練下一個分類器。整個訓練過程如此疊代地進行下去。

(1)AdaBoost算法流程

  • 1,首先初始化樣本的權值
    機器學習實戰(6)--AdaBoost
  • 2,每一個分類器的形式如下:
    機器學習實戰(6)--AdaBoost
  • 3,通過計算a使得誤差率
    機器學習實戰(6)--AdaBoost
    最低,得到最低誤差。
  • 4,此時分類器的權值為:
    機器學習實戰(6)--AdaBoost
    。em <= 1/2時,am >= 0,且am随着em的減小而增大,意味着分類誤差率越小的基本分類器在最終分類器中的作用越大。
  • 5,更新樣本的權值:
    機器學習實戰(6)--AdaBoost
    使得被基本分類器Gm(x)誤分類樣本的權值增大,而被正确分類樣本的權值減小。就這樣,通過這樣的方式,AdaBoost方法能“聚焦于”那些較難分的樣本上。其中,Zm是規範化因子,使得Dm+1成為一個機率分布:
    機器學習實戰(6)--AdaBoost
  • 6,計算各個分類器的權重值:
    機器學習實戰(6)--AdaBoost
    ,得到最終的類别:
    機器學習實戰(6)--AdaBoost
  • 如果得到的各分類器的權重值還不滿足要求,誤差還很高,繼續上述的3,4,5,6步。

    (2)一個例子

    下面,給定下列訓練樣本,請用AdaBoost算法學習一個強分類器。

機器學習實戰(6)--AdaBoost

求解過程:初始化訓練資料的權值分布,令每個權值W1i = 1/N = 0.1,其中,N = 10,i = 1,2, …, 10,然後分别對于m = 1,2,3, …等值進行疊代。

疊代過程1:對于m=1,在權值分布為D1的訓練資料上,門檻值v取2.5時誤差率最低,故基本分類器為:

機器學習實戰(6)--AdaBoost

進而可得G1(x)在訓練資料集上的誤差率e1=P(G1(xi)≠yi) = 0.3

然後計算G1的系數:

機器學習實戰(6)--AdaBoost

接着更新訓練資料的權值分布:

機器學習實戰(6)--AdaBoost

最後得到各個資料的權值分布D2=(0.0715, 0.0715, 0.0715, 0.0715, 0.0715, 0.0715, 0.1666, 0.1666, 0.1666, 0.0715),分類函數f1(x)=0.4236G1(x),故最終得到的分類器sign(f1(x))在訓練資料集上有3個誤分類點。

疊代過程2:對于m=2,在權值分布為D2的訓練資料上,門檻值v取8.5時誤差率最低,故基本分類器為:

機器學習實戰(6)--AdaBoost

G2(x)在訓練資料集上的誤差率e2=P(G2(xi)≠yi) = 0.2143

計算G2的系數:

機器學習實戰(6)--AdaBoost

更新訓練資料的權值分布:

機器學習實戰(6)--AdaBoost

D3=(0.0455, 0.0455, 0.0455, 0.1667, 0.1667, 0.01667, 0.1060, 0.1060, 0.1060, 0.0455)

f2(x)=0.4236G1(x) + 0.6496G2(x)

分類器sign(f2(x))在訓練資料集上有3個誤分類點。

疊代過程3:對于m=3,在權值分布為D3的訓練資料上,門檻值v取5.5時誤差率最低,故基本分類器為:

機器學習實戰(6)--AdaBoost

G3(x)在訓練資料集上的誤差率e3=P(G3(xi)≠yi) = 0.1820

計算G3的系數:

機器學習實戰(6)--AdaBoost

更新訓練資料的權值分布:

機器學習實戰(6)--AdaBoost

D4=(0.125, 0.125, 0.125, 0.102, 0.102, 0.102, 0.065, 0.065, 0.065, 0.125),f3(x)=0.4236G1(x) + 0.6496G2(x)+0.7514G3(x),分類器sign(f3(x))在訓練資料集上有0個誤分類點。

3,Python實作

from numpy import *

def loadSimpData():
    datMat = matrix([[  ,  ],
        [  ,  ],
        [ ,   ],
        [  ,   ],
        [  ,   ]])
    classLabels = [, , -, -, ]
    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-):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-]))
    return dataMat,labelMat
#對資料進行分類,threshIneq表示兩種比較模式(>threshVal為1,或<threshVal為1),dimen是用來比較的特征的位置
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):#just classify the data
    retArray = ones((shape(dataMatrix)[],))
    if threshIneq == 'lt':
        retArray[dataMatrix[:,dimen] <= threshVal] = -
    else:
        retArray[dataMatrix[:,dimen] > threshVal] = -
    return retArray

#建立單層決策樹
def buildStump(dataArr,classLabels,D):
    dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
    m,n = shape(dataMatrix)
    numSteps = ; bestStump = {}; bestClasEst = mat(zeros((m,)))
    minError = inf #init error sum, to +infinity
    #計算在所有特征中能使得誤差率最小的特征是哪一個,并計算出用來分割的值,即在上文中的a
    for i in range(n):#loop over all dimensions
        #計算每個特征的最大值與最小值
        rangeMin = dataMatrix[:,i].min(); rangeMax = dataMatrix[:,i].max();
        #将最大值與最小值之間分為10段
        stepSize = (rangeMax-rangeMin)/numSteps
        #依次在最大值與最小值之間取值,計算誤差
        for j in range(-,int(numSteps)+):
            for inequal in ['lt', 'gt']: #go over less than and greater than
                threshVal = (rangeMin + float(j) * stepSize)
                predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)
                errArr = mat(ones((m,)))
                errArr[predictedVals == labelMat] = 
                weightedError = D.T*errArr  #calc total error multiplied by D
                if weightedError < minError:
                    minError = weightedError
                    bestClasEst = predictedVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump,minError,bestClasEst


def adaBoostTrainDS(dataArr,classLabels,numIt=):
    weakClassArr = []
    m = shape(dataArr)[]
    D = mat(ones((m,))/m)   #init D to all equal
    aggClassEst = mat(zeros((m,)))
    #疊代numIt次
    for i in range(numIt):
        #計算在目前樣本權值D下的最小誤差
        bestStump,error,classEst = buildStump(dataArr,classLabels,D)#build Stump
        #print "D:",D.T
        #calc alpha, throw in max(error,eps) to account for error=0
        alpha = float(*log((-error)/max(error,)))
        bestStump['alpha'] = alpha  
        #store Stump Params in Array
        weakClassArr.append(bestStump)                  
        expon = multiply(-*alpha*mat(classLabels).T,classEst) #exponent for D calc, getting messy
         #更新D
        D = multiply(D,exp(expon))                             
        D = D/D.sum()
        #classEst的值為1或-1,alpha*classEst為每一個分類器的權值與對應樣本的類别相乘,下式對所有的分類器進行相加,得到最終的類别,不過還要在用sign函數
        aggClassEst += alpha*classEst
        #sign(aggClassEst) != mat(classLabels).T不相等的位為1,相等的位為0,與ones((m,1)相乘,即得到誤差個數
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,)))
        errorRate = aggErrors.sum()/m
        print "total error: ",errorRate
        if errorRate == : break
    return weakClassArr,aggClassEst

#classifierArr即為上個方法傳回的weakClassArr,即每個分類器的最小誤差,分類所選取的特征,分割數a等
def adaClassify(datToClass,classifierArr):
    dataMatrix = mat(datToClass)#do stuff similar to last aggClassEst in adaBoostTrainDS
    m = shape(dataMatrix)[]
    aggClassEst = mat(zeros((m,)))
    for i in range(len(classifierArr)):
        classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],\
                                 classifierArr[i]['thresh'],\
                                 classifierArr[i]['ineq'])#call stump classify
        aggClassEst += classifierArr[i]['alpha']*classEst
        print aggClassEst
    return sign(aggClassEst)
           

繼續閱讀