關於adaboost分類器


我花了將近一周的時間,才算搞懂了adaboost的原理。這根骨頭終究還是被我啃下來了。

Adaboost是boosting系的解決方案,類似的是bagging系,bagging系是另外一個話題,還沒有深入研究。Adaboost是boosting系非常流行的算法。但凡是介紹boosting的書籍無不介紹Adaboosting,也是因為其學習效果很好。

Adaboost首先要建立一個概念:

弱分類器,也成為基礎分類器,就是分類能力不是特別強,正確概率略高於50%的那種,比如只有一層的決策樹。boosting的原理就是整合弱分類器,使其聯合起來變成一種"強分類器"。

在Adaboost中,就是通過訓練出多個弱分類器,然后為他們賦權重;最后形成了一組弱分類器+權重的模型,

那么,關鍵來了怎么選擇弱分類器,怎么來分配權重?據說弱分類器可以是svm,可以是邏輯回歸;但是我看到資料和描述都是以決策樹為藍本的。

要想要搞懂adaboost,還要搞懂他的兩個層級的權重,第一個權重是上面我們講到的分類器的權重,成為alpha,是一個浮點型的值;

另外一個是樣本權重,稱之為D,是一個列向量,和每個樣本對應。首先講一下樣本權重,在一個分類器訓練出來之后,將會重新設置樣本權重,首個分類器他的樣本權重是一樣的,都是1/sample_count,然后每每次訓練完,都會調整這個這個樣本權重,為什么?我們繼續沿用決策樹說事。調整的策略就是增大預測錯誤的樣本的權重,為什么?樣本權重只有一個作用,就是計算錯誤權重,錯誤權重errorWeight=D.T * errorArr,errorArr是預測錯誤的列向量,預測正確的樣本對應值0,預測錯誤的為1,樣本權重D就是做件事情,那么對於決策樹模型而言,本輪某個特征判斷錯了,那么樣本其實就上了黑名單,用數學表示就是這個這個樣本的權重將會增加,

樣本權重增加導致了什么?其實不會導致什么,即使說明了某個樣本的錯誤比重要增加。所謂錯誤權重,都是判斷錯誤,如果歷史某個樣本已經判讀出錯過一次,那么這個樣本如果再錯,它的錯誤權重就要增加,這種權重的改變(D中元素wi的總和不變,保持為1),將會導致weighterror值更加有意義,判定最小weighterror也會更加准確。如果判斷對了,會相應的減小樣本的權重。

兩層的權重介紹完了,基本算法也就明了了。

下面即使就兩層權重來說明一下兩層算法。內層的算法是遍歷樣本中的每個特征,然后再從特征值的最小值開始嘗試進行分類,逐漸按照等量增加特征值不斷地嘗試分類一直達到最大值,走完了一輪特征,換下一個特征,在逐次增加特征值...計算下來每次嘗試的錯誤權重,記錄下來最小的錯誤權重的信息,信息包括:特征列索引,特征值以及邏輯比較(大於還是小於),當把所有的特征跑完一遍,到此,一個分類器就橫空出世了,設么是分類器?本質就是最小錯誤權重的信息,就是分類器。

 1 # 分類,滿足指定取值范圍的分類為-1,不滿足的為1
 2 def stumpClassifier(dataMat, dim, threshValue, inequal):
 3     #print("stumpClassifier-dataMat: ")
 4     #print(dataMat)
 5     retArr = ones((shape(dataMat)[0], 1))
 6     if(inequal=="lt"):
 7         retArr[dataMat[:,dim]<=threshValue] = -1
 8     else:
 9         retArr[dataMat[:,dim]>threshValue] = -1
10     return retArr
11 
12 # 返回一個弱分類器,本質上就是一個一層決策樹,這棵樹包括:
13 # 1.錯誤權重最低的區分特征以及特征值信息
14 # 2.最小錯誤權重
15 # 3.最小錯誤權重對應的預測分類
16 def buildstump(dataArr, labelArr, D):
17     datamat = mat(dataArr)
18     labelmat = mat(labelArr).T
19     m,n = shape(datamat)
20     errorArr = mat(zeros((m,1)))
21     beststump = {}
22     bestClassEst = mat(zeros((m, 1)))
23     minError = inf
24     numstep = 10.0 # 這里設置了一個float類型
25     # 遍歷每一列,尋求最分度最大的特征(維度)自己特征值
26     for i in range(n):
27         minvalue = datamat[:,i].min()
28         maxvalue = datamat[:,i].max()
29         stepsize = (maxvalue - minvalue)/numstep
30         for j in range(-1, int(numstep) + 1):
31             for ineq in ["lt", "gt"]:
32                 threshValue = minvalue + int(j) * stepsize
33                 predictValue = stumpClassifier(datamat, i, threshValue, ineq)
34                 errorArr = mat(ones((m, 1))) # 一個列向量
35                 # 這里設置分類正確的矩陣值為0,這樣在參與計算錯誤權重的時候,正確分類就不參與計算,只有錯誤分類錯誤的樣本才會參與計算
36                 errorArr[predictValue==labelmat] = 0
37                 # 這里注意,雖然是行向量和列向量相乘結果是累加值,但是形式還是一個矩陣,結果獲取方需要通過float等函數進行處理
38                 # D在初始化的時候是1/m,之后將會根據學習情況,提高錯誤樣本的權重,減少正確樣本點的權重
39                 weightError = D.T * errorArr
40                 #print("split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshValue, ineq, weightError))
41                 if(weightError < minError):
42                     minError = weightError
43                     bestClassEst = predictValue.copy()
44                     beststump["dim"] = i
45                     beststump["threshVal"] = threshValue
46                     beststump["ineq"] = ineq
47         
48     return beststump, minError, bestClassEst

作為外層算法,是一個循環調用內層算法的過程,每當獲得了一個分類器,都要為他計算權重,權重alpha的計算公式上面已經給出,總之和最小錯誤權重有關系,錯誤權重越小,分類器的權重越高,說明是優質分類器(相對的),反之亦然;然后就是累加權重alpha*預測值classEst,累加的目標就是sign和真實的分類器一致,注意是符號一致,真實分類器只有-1,1兩種值。如果一致了,退出循環;不一致,說明還要再引入分類器,此時再來計算D值(參見上文公式),然后基於D值再來調用內層算法。

這樣不斷獲得分類器,直到分類一致(或者循環次數達到指定次數)。外層算分目的是獲取到一組分類器,這組分類器是經過訓練,實現了全來一遍,就可以保證累加權重預測值之和的符號(sign)和真實的分類一致。

 1 from numpy import multiply
 2 from numpy import exp
 3 from numpy import zeros
 4 from numpy import log
 5 
 6 # adaboost本質其實就是將多個分類器按照訓練的權重進行整合,每個分類器都提供了區分度最高的特征以及特征值區分范圍(包括值以及lt/gt)
 7 # 在使用的時候因為是二元分類,所以每個分類器都是關注自己的識別出來的關鍵特征來進行分類,最后通過權重來進行整合。demo中的數據因為特征
 8 # 比較少,所以三輪下來就OK了,如果是多特征的需要更多分類器來進行是別的。
 9 def adaboostTransDS(dataArr, labelArr, itNum=41):
10     dataMat = mat(dataArr)
11     m = shape(dataMat)[0]
12     D = mat(ones((m, 1))/m)
13     weakClassArr=[]
14     aggClassEst=mat(zeros((m,1)))
15     for i in range(itNum):
16         # classESt代表的是本輪學習中,錯誤率最低的樣本預測分類情況
17         # 獲取一個分類器
18         bestStump, error, classEst = buildstump(dataMat, labelArr, D)
19         # 計算該分類器的alpha值,注意這里必須要通過float進行強壯,否則alpha將會是矩陣值形式,無法參與后續的計算。具體原因參見buildstump
20         # 注意alpha是分類器級別的權重,D則是分類器中樣本的權重;而且error越小,alpha越大,分類器的權重也越大
21         alpha = float(0.5 * log((1 - error)/ max(error, 1e-16)))
22         bestStump["alpha"] = alpha
23         # 添加該分類器的信息
24         weakClassArr.append(bestStump)
25         
26         # 計算下一個分類器中樣本的D值(權重),D值是
27         labelMat = mat(labelArr).T
28         alphaLabel = -1 * alpha * labelMat
29         # labelMat和classEst要么-1,要么1,這里的乘法就是要解決一個問題:判斷正確的是-alpha,判斷錯誤的是alpha,這個邏輯是
30         # 根據D的公式來的,通過這個符號實現如果是判斷正確,則減輕權重,判斷錯誤則家中權重;
31         # 之所以要加重錯誤列的權重是為了讓下一個分類器注意了,如果下一個分類器還是在此特征上面預測錯誤,那么錯誤權重會增加,這個
32         # 特征就作為最小錯誤權重(weihterror)特征出現的可能性就降低了。
33         expon = multiply((-1)*alpha * labelMat, classEst)
34         D = multiply(D ,exp(expon))
35         # D是如何保證D集合的值之和是1的呢?因為D/D.sum(),就像1/6,2/6,3/6之和為1的道理一樣的
36         D = D/D.sum()
37         print("alpha is: " + str(alpha))
38         #print("D is: ")
39         #print(D)
40         print("classEst:")
41         print(classEst)
42         # 計算Error值,這里其實是累加每個分類器的預測值,直到他們的累加值的符號和目標分類目標一致,所以錯誤率並不是每個分類器的錯誤率
43         # 而是分類器的分類預估*alpha的累加列向量vs原始分類列向量的錯誤率。
44         # 之類classEst是由-1和1組成,所以是帶有符號的
45         aggClassEst += alpha * classEst
46         #print("aggClassEst")
47         #print(aggClassEst)
48         errorMat = sign(aggClassEst) != labelMat
49         #print("errorMat")
50         #print(errorMat)
51         aggErrors = multiply(errorMat, ones((m,1)))
52         errorRate = aggErrors.sum() / m
53         print("error rate: %f" % errorRate)
54         
55         if(errorRate == 0.0):
56             break
57             
58     return weakClassArr

有了這組分類器,即adaboost classifieies,那么就可以進行分類了。

首先是獲取訓練數據集,然后通過外層算法獲取到adaboost classifieies(組分類器),這個是訓練過程;獲得了組分類器之后,在獲取測試數據集,然后遍歷分類器,讓每個分類器都對這批測試數據進行分類,每個分類器都會使用自己最好的分類方式(權重錯誤最低)來進行分類,即根據指定的特征,利用指定特征值進行比較分類;得到的分類結果(-1,1集合)將會乘以他們的權重(alpha),成為權重分類向量(weightClassEst);然后將各個分類器的權重分類向量進行累加(aggClassEst),最后取aggClassEst的符號作為分類結果。到此,分類結束。

 1 def adaClassifier(dataToClass, classifierArr):
 2     dataTestMat = mat(dataToClass)
 3     print("handler dataset is: ")
 4     print(dataTestMat)
 5     classifer_count = shape(classifierArr)[0]
 6     data_count = shape(dataTestMat)[0]
 7     aggClassEst = mat(zeros((data_count, 1)))
 8     for i in range(classifer_count):
 9         classifier = classifierArr[i]
10         print(classifier)
11         classEst = stumpClassifier(dataTestMat, classifier["dim"], classifier["threshVal"], classifier["ineq"])
12         aggClassEst += classifier["alpha"]*classEst
13         print("aggClassEst")
14         print(aggClassEst)
15     return sign(aggClassEst)
16 
17 # 開始分類
18 dataMat, labelArr = loadSimpData()
19 classifierArr = adaboostTransDS(dataMat, labelArr, 9)
20 adaClassifier([[0,0],[5,5]], classifierArr)

 


免責聲明!

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



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