AdaBoost 演算法-分析波士頓房價資料集

碼農充電站發表於2020-12-17

公號:碼農充電站pro
主頁:https://codeshellme.github.io

在機器學習演算法中,有一種演算法叫做整合演算法AdaBoost 演算法是整合演算法的一種。我們先來看下什麼是整合演算法。

1,整合演算法

通常,一個 Boss 在做一項決定之前,會聽取多個 Leader 的意見。整合演算法就是這個意思,它的基本含義就是集眾演算法之所長

前面已經介紹過許多演算法,每種演算法都有優缺點。那麼是否可以將這些演算法組合起來,共同做一項決定呢?答案是肯定的。這就誕生了整合演算法Ensemble Methods)。

整合演算法的基本架構如下:

在這裡插入圖片描述

演算法的組合有多種形式,比如將不同的演算法整合起來,或者將同一種演算法以不同的形式整合起來。

常見的整合演算法有四大類:

  • bagging:裝袋法,代表演算法為 RandomForest(隨機森林)。
  • boosting:提升法,代表演算法有 AdaBoostXGBoost 等。
  • stacking:堆疊法。
  • blending:混合法。

多個演算法以不同的方式可以組合成整合演算法,如果再深入探究的話,不同的整合方法也可以組合起來:

  • 如果將 boosting 演算法的輸出作為bagging 演算法的基學習器,得到的是 MultiBoosting 演算法;
  • 如果將 bagging 演算法的輸出作為boosting 演算法的基學習器,得到的是 IterativBagging 演算法。

對於整合演算法的整合,這裡不再過多介紹。

2,bagging 與 boosting 演算法

baggingboosting是兩個比較著名的整合演算法。

bagging 演算法

bagging 演算法是將一個原始資料集隨機抽樣成 N 個新的資料集。然後將這N 個新的資料集作用於同一個機器學習演算法,從而得到 N 個模型,最終整合一個綜合模型

在對新的資料進行預測時,需要經過這 N 個模型(每個模型互不依賴干擾)的預測(投票),最終綜合 N 個投票結果,來形成最後的預測結果。

在這裡插入圖片描述

boosting 演算法

boosting 演算法的含義為提升學習,它將多個弱分類器組合起來形成一個強分類器

boosting 演算法是將一個原始資料集使用同一個演算法迭代學習 N 次,每次迭代會給資料集中的樣本分配不同的權重。

分類正確的樣本會在下一次迭代中降低權重,而分類錯誤的樣本會在下一次迭代中提高權重,這樣做的目的是,使得演算法能夠對其不擅長(分類錯誤)的資料不斷的加強提升學習,最終使得演算法的成功率越來越高。

每次迭代都會訓練出一個新的帶有權重的模型,迭代到一定的次數或者最終模型的錯誤率足夠低時,迭代停止。最終整合一個強大的綜合模型

在對新的資料進行預測時,需要經過這 N 個模型的預測,每個模型的預測結果會帶有一個權重值,最終綜合 N 個模型結果,來形成最後的預測結果。

在這裡插入圖片描述

boosting 演算法中每個模型的權重是不相等的,而bagging 演算法中每個模型的權重是相等的。

3,AdaBoost 演算法

AdaBoost 演算法是非常流行的一種 boosting 演算法,它的全稱為 Adaptive Boosting,即自適應提升學習

AdaBoost 演算法FreundSchapire1995 年提出。這兩位作者寫了一篇關於AdaBoost 的簡介論文,這應該是關於AdaBoost 演算法的最權威的資料了。為了防止連結丟失,我將論文下載了,放在了這裡

AdaBoost 演算法SVM 演算法被很多人認為是監督學習中最強大的兩種演算法。

AdaBoost 演算法的執行過程如下:

  1. 為訓練集中的每個樣本初始化一個權重 wi,初始時的權重都相等。
  2. 根據樣本訓練出一個模型 Gi,並計算該模型的錯誤率 ei 和權重 ai
  3. 根據權重 ai 將每個樣本的權重調整為 wi+1,使得被正確分類的樣本權重降低,被錯誤分類的樣本權重增加(這樣可以著重訓練錯誤樣本)。
  4. 這樣迭代第2,3 步,直到訓練出最終模型。

這個過程中,我們假設 x 為樣本,Gi(x) 為第 i 輪訓練出的模型,aiGi(x) 的權重,一共迭代 n 輪,那麼最終模型 G(x) 的計算公式為:

在這裡插入圖片描述

模型權重 ai 的計算公式如下,其中 ei 為第 i 輪模型的錯誤率:

在這裡插入圖片描述

我們用 Dk+1 ​代表第 k+1 輪的樣本的權重集合,用 Wk+1,1 代表第 k+1 輪中第1個樣本的權重, Wk+1,N 代表第 k+1 輪中第 N 個樣本的權重,用公式表示為:

在這裡插入圖片描述

樣本權重 Wk+1,i 的計算公式為:

在這裡插入圖片描述

其中:

  • yixi 的目標值。
  • Zk 為歸一化因子,使得 Dk+1 成為一個概率分佈。
  • exp 為指數函式。

4,AdaBoost 演算法示例

下面我們以一個二分類問題,來看一下AdaBoost 演算法的計算過程。

假設我們有10 個樣本資料,X 為特徵集,Y 為目標集,如下:

X Y
0 1
1 1
2 1
3 -1
4 -1
5 -1
6 1
7 1
8 1
9 -1

假設有三個分類器,分別以2.5,5.5,8.5將資料分界:

在這裡插入圖片描述

簡單看下其分佈圖:

根據這三個分類器,我們可以算出每個樣本對應的值:

X Y f1(x) f2(x) f3(x)
0 1 1 -1 1
1 1 1 -1 1
2 1 1 -1 1
3 -1 -1 -1 1
4 -1 -1 -1 1
5 -1 -1 -1 1
6 1 -1 1 1
7 1 -1 1 1
8 1 -1 1 1
9 -1 -1 1 -1

上面表格中,對於每個分類器分類錯誤的資料,我進行了標紅

第一輪

將每個樣本的權重初始化為0.1

  • D1 = (0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1)

根據 D1 計算每個分類器的錯誤率:

  • e1(x) = 0.1*3 = 0.3
  • e2(x) = 0.1*4 = 0.4
  • e3(x) = 0.1*3 = 0.3

選擇錯誤率最小的分類器作為第1輪的分類器,因為 f1(x)和 f3(x) 的錯誤率都是0.3,所以可以任意選一個,比如我們選 f1(x),所以 G1(x) = f1(x)。

計算 G1(x) 的權重 a1(x)

  • a1(x) = (1/2) * log((1-0.3)/0.3) = 0.42

這裡的 loge 為底。

計算第2輪的樣本權重D2,首先需要根據Zk 的公式來計算 Z1,先計算 -a1yiG1(xi) ,如下:

序號 i yi G1(xi) -a1yiG1(xi)
1 1 1 -0.42 x 1 x 1 => -0.42
2 1 1 -0.42 x 1 x 1 => -0.42
3 1 1 -0.42 x 1 x 1 => -0.42
4 -1 -1 -0.42 x -1 x -1 => -0.42
5 -1 -1 -0.42 x -1 x -1 => -0.42
6 -1 -1 -0.42 x -1 x -1 => -0.42
7 1 -1 -0.42 x 1 x -1 => 0.42
8 1 -1 -0.42 x 1 x -1 => 0.42
9 1 -1 -0.42 x 1 x -1 => 0.42
10 -1 -1 -0.42 x -1 x -1 => -0.42

那麼 Z1 = 0.1 * (7 * e^-0.42 + 3 * e^0.42) = 0.92

再根據樣本權重的計算公式可以得出:

  • D2 = (0.0715, 0.0715, 0.0715, 0.0715, 0.0715, 0.0715, 0.1666, 0.1666, 0.1666, 0.0715)

第二輪

根據 D2 計算每個分類器的錯誤率:

  • e1(x) = 0.1666*3 = 0.4998
  • e2(x) = 0.0715*4 = 0.286
  • e3(x) = 0.0715*3 = 0.2145

選擇錯誤率最小的分類器作為第2輪的分類器,所以 G2(x) = f3(x)。

計算 G2(x) 的權重 a2(x)

  • a2(x) = (1/2) * log((1-0.2145)/0.2145) = 0.65

計算第3輪每個樣本的權重:

  • D3 = (0.0455,0.0455,0.0455,0.1667, 0.1667,0.01667,0.1060, 0.1060, 0.1060, 0.0455)

這裡省略了D3 的計算過程,其計算過程與D2 一樣。

第三輪

根據 D3 計算每個分類器的錯誤率:

  • e1(x) = 0.1060*3 = 0.318
  • e2(x) = 0.0455*4 = 0.182
  • e3(x) = 0.1667*3 = 0.5

選擇錯誤率最小的分類器作為第3輪的分類器,所以 G3(x) = f2(x)。

計算 G3(x) 的權重 a3(x)

  • a3(x) = (1/2) * log((1-0.182)/0.182) = 0.75

如果我們只迭代三輪,那麼最終的模型 G(x) = 0.42G1(x) + 0.65G2(x) + 0.75G3(x)。

在這裡插入圖片描述

有了最終的模型G(x),我們根據G(x) 來計算每個樣本對應的值:

G0 = 0.42 + 0.65 - 0.75  = 0.32  =>  1
G1 = 0.42 + 0.65 - 0.75  = 0.32  =>  1
G2 = 0.42 + 0.65 - 0.75  = 0.32  =>  1
G3 = -0.42 + 0.65 - 0.75 = -0.52 => -1
G4 = -0.42 + 0.65 - 0.75 = -0.52 => -1
G5 = -0.42 + 0.65 - 0.75 = -0.52 => -1
G6 = -0.42 + 0.65 + 0.75 = 0.98  =>  1
G7 = -0.42 + 0.65 + 0.75 = 0.98  =>  1
G8 = -0.42 + 0.65 + 0.75 = 0.98  =>  1
G9 = -0.42 - 0.65 + 0.75 = -0.32 => -1

因為本例是一個二分類問題,所以對於值大於 0 均取 1,值小於 0 均取 -1

最終可以得到如下表格:

X Y G(x)
0 1 1
1 1 1
2 1 1
3 -1 -1
4 -1 -1
5 -1 -1
6 1 1
7 1 1
8 1 1
9 -1 -1

可以看到經過提升學習後的模型的準確率提高到了100%

當然對於實際問題,準確率基本達不到100%

以上就是一個簡化版的 AdaBoost 演算法的計算過程。

本例的原型出自《統計學習方法 · 李航》

5,sklearn 對 AdaBoost 的實現

sklearn 庫的 ensemble 模組實現了一系列的整合演算法,對於整合方法的介紹,可以參看這裡

AdaBoost 演算法即可用於分類問題,也可用於迴歸問題:

來看下 AdaBoostClassifier 類的原型:

AdaBoostClassifier(
  base_estimator=None, 
  n_estimators=50, 
  learning_rate=1.0, 
  algorithm='SAMME.R', 
  random_state=None)

其引數含義:

  • base_estimator:代表弱分類器,預設使用的是決策樹
    • 對於 AdaBoostClassifier 預設使用的是 DecisionTreeClassifier(max_depth=1)
    • 對於 AdaBoostRegressor 預設使用的是 DecisionTreeRegressor(max_depth=3)
    • 一般不需要修改這個引數,當然也可以指定具體的分類器。
  • n_estimators:最大迭代次數,也是分類器的個數,預設是 50。
  • learning_rate:代表學習率,取值在 0-1 之間,預設是 1.0。
    • 學習率和迭代次數是相關的,如果學習率較小,就需要比較多的迭代次數才能收斂。
    • 所以如果調整了 learning_rate,一般也需要調整 n_estimators
  • algorithm:代表採用哪種 boosting 演算法,有兩種選擇:SAMMESAMME.R,預設是 SAMME.R
    • SAMMESAMME.R 的區別在於對弱分類權重的計算方式不同。
    • SAMME.R 的收斂速度通常比 SAMME 快。
  • random_state:代表隨機數種子,預設是 None。
    • 隨機種子用來控制隨機模式,當隨機種子取了一個值,也就確定了一種隨機規則,其他人取這個值可以得到同樣的結果。
    • 如果不設定隨機種子,每次得到的隨機數也就不同。

再來看下 AdaBoostRegressor 類的原型:

AdaBoostRegressor(
  base_estimator=None, 
  n_estimators=50, 
  learning_rate=1.0, 
  loss='linear', 
  random_state=None)

可以看到,迴歸和分類的引數基本一致,而回歸演算法裡沒有 algorithm 引數,但多了 loss 引數。

loss 引數代表損失函式,用於(每次迭代後)更新樣本的權重,其共有 3 種選擇,分別為:

  • linear,代表線性函式。
  • square,代表平方函式。
  • exponential,代表指數函式。
  • 預設是 linear,一般採用線性就可得到不錯的效果。

6,使用 AdaBoost 進行迴歸分析

接下來,我們看下如何用 AdaBoost 演算法進行迴歸分析。

之前在文章《決策樹演算法-實戰篇-鳶尾花及波士頓房價預測》中,我們介紹過波士頓房價資料集,這裡不再對資料本身進行過多介紹,下面我們用 AdaBoost 演算法來分析該資料集。

首先載入資料集:

from sklearn.datasets import load_boston

boston = load_boston()
features = boston.data # 特徵集
prices = boston.target # 目標集

將資料拆分成訓練集和測試集:

from sklearn.model_selection import train_test_split
train_x, test_x, train_y, test_y = train_test_split(
    features, prices, test_size=0.25, random_state=33)

構建 AdaBoost 迴歸模型:

from sklearn.ensemble import AdaBoostRegressor
regressor = AdaBoostRegressor()  # 均採用預設引數
regressor.fit(train_x, train_y)  # 擬合模型

使用模型進行預測:

pred_y = regressor.predict(test_x)

評價模型準確率:

from sklearn.metrics import mean_squared_error

mse = mean_squared_error(test_y, pred_y)
print "AdaBoost 均方誤差 = ", round(mse, 2) # 18.57

7,分析 AdaBoost 模型的屬性

base_estimator_ 屬性是基學習器,也就是訓練之前的模型:

>>> regressor.base_estimator_
DecisionTreeRegressor(criterion='mse', 
    max_depth=3, max_features=None,
    max_leaf_nodes=None, min_impurity_decrease=0.0,
    min_impurity_split=None, min_samples_leaf=1,
    min_samples_split=2, min_weight_fraction_leaf=0.0,
    presort=False, random_state=None, splitter='best')

estimators_ 屬性是經過訓練之後的所有弱學習器,有 50 個:

>>> len(regressor.estimators_)
50

feature_importances_ 屬性中儲存了每個特徵的重要性:

>>> regressor.feature_importances_
array([0.02104728, 0.        , 0.00304314,
       0.        , 0.00891602, 0.2825294 ,
       0.00438134, 0.17308669, 0.00929782,
       0.07457966, 0.02250937, 0.00592025, 
       0.39468902])

estimator_weights_ 屬性是每個弱學習器的權重:

>>> regressor.estimator_weights_
array([2.39259487, 2.02119506, 1.68364189, 0.71892012, 2.01966649,
       1.03178435, 1.14573926, 2.15335207, 1.62996738, 1.39576421,
       1.42582945, 0.55214963, 1.17953337, 0.20934333, 0.3022646 ,
       1.73484417, 1.36590071, 0.27471584, 0.97297267, 0.21729445,
       1.97061649, 0.91072652, 1.95231025, 0.11764431, 1.19301792,
       0.21629414, 1.57477075, 1.23626619, 1.21423494, 0.24063141,
       0.08265621, 0.17198137, 0.58300858, 0.72722721, 2.07974547,
       0.61855751, 1.98179632, 0.5886063 , 0.18646107, 0.38176832,
       1.11993353, 1.81984396, 1.06785584, 0.45475221, 1.85522596,
       0.29177236, 1.0699074 , 1.79358974, 1.37771849, 0.15698322])

estimator_errors_ 屬性是每個弱學習器的錯誤率:

>>> regressor.estimator_errors_
array([0.08373912, 0.11699548, 0.15661382, 0.32763082, 0.11715348,
       0.26273832, 0.24126819, 0.1040184 , 0.16383483, 0.19848913,
       0.19374934, 0.36536582, 0.23513611, 0.44785447, 0.42500398,
       0.149969  , 0.20328296, 0.43174973, 0.27428838, 0.44588913,
       0.12232269, 0.28685119, 0.12430167, 0.4706228 , 0.23271962,
       0.44613629, 0.17153735, 0.22508658, 0.22895259, 0.44013076,
       0.47934771, 0.45711032, 0.35824061, 0.32580349, 0.1110811 ,
       0.3501096 , 0.12112748, 0.3569547 , 0.45351932, 0.40570047,
       0.24602361, 0.1394526 , 0.25581106, 0.38823148, 0.13526048,
       0.42757002, 0.25542069, 0.14263317, 0.20137567, 0.46083459])

我們將每個弱學習器的權重和錯誤率使用 Matplotlib 畫出折線圖如下:

在這裡插入圖片描述

可以看到弱學習器的錯誤率與權重成反比

  • 弱學習器的錯誤率越低,權重越高。
  • 弱學習器的錯誤率越高,權重越低。

8,對比 AdaBoost 模型與決策樹,KNN 演算法

下面分別使用決策樹迴歸KNN 迴歸來分析波士頓資料集,從而對比這三種演算法的準確度。

使用決策樹迴歸

程式碼如下

from sklearn.tree import DecisionTreeRegressor

# 構建決策樹
dec_regressor = DecisionTreeRegressor()

# 擬合決策樹
dec_regressor.fit(train_x, train_y)

# 預測資料
pred_y = dec_regressor.predict(test_x)

# 計算模型準確度
mse = mean_squared_error(test_y, pred_y)
print "決策樹均方誤差 = ", round(mse, 2)

使用KNN 迴歸

程式碼如下

from sklearn.neighbors import KNeighborsRegressor

# 構建 KNN 模型
knn_regressor = KNeighborsRegressor()

# 擬合模型
knn_regressor.fit(train_x, train_y)

# 預測資料
pred_y = knn_regressor.predict(test_x)

# 計算模型準確度
mse = mean_squared_error(test_y, pred_y)
print "KNN 均方誤差 = ", round(mse, 2)

執行程式碼得出的結果是:

  • AdaBoost 均方誤差 = 18.57
  • 決策樹均方誤差 = 36.92
  • KNN 均方誤差 = 27.87

我們知道均方誤差越小,準確率越高,所以 AdaBoost 演算法在這三種演算法中表現最好。

9,探究迭代次數與錯誤率的關係

理想情況下,迭代次數越多,最終模型的錯誤率應該越低,下面我們來探究一下是否是這樣?

sklearn 中的 make_hastie_10_2 函式用於生成二分類資料

我們用該函式生成12000 個資料,取前2000 個作為測試集,其餘為訓練集:

from sklearn import datasets

X, Y = datasets.make_hastie_10_2(n_samples=12000, random_state=1)
train_x, train_y = X[2000:], Y[2000:]
test_x, test_y = X[:2000], Y[:2000]

構建 AdaBoost 分類模型,迭代次數為 500

from sklearn.ensemble import AdaBoostClassifier

IterationN = 500 
ada = AdaBoostClassifier(n_estimators=IterationN)
ada.fit(train_x, train_y)

對測試資料進行預測,並統計錯誤率:

from sklearn.metrics import zero_one_loss

errs = []
for pred_y in ada.staged_predict(test_x):
    err = zero_one_loss(pred_y, test_y)
    errs.append(err)

staged_predict 方法用於預測每一輪迭代後輸入樣本的預測值,所以模型迭代了多少次,該方法就會返回多少次預測結果,其返回的就是分別迭代1,2,3...N 次的預測結果。

zero_one_loss 方法用於計算錯誤率。

errs 列表中儲存了每次迭代的錯誤率。

Matplotlib 畫出錯誤率折線圖:

import matplotlib.pyplot as plt

plt.plot(range(1, IterationN+1), errs, label='AdaBoost Error Rate', color='orange')
plt.legend(loc='upper right', fancybox=True) # 顯示圖例
plt.show()

在這裡插入圖片描述

通過上圖可以看出:

  • 隨著迭代次數的增多,錯誤率逐漸降低。
  • 在迭代100 次之後,錯誤率趨於平緩。

建議:
在實際應用中,可以通過畫這種折線圖的方式,來判斷模型應該迭代多少次。當然也要考慮時間成本,迭代次數越多,時間成本也會越高。

sklearn 官方文件中也有一個這樣的例子,你可以參考這裡

需要注意的是,如果資料集不夠好的話,錯誤率在達到一定值後有可能會反彈,即迭代次數如果再增加,錯誤率可能會增高,這時候就是過擬合現象。

10,總結

本篇文章主要介紹了以下內容:

  • 什麼是整合演算法及常見的整合演算法有哪些?
  • bagging 演算法與boosting 演算法的區別。
  • AdaBoost 演算法原理及其計算過程。
  • 使用AdaBoost 演算法分析波士頓房價資料集。
  • 對比AdaBoost 演算法,決策樹演算法及KNN 演算法哪個更強大。
  • 探究AdaBoost 演算法迭代次數與錯誤率的關係。

(本節完。)


推薦閱讀:

如何使用Python 進行資料視覺化

如何用Python 製作詞雲-對1000首古詩做詞雲分析

決策樹演算法-實戰篇-鳶尾花及波士頓房價預測

Apriori 演算法-如何進行關聯規則挖掘

EM 演算法-對鳶尾花資料進行聚類


歡迎關注作者公眾號,獲取更多技術乾貨。

碼農充電站pro

相關文章