AdaBoost的全稱是(Adaptiva Boosting),即自適應(yīng)提升方法。他的自適應(yīng)在于:前一個(gè)弱分類器分錯(cuò)的樣本權(quán)重會(huì)得到加強(qiáng),權(quán)重更新后的全體樣本再次被用來(lái)訓(xùn)練下一個(gè)弱分類器。同時(shí),在每一輪中加入一個(gè)新的弱分類器,直到達(dá)到某個(gè)預(yù)定的足夠小的錯(cuò)誤率或達(dá)到預(yù)先指定的最大迭代次數(shù)。
具體來(lái)講,AdaBoost算法可以分為三步:
初始化訓(xùn)練數(shù)據(jù)的權(quán)值分布。如果有N個(gè)樣本,則每一個(gè)訓(xùn)練樣本最開(kāi)始時(shí)都被賦予相同的權(quán)值:1/N。
訓(xùn)練弱分類器。具體訓(xùn)練過(guò)程中,如果某個(gè)樣本點(diǎn)已經(jīng)被準(zhǔn)確地分類,那么在構(gòu)造下一個(gè)訓(xùn)練集中,它的權(quán)值就被降低;相反,如果某個(gè)樣本點(diǎn)沒(méi)有被準(zhǔn)確地分類,那么它的權(quán)值就得到提高。然后,權(quán)值更新過(guò)的樣本集被用于訓(xùn)練下一個(gè)分類器,整個(gè)訓(xùn)練過(guò)程如此迭代地進(jìn)行下去。
將各個(gè)訓(xùn)練得到的弱分類器組合成強(qiáng)分類器。各個(gè)弱分類器的訓(xùn)練過(guò)程結(jié)束后,加大分類誤差率小的弱分類器的權(quán)重,使其在最終的分類函數(shù)中起著較大的決定作用,而降低分類誤差率大的弱分類器的權(quán)重,使其在最終的分類函數(shù)中起著較小的決定作用。換言之,誤差率低的弱分類器在最終分類器中占的權(quán)重較大,否則較小。
AdaBoost二分類問(wèn)題算法流程
-
初始化每個(gè)訓(xùn)練樣本的權(quán)重值,每個(gè)樣本的權(quán)重相等,共N個(gè)樣本。
-
循環(huán),對(duì)第t=1,2,...,T個(gè)弱分類器依次訓(xùn)練:
- 訓(xùn)練權(quán)重分布為
的樣本數(shù)據(jù),得到弱分類器
,計(jì)算它對(duì)樣本集的錯(cuò)誤率
- 計(jì)算弱分類器的權(quán)重
- 更新訓(xùn)練樣本的權(quán)重
其中
為歸一化因子,是所有訓(xùn)練樣本的權(quán)重之和,
- 訓(xùn)練權(quán)重分布為
-
結(jié)束循環(huán),得到一系列的權(quán)重為
的弱分類器
,將弱分類器根據(jù)權(quán)重線性組合,得到最終的強(qiáng)分類器:
關(guān)于弱分類器權(quán)重和樣本權(quán)重的分析(二分類問(wèn)題)
關(guān)于弱分類器的權(quán)重,由于每個(gè)弱分類器的分類性能要好于隨機(jī)分類器,故而誤差率,
且
隨著
的減小而增大,所以,分類誤差率越小的弱分類器在最終的分類器中所占的權(quán)重越大。
對(duì)于被被弱分類器正確分類的樣本,有:
對(duì)于被弱分類器錯(cuò)誤分類的樣本,有:
其中代表真實(shí)分布,
代表弱學(xué)習(xí)器的預(yù)測(cè)值即非真實(shí)分布。
因此樣本權(quán)重的更新公式可以寫成:
又有:
由于大于0,故而
小于1,分對(duì)的樣本權(quán)重減小;
大于1,分錯(cuò)的樣本權(quán)重增大。
AdaBoost多分類
對(duì)于多分類問(wèn)題,流程原理與二分類基本類似。
只是弱學(xué)習(xí)器的權(quán)重為
其中R是類別的數(shù)量,對(duì)于二分類問(wèn)題,R=2,于是有了
對(duì)于樣本權(quán)重的更新,公式為:
對(duì)于弱學(xué)習(xí)器正確分類的樣本,返回False,也就是0,權(quán)重不變
對(duì)于弱學(xué)習(xí)器錯(cuò)誤分類的樣本,返回True,也就是1,權(quán)重放大
對(duì)于多分類的輸出,我們可以轉(zhuǎn)換成二進(jìn)制編碼,或者叫獨(dú)熱編碼,舉個(gè)例子:
例如三分類,類別一可以用[1,0,0]表示,類別二可以用[0,1,0]表示,類別三可以用[0,0,1]表示。
AdaBoost算例
接下來(lái)我們通過(guò)一個(gè)算例,比較sklearn中AdaBoost算法的計(jì)算結(jié)果和我們手動(dòng)計(jì)算的結(jié)果,進(jìn)一步了解AdaBoost算法的流程和原理。
給定以下訓(xùn)練樣本:
| X | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
| Y | 1 | 1 | 1 | -1 | -1 | -1 | 1 | 1 | 1 | -1 |
以sklearn中AdaBoost算法,訓(xùn)練這10個(gè)樣本數(shù)據(jù)。
# 導(dǎo)包
from sklearn.ensemble import AdaBoostClassifier
import numpy as np
from sklearn import tree
# 樣本數(shù)據(jù)
X = np.arange(10).reshape(-1,1)
y = np.array([1,1,1,-1,-1,-1,1,1,1,-1])
# 訓(xùn)練和預(yù)測(cè)數(shù)據(jù)
ada = AdaBoostClassifier(algorithm='SAMME',n_estimators=3)
ada.fit(X,y)
ada.predict(X) # 結(jié)果為array([ 1, 1, 1, -1, -1, -1, 1, 1, 1, -1])
# 分別畫出3棵樹(shù)
_ = tree.plot_tree(ada[0],filled=True)
ada[0].predict(X)
# _ = tree.plot_tree(ada[0],filled=True)
# ada[0].predict(X)
# _ = tree.plot_tree(ada[0],filled=True)
# ada[0].predict(X)
畫出三棵樹(shù),我們可以看出依次是從第3個(gè),第9個(gè),第6個(gè)樣本劃分分類。
接下來(lái)我們根據(jù)上文的公式來(lái)看看AdaBoost的算法流程。
初始化,每個(gè)樣本的權(quán)重都為0.1
w1 = np.full(shape = 10,fill_value=0.1)
w1
第一棵樹(shù)劃分前,將10個(gè)樣本劃分為10個(gè)閾值,以最小誤差率劃分。
t = np.arange(0.5,10)
print(t)
for i,t_i in enumerate(t,start = 1):#enumerate,獲取索引,默認(rèn)從0開(kāi)始,
# y_是弱分類器,預(yù)測(cè)值
y_ = np.array([1]*i + [-1]*(10-i))
# print(y_)
print(t_i,((y !=y_)*w1).sum())
從結(jié)果可以看出閾值為2.5或者8.5時(shí)誤差最小,所以從第三個(gè)樣本劃分。
然后根據(jù)公式計(jì)算第一個(gè)弱學(xué)習(xí)器的權(quán)重
e1 = 0.3
alpha1 = 1/2*np.log((1-e1)/e1)
print('第一個(gè)學(xué)習(xí)器的權(quán)重:',alpha1)
得到結(jié)果為 0.42364893019360184
接下來(lái)更新所有樣本的權(quán)重
y_ = np.array([1]*3 + [-1]*7) # f(x)
w2 = w1*np.exp(-y*y_*alpha1)
w2 = w2/w2.sum()
print('更新后樣本的權(quán)重:',w2)
同理,第二棵樹(shù)和第三棵樹(shù)也能同樣計(jì)算出來(lái)
第二棵樹(shù):
# 根據(jù)結(jié)果找出從第九棵樹(shù)劃分
t = np.arange(0.5,10)
print(t)
for i,t_i in enumerate(t,start = 1):#enumerate,獲取索引,默認(rèn)從0開(kāi)始,
# y_是弱分類器,預(yù)測(cè)值
y_ = np.array([1]*i + [-1]*(10-i))
print(t_i,((y !=y_)*w2).sum())
# 計(jì)算第二個(gè)弱學(xué)習(xí)器的權(quán)重
e2 = 0.214
alpha2 = 1/2*np.log((1-e2)/e2)
print('第二個(gè)學(xué)習(xí)器的權(quán)重:',alpha2)
# 更新樣本的權(quán)重
y_ = np.array([1]*9 + [-1]*1) # f(x)
w3 = w2*np.exp(-y*y_*alpha2)
w3 = w3/w3.sum()
print('更新后樣本的權(quán)重:',w3)
第二棵樹(shù)是從第九個(gè)樣本劃分,權(quán)重是 0.6504903887036776
第三棵樹(shù):
t = np.arange(0.5,10)
print(t)
for i,t_i in enumerate(t,start = 1): #enumerate,獲取索引,默認(rèn)從0開(kāi)始,
# y_是弱分類器,預(yù)測(cè)值
y_ = np.array([-1]*i + [1]*(10-i))
print(t_i,((y !=y_)*w3).sum())
# 計(jì)算第三個(gè)弱學(xué)習(xí)器的權(quán)重
e3 = 0.18163
alpha3 = 1/2*np.log((1-e3)/e3)
print('第二個(gè)學(xué)習(xí)器的權(quán)重:',alpha3)
# 更新樣本的權(quán)重
y_ = np.array([-1]*6 + [1]*4) # f(x)
w4 = w3*np.exp(-y*y_*alpha3)
w4 = w4/w4.sum()
print('更新后樣本的權(quán)重:',w4)
第三棵樹(shù)是從第6個(gè)樣本劃分,權(quán)重是 0.7526714531563444
接下來(lái)將弱學(xué)習(xí)器組合成強(qiáng)學(xué)習(xí)器
print(alpha1,alpha2,alpha3)
# 0.42364893019360184 0.6504903887036776 0.7526714531563444
# 第一棵樹(shù)ft(x)
y1 = np.array([1]*3 + [-1]*(10-3))
# 第二棵樹(shù)的預(yù)測(cè)值
y2 = np.array([1]*9 + [-1]*(10-9))#預(yù)測(cè)值
# 第三棵樹(shù),預(yù)測(cè)值
y3 = np.array([-1]*6 + [1]*(10-6))
F = alpha1*y1 + alpha2*y2 + alpha3*y3
# 將多個(gè)弱分類器,整合,變成了強(qiáng)分類器F(X)
F
打印輸出結(jié)果為:
array([ 0.32146787, 0.32146787, 0.32146787, -0.52582999, -0.52582999,
-0.52582999, 0.97951291, 0.97951291, 0.97951291, -0.32146787])
根據(jù)F的結(jié)果,劃分為類別1和類別-1
result = [-1 if i <0 else 1 for i in F]
result
[1, 1, 1, -1, -1, -1, 1, 1, 1, -1]
結(jié)果和sklearn中算法計(jì)算的一樣!
總結(jié)
AdaBoost算是是一種實(shí)現(xiàn)簡(jiǎn)單、易于運(yùn)用的算法,具有分類精度高,不會(huì)出現(xiàn)過(guò)擬合的優(yōu)點(diǎn),是一種適用于各種分類場(chǎng)景下應(yīng)用的算法。