adaboost 基於錯誤提升分類器


引自(機器學習實戰)

簡單概念

Adaboost是一種弱學習算法到強學習算法,這里的弱和強學習算法,指的當然都是分類器,首先我們需要簡單介紹幾個概念。

1:弱學習器:在二分情況下弱分類器的錯誤率會低於50%。其實任意的分類器都可以做為弱分類器,比如之前介紹的KNN、決策樹、Naïve Bayes、logiostic回歸和SVM都可以。這里我們采用的弱分類器是單層決策樹,它是一個單節點的決策樹。它是adaboost中最流行的弱分類器,當然並非唯一可用的弱分類器。即從特征中選擇一個特征來進行分類,該特征能使錯誤率達到最低,注意這里的錯誤率是加權錯誤率,為錯分樣本(1)與該樣本的權重的乘積之和(不明白看后面代碼)。

更為嚴格點的定義:

 

強學習:一個概念如果存在一個多項式的學習算法能夠學習它,並且正確率很高,那么,這個概念是強可學習的;
弱學習:一個概念如果存在一個多項式的學習算法能夠學習它,並且學習的正確率僅比隨機猜測略好(高於50%),那么,這個概念是弱可學習的;
強可學習與弱可學習是等價的。並且理論證明可以將若干個弱學習分類器通過線性疊加提升為強學習分類器。

 

 

2:強學習器:識別准確率很高並能在多項式時間內完成的學習算法

3:集成方法:就是將不同的分類器組合在一起,這種組合的結果就是集成方法或者稱為元算法。它可以是不同算法的集成,也可以是同一算法在不同設置下的集成,還可以是數據集的不同部分分配給不同分類器后的集成。

4:通常的集成方法有bagging方法和boosting方法,adaboost是boosting的代表算法,他們的區別在於:bagging方法(bootstrapaggregating),中文為自舉匯聚法,是從原始數據集重選擇(有放回,可以重復)得到S個新數據集的一種技術,每個新數據集樣本數目與原數據集樣本數目相等,這樣就可以得到S個分類器,再對這S個分類器進行疊加,他們的權重都相等(當然這里S個分類器采用的分類算法不一樣的話,可以考慮使用投票),這樣就可以得到一個強學習器。

而boosting方法是通過集中關注被已有分類器錯分的那些數據來獲得新的分類器,boosting算法中分類的權重並不相等,每個權重代表的是其對應分類器在上一輪迭代中的成功度。這里不是太明白的話,看完后面adaboost算法就會明白這句話的含義。

5:adaboost算法:機器學習實戰這本書上的描述和論文中的描述是一致的,見下面(前兩幅是書中描述,后一副是論文中描述)。

 

adaboost運行過程如下:訓練數據中的每一個樣本,賦予其一個權重,這些權重構成了向量D,一開始,這些權重都初始化成相等值。

首先在訓練數據中訓練出一個弱分類器並計算改分類器的錯誤率,然后在同一數據集上再次訓練弱分類器。在分類器的第二次訓練當中

,將會重新調整每個樣本的權重,其中第一次分對的樣本的權重將會降低,而第一次分錯的樣本權重將會提高。為了從所有弱分類器中

得到最終的分類結果,adaboost為每個分類器都分配一個權重值alpha,這些alpha值都是基於每個弱分類器的錯誤率進行計算的。

其中錯誤率定義為

            

alpha計算公式

              

 

問題:上題中的alpha為什么是這個公式呢?解釋為:-----再看沒看懂!!

 

 

 (1)基於單層決策樹構建弱分類器

def loadSimDat():  
    dataMat = matrix([[1, 2.1],  
                      [2.0, 1.1],  
                      [1.3, 1.0],  
                      [1.0, 1.0],  
                      [2.0, 1.0]])  
    classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]  
    return dataMat, classLabels  
  
# 單層決策樹生成函數  
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):#just classify the data  
    retArray = ones((shape(dataMatrix)[0],1))  
    if threshIneq == 'lt':  
        retArray[dataMatrix[:,dimen] <= threshVal] = -1.0  
    else:  
        retArray[dataMatrix[:,dimen] > threshVal] = -1.0  
    return retArray  
  
  
def buildStump(dataArr, classLabels, D):  
    dataMatrix = mat(dataArr); labelMat = 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)  
                predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)  
                errArr = mat(ones((m,1)))  
                errArr[predictedVals == labelMat] = 0  
                weightedError = D.T * errArr           #這里的error是錯誤向量errArr和權重向量D的相應元素相乘得到的即加權錯誤率  
                #print "split: dim %d, thresh %.2f, thresh inequal: %s, the weighted error is %.3f" %(i, threshVal, inequal, weightedError)  
                if weightedError < minError:  
                    minError = weightedError  
                    bestClassEst = predictedVals.copy()  
                    bestStump['dim'] = i  
                    bestStump['thresh'] = threshVal  
                    bestStump['ineq'] = inequal  
    return bestStump, minError, bestClassEst  

注意這里有三層循環構建了單層決策樹,最外層循環為遍歷特征,次外層循環為遍歷的步長,最內層為是否大於或小於閥值。構建的最小錯誤率為加權錯誤率,這就是為什么增加分錯樣本的權重,因為分錯樣本的權重增加了,下次如果繼續分錯,加權錯誤率會很大,這就不滿足算法最小化加權錯誤率了。此外,加權錯誤率在每次迭代過程中一定是逐次降低的。。

 (2)完整的adaboost算法

def adaBoostTrainDS(dataArr, classLabels, 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)  
       # 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    #累加變成強分類器  
        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  

注意代碼中的一個技巧max(error,le-16)用於確保在沒有錯誤時不會發生除零溢出。

(3)   測試算法:基於adaboost的分類

#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)  

 

此外如何理論上證明弱學習分類器可以通過線性疊加提升為強學習分類器,有兩種證明方法:(1)通過誤差上界,(2)通過adaboost的損失函數(指數損失函數)來證明。推導看以參看:http://blog.csdn.net/v_july_v/article/details/40718799, 其中我只看了誤差上界的推導。

誤差上界的結論表明,AdaBoost的訓練誤差是以指數速率下降的。另外,AdaBoost算法不需要事先知道下界γ,AdaBoost具有自適應性,它能適應弱分類器各自的訓練誤差率 。

只要保證弱分類器的錯誤率小於0.5,每次e^(2Mr^2))肯定是不斷減小的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM