自適應增強(Adaptive Boosting)


  • 簡介

AdaBoost,是英文”Adaptive Boosting“(自適應增強)的縮寫,是一種迭代提升算法,其核心思想是針對同一個訓練集訓練不同的分類器(弱分類器),然后把這些弱分類器集合起來,構成一個更強的最終分類器(強分類器)。

它的自適應在於:其算法本身是通過改變數據分布來實現的,它根據每次訓練集之中每個樣本的分類是否正確,以及上次的總體分類的准確率,來確定每個樣本的權值。將修改過權值的新數據集送給下層分類器進行訓練,最后將每次訓練得到的分類器最后融合起來,作為最后的決策分類器。

 

  • 基本思想

AdaBoost 的核心就是不斷迭代訓練弱分類器,並計算弱分類器的權重。需要注意的是,弱分類器的訓練依賴於樣本權重。每一輪迭代的樣本權重都不相同,依賴於弱分類器的權重值和上一輪迭代的樣本權重。具體過程如下:

1、訓練當前迭代最優弱分類器

  最優弱分類器是錯誤率最小的那個弱分類器。錯誤率的計算公式是:

  

  其中m = 1,2,..,M,代表第m輪迭代。i代表第i個樣本。w 是樣本權重。I指示函數取值為1或0,當I指示函數括號中的表達式為真時,I 函數結果為1;當I函數括號中的表達式為假時,I 函數結果為0。取錯誤率最低的弱分類器為當前迭代的最優弱分類器。

  第一輪迭代計算時樣本權重初始化為總樣本數分之一。

2、計算最優弱分類器的權重

  優弱分類器的權重只與該弱分類器的錯誤率有關。弱分類器的權重計算公式如下:

  

  可以看出,錯誤率越小,則 alpha 值越大,即該弱分類器的權重越高;反之,錯誤率越大,則 alpha 值越小,則該弱分類器的權重越小。這樣可以使分類精度高的弱分類器起到更大的作用,並削弱精度低的弱分類器的作用。

3、根據錯誤率更新樣本權重

  樣本權重的更新與當前樣本權重和弱分類器的權重有關。樣本權重更新公式如下:

  

  其中m = 1,2,..,M,代表第 m 輪迭代。i代表第i個樣本。w 是樣本權重。alpha 是弱分類器的權重。當樣本被正確分類時,y 和 Gm 取值一致,則新樣本權重變小;當樣本被錯誤分類時,y 和 Gm 取值不一致,則新樣本權重變大。這樣處理,可以使被錯誤分類的樣本權重變大,從而在下一輪迭代中得到重視。

4、迭代終止條件

  不斷重復1,2,3步驟,直到達到終止條件為止。終止條件是強分類器的錯誤率低於最低錯誤率閾值或達到最大迭代次數。

 

  • 舉例說明

數據集如表:

X 0 1 2 3 4 5
Y 1 1 -1 -1 1 -1

 

 

第一輪迭代

 

1、選擇最優弱分類器

第一輪迭代時,樣本權重初始化為(0.167, 0.167, 0.167, 0.167, 0.167, 0.167)。即1/6

表1數據集的切分點有0.5, 1.5, 2.5, 3.5, 4.5

若按0.5切分數據,得弱分類器x < 0.5,則 y = 1; x > 0.5, 則 y = -1。此時錯誤率為2 * 0.167 = 0.334

若按1.5切分數據,得弱分類器x < 1.5,則 y = 1; x > 1.5, 則 y = -1。此時錯誤率為1 * 0.167 = 0.167

若按2.5切分數據,得弱分類器x < 2.5,則 y = 1; x > 2.5, 則 y = -1。此時錯誤率為2 * 0.167 = 0.334

若按3.5切分數據,得弱分類器x < 3.5,則 y = 1; x > 3.5, 則 y = -1。此時錯誤率為3 * 0.167 = 0.501

若按4.5切分數據,得弱分類器x < 4.5,則 y = 1; x > 4.5, 則 y = -1。此時錯誤率為2 * 0.167 = 0.334

由於按1.5划分數據時錯誤率最小為0.167,則最優弱分類器為x < 1.5,則 y = 1; x > 1.5, 則 y = -1。

 

2、計算最優弱分類器的權重

alpha = 0.5 * ln((1 – 0.167) / 0.167) = 0.8047

 

3、更新樣本權重

x = 0, 1, 2, 3, 5時,y分類正確,則樣本權重為:

0.167 * exp(-0.8047) = 0.075

x = 4時,y分類錯誤,則樣本權重為:

0.167 * exp(0.8047) = 0.373

新樣本權重總和為0.075 * 5 + 0.373 = 0.748

規范化后,

x = 0, 1, 2, 3, 5時,樣本權重更新為:

0.075 / 0.748 = 0.10

x = 4時, 樣本權重更新為:

0.373 / 0.748 = 0.50

綜上,新的樣本權重為(0.1, 0.1, 0.1, 0.1, 0.5, 0.1)。

此時強分類器為G(x) = 0.8047 * G1(x)。G1(x)為x < 1.5,則 y = 1; x > 1.5, 則 y = -1。則強分類器的錯誤率為1 / 6 = 0.167。

 

第二輪迭代

 

1、選擇最優弱分類器

若按0.5切分數據,得弱分類器x > 0.5,則 y = 1; x < 0.5, 則 y = -1。此時錯誤率為0.1 * 4 = 0.4

若按1.5切分數據,得弱分類器x < 1.5,則 y = 1; x > 1.5, 則 y = -1。此時錯誤率為1 * 0.5 = 0.5

若按2.5切分數據,得弱分類器x > 2.5,則 y = 1; x < 2.5, 則 y = -1。此時錯誤率為0.1 * 4 = 0.4

若按3.5切分數據,得弱分類器x > 3.5,則 y = 1; x < 3.5, 則 y = -1。此時錯誤率為0.1 * 3 = 0.3

若按4.5切分數據,得弱分類器x < 4.5,則 y = 1; x > 4.5, 則 y = -1。此時錯誤率為2 * 0.1 = 0.2

由於按4.5划分數據時錯誤率最小為0.2,則最優弱分類器為x < 4.5,則 y = 1; x > 4.5, 則 y = -1。

 

2、計算最優弱分類器的權重

alpha = 0.5 * ln((1 –0.2) / 0.2) = 0.6931

 

3、更新樣本權重

x = 0, 1, 5時,y分類正確,則樣本權重為:

0.1 * exp(-0.6931) = 0.05

x = 4 時,y分類正確,則樣本權重為:

0.5 * exp(-0.6931) = 0.25

x = 2,3時,y分類錯誤,則樣本權重為:

0.1 * exp(0.6931) = 0.20

新樣本權重總和為 0.05 * 3 + 0.25 + 0.20 * 2 = 0.8

規范化后,

x = 0, 1, 5時,樣本權重更新為:

0.05 / 0.8 = 0.0625

x = 4時, 樣本權重更新為:

0.25 / 0.8 = 0.3125

x = 2, 3時, 樣本權重更新為:

0.20 / 0.8 = 0.250

綜上,新的樣本權重為(0.0625, 0.0625, 0.250, 0.250, 0.3125, 0.0625)。

此時強分類器為G(x) = 0.8047 * G1(x) + 0.6931 * G2(x)。G1(x)為x < 1.5,則 y = 1; x > 1.5, 則 y = -1。G2(x)為x < 4.5,則 y = 1; x > 4.5, 則 y = -1。

按G(x)分類會使x=4分類錯誤,則強分類器的錯誤率為1 / 6 = 0.167。

 

第三輪迭代

 

1、選擇最優弱分類器

若按0.5切分數據,得弱分類器x < 0.5,則 y = 1; x > 0.5, 則 y = -1。此時錯誤率為0.0625 + 0.3125 = 0.375

若按1.5切分數據,得弱分類器x < 1.5,則 y = 1; x > 1.5, 則 y = -1。此時錯誤率為1 * 0.3125 = 0.3125

若按2.5切分數據,得弱分類器x > 2.5,則 y = 1; x < 2.5, 則 y = -1。此時錯誤率為0.0625 * 2 + 0.250 + 0.0625 = 0.4375

若按3.5切分數據,得弱分類器x > 3.5,則 y = 1; x < 3.5, 則 y = -1。此時錯誤率為0.0625 * 3 = 0.1875

若按4.5切分數據,得弱分類器x < 4.5,則 y = 1; x > 4.5, 則 y = -1。此時錯誤率為2 * 0.25 = 0.5

由於按3.5划分數據時錯誤率最小為0.1875,則最優弱分類器為x > 3.5,則 y = 1; x < 3.5, 則 y = -1。

 

2、計算最優弱分類器的權重

alpha = 0.5 * ln((1 –0.1875) / 0.1875) = 0.7332

 

3、更新樣本權重

x = 2, 3時,y分類正確,則樣本權重為:

0.25 * exp(-0.7332) = 0.1201

x = 4 時,y分類正確,則樣本權重為:

0.3125 * exp(-0.7332) = 0.1501

x = 0, 1, 5時,y分類錯誤,則樣本權重為:

0.0625 * exp(0.7332) = 0.1301

新樣本權重總和為 0.1201 * 2 + 0.1501 + 0.1301 * 3 = 0.7806

規范化后,

x = 2, 3時,樣本權重更新為:

0.1201 / 0.7806 = 0.1539

x = 4時, 樣本權重更新為:

0.1501 / 0.7806 = 0.1923

x = 0, 1, 5時, 樣本權重更新為:

0.1301 / 0.7806 = 0.1667

綜上,新的樣本權重為(0.1667, 0.1667, 0.1539, 0.1539, 0.1923, 0.1667)。

 

此時強分類器為G(x) = 0.8047 * G1(x) + 0.6931 * G2(x) + 0.7332 * G3(x)。

G1(x)為x < 1.5,則 y = 1; x > 1.5, 則 y = -1。

G2(x)為x < 4.5,則 y = 1; x > 4.5, 則 y = -1。

G3(x)為x > 3.5,則 y = 1; x < 3.5, 則 y = -1。

按G(x)分類所有樣本均分類正確,則強分類器的錯誤率為0 / 6 = 0,則停止迭代。

最終強分類器為G(x) = 0.8047 * G1(x) + 0.6931 * G2(x) + 0.7332 * G3(x)。

 

  • 代碼實現

環境:MacOS mojave  10.14.3

Python  3.7.0

使用庫:scikit-learn    0.19.2

sklearn.ensemble.AdaBoostClassifier官方庫:https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.AdaBoostClassifier.html

 

AdaBoost.py  主程序和算法

import matplotlib.pyplot as plt
from prep_terrain_data import makeTerrainData
from class_vis import prettyPicture

features_train, labels_train, features_test, labels_test = makeTerrainData()


### the training data (features_train, labels_train) have both "fast" and "slow"
### points mixed together--separate them so we can give them different colors
### in the scatterplot and identify them visually
grade_fast = [features_train[ii][0] for ii in range(0, len(features_train)) if labels_train[ii]==0]
bumpy_fast = [features_train[ii][1] for ii in range(0, len(features_train)) if labels_train[ii]==0]
grade_slow = [features_train[ii][0] for ii in range(0, len(features_train)) if labels_train[ii]==1]
bumpy_slow = [features_train[ii][1] for ii in range(0, len(features_train)) if labels_train[ii]==1]


#### initial visualization
plt.xlim(0.0, 1.0)
plt.ylim(0.0, 1.0)
plt.scatter(bumpy_fast, grade_fast, color = "b", label="fast")
plt.scatter(grade_slow, bumpy_slow, color = "r", label="slow")
plt.legend()
plt.xlabel("bumpiness")
plt.ylabel("grade")

################################################################################


### your code here!  name your classifier object clf if you want the 
### visualization code (prettyPicture) to show you the decision boundary
from sklearn.ensemble import AdaBoostClassifier

clf = AdaBoostClassifier(n_estimators=100)
clf.fit(features_train,labels_train)

prettyPicture(clf, features_test, labels_test)
accuracy = clf.score(features_test, labels_test)
print (accuracy)

plt.show()

 

class_vis.py  繪圖與保存圖像

import numpy as np
import matplotlib.pyplot as plt
import pylab as pl

def prettyPicture(clf, X_test, y_test):
    x_min = 0.0; x_max = 1.0
    y_min = 0.0; y_max = 1.0
    
    # Plot the decision boundary. For that, we will assign a color to each
    # point in the mesh [x_min, m_max]x[y_min, y_max].
    h = .01  # step size in the mesh
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

    # Put the result into a color plot
    Z = Z.reshape(xx.shape)
    plt.xlim(xx.min(), xx.max())
    plt.ylim(yy.min(), yy.max())

    plt.pcolormesh(xx, yy, Z, cmap=pl.cm.seismic)

    # Plot also the test points
    grade_sig = [X_test[ii][0] for ii in range(0, len(X_test)) if y_test[ii]==0]
    bumpy_sig = [X_test[ii][1] for ii in range(0, len(X_test)) if y_test[ii]==0]
    grade_bkg = [X_test[ii][0] for ii in range(0, len(X_test)) if y_test[ii]==1]
    bumpy_bkg = [X_test[ii][1] for ii in range(0, len(X_test)) if y_test[ii]==1]

    plt.scatter(grade_sig, bumpy_sig, color = "b", )
    plt.scatter(grade_bkg, bumpy_bkg, color = "r",)
    plt.legend()
    plt.xlabel("bumpiness")
    plt.ylabel("grade")

    plt.savefig("test.png")
                                    

 

perp_terrain_data.py  生成訓練點

import random


def makeTerrainData(n_points=1000):
###############################################################################
### make the toy dataset
    random.seed(42)
    grade = [random.random() for ii in range(0,n_points)]
    bumpy = [random.random() for ii in range(0,n_points)]
    error = [random.random() for ii in range(0,n_points)]
    y = [round(grade[ii]*bumpy[ii]+0.3+0.1*error[ii]) for ii in range(0,n_points)]
    for ii in range(0, len(y)):
        if grade[ii]>0.8 or bumpy[ii]>0.8:
            y[ii] = 1.0

### split into train/test sets
    X = [[gg, ss] for gg, ss in zip(grade, bumpy)]
    split = int(0.75*n_points)
    X_train = X[0:split]
    X_test  = X[split:]
    y_train = y[0:split]
    y_test  = y[split:]

    grade_sig = [X_train[ii][0] for ii in range(0, len(X_train)) if y_train[ii]==0]
    bumpy_sig = [X_train[ii][1] for ii in range(0, len(X_train)) if y_train[ii]==0]
    grade_bkg = [X_train[ii][0] for ii in range(0, len(X_train)) if y_train[ii]==1]
    bumpy_bkg = [X_train[ii][1] for ii in range(0, len(X_train)) if y_train[ii]==1]

    training_data = {"fast":{"grade":grade_sig, "bumpiness":bumpy_sig}
            , "slow":{"grade":grade_bkg, "bumpiness":bumpy_bkg}}


    grade_sig = [X_test[ii][0] for ii in range(0, len(X_test)) if y_test[ii]==0]
    bumpy_sig = [X_test[ii][1] for ii in range(0, len(X_test)) if y_test[ii]==0]
    grade_bkg = [X_test[ii][0] for ii in range(0, len(X_test)) if y_test[ii]==1]
    bumpy_bkg = [X_test[ii][1] for ii in range(0, len(X_test)) if y_test[ii]==1]

    test_data = {"fast":{"grade":grade_sig, "bumpiness":bumpy_sig}
            , "slow":{"grade":grade_bkg, "bumpiness":bumpy_bkg}}

    return X_train, y_train, X_test, y_test

 

得到結果,正確率為92.4%

 

Adaboost的參數

n_estimators表示迭代的次數

n_estimators分別為100、1000、10000時:

 

正確率分別為:92.4%  91.6%  92%

 可以看出迭代次數越大,過擬合現象越嚴重,但正確率並無明顯變化,編譯時間略微增加。

 

  • AdaBoost優缺點

 優點:

1、可以將不同的分類算法作為弱分類器。

2、AdaBoost充分考慮的每個分類器的權重。

 

缺點:

1、AdaBoost迭代次數也就是弱分類器數目不太好設定。

2、數據不平衡導致分類精度下降。

3、訓練比較耗時,

 


免責聲明!

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



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