AdaBoost(自適應增強算法)

AdaBoost(自適應增強算法)

AdaBoost的目標是通過一個弱分類器構建一個強分類器,AdaBoost的大致運行過程:訓練數據中的每一個樣本,並賦予其一個權重,形成對應的權重向量D ,一開始所有訓練樣本具有相同權值,然後使用弱分類器分類並計算出該分類器的錯誤率,然後再統一數據集上面再次訓練弱分類器,在第二次訓練中,將會調整每個樣本的權值,其中第一次分隊的樣本的權重將會降低,第一次分錯的樣本權重將會提高。最終我們能得到一組分類器,通過,並且根據最終每個分類器的錯誤率爲每個分類器賦予一個權重值alpha , alpha 公式如下:

α=12ln(1ϵϵ)1
,當alpha 得到後我們對權重向量D 進行更新,使得正確分類的樣本權值降低,錯分樣本權重升高,計算方法如下:如果某個樣本被正確分類則權重值更改爲:
D(t+1)i=D(t)ieαSum(D)2
,如果某個樣本被錯分,那麼樣本的權重更改爲:
D(t+1)i=D(t)ieαSum(D)3
,通過不斷的訓練和調整權重產生新的分類器,知道訓練錯誤率爲0或者達到指定值爲止。

通過單層決策樹構建弱分類器

單層決策樹是一種簡單的決策樹,不像之前的介紹的決策樹,它只會做一層分裂,例如判斷數值大於指定值時歸類到class1,否則歸類到class2。
構建一個簡單的數據集:

dataMat = 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]


AdaBoost需要構建多個單層決策樹,多個決策樹組合起來實現正確的對數據集進行分類。
單層決策樹實現:

#dimen 表示特徵下標
#threshVal 表示分隔值
#threshIneq 表示分隔方式
def stumpClassify(dataMat, dimen, threshVal, threshIneq):
    retArray = ones((shape(dataMat)[0],1))
    if threshIneq == 'lt':
        for i in shape(dataMat)[0]:
            if dataMat[i][dimen] <= threshVal: retArray[i] = -1.0
    else:
        for i in shape(dataMat)[0]:
            if dataMat[i][dimen] > threshVal: retArray[i] = -1.0
    return retArray

AdaBoost算法實現:
通過下面的方法可選擇出在當前權重D 下最佳的決策分類信息,返回值分別爲當前最優分類器,當前分類器的誤差值,最終的分類結果。

#這裏的D爲每個樣本的初始權重,計算方式爲 D = ones((shape(dataMat)[0],1))/shape(dataMat)[0]
def buildStump(dataMat, classLabels, D):
    dataMatrix = mat(dataMat);labelMatrix=mat(classLabels).T
    m,n = shape(dataMatrix)
    numSteps = 10.0; bestStump ={};bestClassEst=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']:
                threshVal = (rangeMin + float(j) * stepSize)
                predictValue = stumpClassify(dataMatrix, i, threshVal, inequal)
                errArr = mat(ones((m,1)))
                for classIndex in range(0,m):
                    if errArr[classIndex] == labelMatrix[classIndex]:
                        errArr[classIndex]=0
                weightError = D.T * errArr
                if weightError < minError:
                    minError = weightError
                    bestClassEst = predictVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump, minError, bestClassEst

    Example Result:
    >>> bestStump
    {'dim': 0, 'ineq': 'lt', 'thresh': 1.3}
    >>> minError
    matrix([[ 0.2]])
    >>> bestClassEst
    array([[-1.],
           [ 1.],
           [-1.],
           [-1.],
           [ 1.]])

完整AdaBost Training 算法實現:
算法輸出結果爲一組弱分類器,每個分類器都有對應的權重值

def adaBoostTrainDS(dataArr, classLables, numIt=40):
    #用於存儲弱分類器組
    weakClassArr = []
    m = shape(dataArr)[0]
    #初始化訓練數據權重值
    D = mat(ones((m,1))/m)
    aggClassEst = mat(zeros((m,1)))

    for i in range(numIt):
        bestStump, error, classEst = buildStump(dataArr, classLabels, D)
        #計算alpha值
        alpha = float(0.5*log((1.0 - error)/max(error, 1e-16)))
        bestStump['alpha'] = alpha
        weakClassArr.append(bestStump)
        #更新權重向量D,數學公式參見上面的
        #得到的 expon爲一個 (m,1)的向量
        expon = multiply(-1*alpha*mat(classLabel).T, classEst)
        ##利用上面的 公式(2) 公式(3)更新 D
        D = multiply(D, exp(expon))
        D = D/D.sum()
        aggClassEst += alpha*classEst
        ##當前所有分類器組合得到的分類結果
        prediction = sign(aggClassEst)
        ##計算誤差值
        aggError = ones((m,1))
        for i in range(prediction.shape()[0]):
            if prediction[i] == classLabels.T[i] :
                aggError[i] = 0
        # 上面的for 循環可以簡單用下面的語句
        #aggErrors = multiply(sign(aggClassEst)!=mat(classLabels).T, ones((m,1)))

        #計算錯誤率
        errorRate = aggError.sum()/m
        if errorRate == 0.0: break;

    return weakClassArr

使用AdaBoost分類器進行分類目標數據

def adaClassify(dataToClass, classifierArr):
    dataMatrix = mat(dataToClass)
    m = shape(dataMatix)[0]
    ##現將測試數據的分類結果初始爲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+= classifier[i]['alpha']*classEst


    return sign(aggClassEst)

AdaBoost 分類性能調優

不同弱分類數目會存在不同的分類錯誤率,但並不是說弱分類器的數量越多分類錯誤率越低,通常情況下,AdaBoost會達到一個穩定的測試錯誤率,而並不會隨分類數目的增多而提高,另外一些情況下弱分類器數量當超過每一個最佳數值後,隨着弱分類器數量的增加,錯誤率也會隨之增高,這種現象稱之爲過擬合,因此在構造我們分類器時我們需要通過不斷分類錯誤率和分類器數目找到一個最佳的分類器數。
這是一個分類器數目和錯誤率映射case:

分類器數目 訓練錯誤率(%) 測試錯誤率(%)
1 0.28 0.27
10 0.23 0.24
50 0.19 0.21
100 0.19 0.22
500 0.16 0.25
1000 0.14 0.31
10000 0.11 0.33
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章