1. 程式人生 > 其它 >機器學習——整合學習(Bagging、Boosting、Stacking)

機器學習——整合學習(Bagging、Boosting、Stacking)

1 前言

  • 整合學習的思想是將若干個學習器(分類器&迴歸器)組合之後產生一個新學習器。弱分類器(weak learner)指那些分類準確率只稍微好於隨機猜測的分類器(errorrate < 0.5)。
  • 整合演算法的成功在於保證弱分類器的多樣性(Diversity)。而且整合不穩定的演算法也能夠得到一個比較明顯的效能提升。
  • 整合學習可以用於分類問題整合,迴歸問題整合,特徵選取整合,異常點檢測整合等等,可以說所有的機器學習領域都可以看到整合學習的身影。

2 整合學習概述

  • 常見的整合學習思想有∶
    • Bagging
    • Boosting
    • Stacking
  • 為什麼需要整合學習?
  1. 弱分類器間存在一定的差異性 ,這會導致分類的邊界不同,也就是說可能存在錯誤。那麼將多個弱分類器合併後,就可以得到更加合理的邊界,減少整體的錯誤率,實現更好的效果;
  2. 對於資料集過大或者過小,可以分別進行劃分和有放回的操作產生不同的資料子集,然後使用資料子集訓練不同的分類器,最終再合併成為一個大的分類器;
  3. 如果資料的劃分邊界過於複雜,使用線性模型很難描述情況,那麼可以訓練多個模型,然後再進行模型的融合;
  4. 對於多個異構的特徵集的時候,很難進行融合,那麼可以考慮每個資料集構建一個分模型,然後將多個模型融合。

  

3Bagging模型

  Bagging 方法又叫做自舉匯聚法(Bootstrap Aggregating),是一種並行的演算法。
  基本思想︰在原始資料集上通過有放回的抽樣的方式,重新選擇出 $T$ 個新資料集來分別訓練 $T$ 個分類器的整合技術。也就是說這些模型的訓練資料中允許存在重複資料。


  Bagging 的特點在“隨機取樣”。隨機取樣(Bootsrap)就是從訓練集裡面採集固定個數的樣本,但是每採集一個樣本後,都將樣本放回。也就是說,之前採集到的樣本在放回後有可能繼續被採集到。
  Bagging的結合策略:對於分類問題,通常使用簡單投票法,得到最多票數的類別或者類別之一為最終的模型輸出。對於迴歸問題,通常使用簡單平均法,對 $T$ 個弱學習器得到的迴歸結果進行算術平均得到最終的模型輸出。
  由於 Bagging 演算法每次都進行取樣來訓練模型,因此泛化能力很強,對於降低模型的方差很有作用。當然對於訓練集的擬合程度就會差一些,也就是模型的偏倚會大一些。
  Bagging 方法的弱學習器可以是基本的演算法模型,eg: Linear、Ridge、Lasso、Logistic、Softmax、ID3、C4.5、CART、SVM、KNN等。

  

  Bagging對樣本重取樣,對每一輪的取樣資料集都訓練一個模型,最後取平均。由於樣本集的相似性和使用的同種模型,因此各個模型的具有相似的 bias 和variance 。
    $E({\large \frac{\sum_\limits {i=1}^{n}X_i}{n} } )=E(X_i)$
  模型完全獨立:
    $Var({\large \frac{\sum_\limits {i=1}^{n}X_i}{n} } )={\large \frac{Var(X_i)}{n} } $
  模型完全相同:
    $Var({\large \frac{\sum_\limits {i=1}^{n}X_i}{n} } )=\large{Var(X_i)}$
  隨機森林是 Bagging 的一個特化進階版,所謂的特化是因為隨機森林的弱學習器都是決策樹。所謂的進階是隨機森林在 Bagging 的樣本隨機取樣基礎上,又加上了特徵的隨機選擇,其基本思想沒有脫離 Bagging的範疇。Bagging 和隨機森林演算法的原理在後面的文章中會專門來講。

4 隨機森林(Random Forest)

  在Bagging策略的基礎上進行修改後的一種演算法

  1. 從樣本集中用Bootstrap取樣選出 $n$ 個樣本;
  2. 從所有屬性中隨機選擇 $K$ 個屬性,選擇出最佳分割屬性作為節點建立決策樹;
  3. 重複以上兩步 $m$ 次,即建立 $m$ 棵決策樹;
  4. 這 $m$ 個決策樹形成隨機森林,通過投票表決結果決定資料屬於那一類。

  雖然抽樣資料在一定程度上體現了全體樣本資料的特性,所以可以用樣本資料訓練模型來預測其他的全體資料。但是資料與資料之間是存在差異性的,那麼可以認為在擬合當前資料集的模型有可能出現不擬合生產環境中資料的情況,這就是過擬合。在決策樹中,進行特徵屬性劃分選擇的時候,如果選擇最優,表示這個劃分在當前資料集上一定是最優的,但是不一定在全體資料中最優;在隨機森林中,如果每個決策樹都是選擇最優的進行劃分,就會導致所有子模型(內部的決策樹)很大概率上會使用相同的特徵屬性進行資料的劃分,不就會特別容易導致過擬合嘛,所以在隨機森林中選擇特徵屬性劃分的時候一般使用隨機的方式。

5Boosting模型

  在正式介紹Boosting思想之前,先介紹兩個例子:
  第一個例子:不知道大家有沒有做過錯題本,我們將每次測驗的錯的題目記錄在錯題本上,不停的翻閱,直到我們完全掌握。
  第二個例子:對於一個複雜任務來說,將多個專家的判斷進行適當的綜合所作出的判斷,要比其中任何一個專家單獨判斷要好。實際上這是一種“三個臭皮匠頂個諸葛亮的道理"。
  這兩個例子都說明Boosting的道理,也就是不錯地重複學習達到最終的要求。

  Boosting(提升學習)演算法指將弱學習演算法組合成強學習演算法,它的思想起源於Valiant提出的PAC(Probably Approximately Correct)學習模型。可以用於迴歸分類的問題。

  Boosting: 是一種序列的演算法,通過弱學習器開始加強,它每一步產生弱預測模型(如決策樹),並加權累加到總模型中;如果每一步的弱預測模型的生成都是依據損失函式的梯度方式的,那麼就稱為梯度提升(Gradientboosting)。
  基本思想:不同的訓練集是通過調整每個樣本對應的權重實現的,不同的權重對應不同的樣本分佈,而這個權重為分類器不斷增加對錯分樣本的重視程度。
  Boosting的意義∶如果一個問題存在弱預測模型,那麼可以通過提升技術的辦法得到一個強預測模型;
  常見的模型有:

    • Adaboost
    • Gradient Boosting(GBT/GBDT/GBRT)

  基本步驟:

  1. 首先賦予每個訓練樣本相同的初始化權重,在此訓練樣本分佈下訓練出一個弱分類器;
  2. 利用該弱分類器更新每個樣本的權重,分類錯誤的樣本認為是分類困難樣本,權重增加,反之權重降低,得到一個新的樣本分佈;
  3. 在新的樣本分佈下,在訓練一個新的弱分類器,並且更新樣本權重,重複以上過程T次,得到T個弱分類器。

  

  通過改變樣本分佈,使得分類器聚集在那些很難分的樣本上,對那些容易錯分的資料加強學習,增加錯分資料的權重。這樣錯分的資料再下一輪的迭代就有更大的作用(對錯分資料進行懲罰)。對於這些權重,一方面可以使用它們作為抽樣分佈,進行對資料的抽樣;另一方面,可以使用權值學習有利於高權重樣本的分類器,把一個弱分類器提升為一個強分類器。

  

  

  Boosting演算法通過權重投票的方式將T個弱分類器組合成一個強分類器。只要弱分類器的分類精度高於50%,將其組合到強分類器裡,會逐漸降低強分類器的分類誤差。
  由於Boosting將注意力集中在難分的樣本上,使得它對訓練樣本的噪聲非常敏感,主要任務集中在噪聲樣本上,從而影響最終的分類效能。
  對於Boosting來說,有兩個問題需要回答:一是在每一輪如何如何改變訓練資料的概率分佈;二是如何將多個弱分類器組合成一個強分類器。而且存在一個重大的缺陷:該分類演算法要求預先知道弱分類器識別準確率的下限。
  Boosting系列演算法裡最著名演算法主要有AdaBoost演算法和提升樹(boosting tree)系列演算法。提升樹系列演算法裡面應用最廣泛的是梯度提升樹(Gradient Boosting Tree)。AdaBoost和提升樹演算法的原理在後面的文章中會專門來講。

6 Bagging和Boosting的區別

  1 樣本選擇︰Bagging演算法是有放回的隨機取樣;Boosting演算法是每一輪訓練集不變,只是訓練集中的每個樣例在分類器中的權重發生變化,而權重根據上一輪的分類結果進行調整;
  2 樣例權重︰Bagging使用隨機抽樣,樣例的權重;Boosting根據錯誤率不斷的調整樣例的權重值,錯誤率越大則權重越大;
  3 預測函式︰Bagging所有預測模型的權重相等;Boosting演算法對於誤差小的分類器具有更大的權重;
  4 平行計算︰Bagging演算法可以並行生成各個基模型;Boosting理論上只能順序生產,因為後一個模型需要前一個模型的結果;
  5 Bagging是減少模型的variance(方差);Boosting是減少模型的Bias(偏度);
  6 Bagging裡每個分類模型都是強分類器,因為降低的是方差,方差過高需要降低是過擬合;Boosting裡每個分類模型都是弱分類器,因為降低的是偏度,偏度過高是欠擬合。

7 Stacking模型

7.1 模型解釋

  Stacking是指訓練一個模型用於組合(combine)其它模型(基模型/基學習器)的技術。即首先訓練出多個不同的模型,然後再以之前訓練的各個模型的輸出作為輸入來新訓練一個新的模型,從而得到一個最終的模型。一般情況下使用單層的Logistic迴歸作為組合模型。
  Stacking的過程圖,如下:

  

  第一層
  1、首先得到兩組資料:訓練集 train 和測試集 test。將訓練集 train 分成5份:train1,train2,train3,train4,train5。
  2、選定基模型。這裡假定選擇了 Model1 作為基模型。
  在 Model1 模型部分:依次用 train1,train2,train3,train4,train5 作為驗證集,其餘4份作為訓練集,進行5折交叉驗證進行模型訓練;
  假定 tain 有890行資料,test 有 418 行資料。每個小 train(即train1,train2...)則有 890/5=178行資料。
  對於每一輪的 5-fold,Model1 都要做滿 5 次的訓練和預測。用 Model1來訓練 713 (=178*4) 行的小 train,然後預測 178 行 小test(Predict部分),預測的結果是長度為 178 的預測值。
  執行5次,使用每次長度為 178 的預測值組合形成長度為 178 X 5 = 890 預測值,剛好和 train 長度吻合。這一步產生的預測值轉成 890 X 1 (890 行,1列)的 New Feature,記作 A1。
  3、再在測試集 test 上進行預測。
  每一次的 fold,713 行的 小train 組合訓練出來的 區域性最優 Model1 要去預測全部的 test (418行資料)(因為 test 沒有加入 5-fold,所以每次都是全部)。此時,Model1 的預測結果是長度為 418 的預測值。 執行 5 次,可以得到一個 5 X 418 的預測值。然後根據行來就平均值,最後得到一個 418 X 1 的平均預測值,記作 B1。
  4、走到這裡,第一層的 Model1完成了它的使命。
  第一層還會有其他Model的,比如Model2,同樣的走一遍, 可以得到 890 X 1New Feature (A2) 和 418 X 1 (B1 ) 列預測值。
  這樣吧,假設第一層有3個模型,這樣你就會得到:
  來自 5-fold 的預測值矩陣 890 X 3,(A1,A2,A3) 和 來自 test 預測值矩陣 418 X 3(B1, B2, B3)。
  第二層
  來自5-fold的 預測值矩陣 890 X 3 (A1,A2,A3)作為新的train Data,訓練第二層的模型(Model4)。
  來自 test Data 預測值矩陣 418 X 3 (B1, B2, B3) 就是新的test Data,用訓練好的模型來預測。

7.2 Stacking注意事項

  做Stacking模型融合時需要注意以下個點,我們拿2層stacking模型融合來舉例子:

  1. 第一層的基模型最好是強模型,而第二層的基模型可以放一個簡單的分類器,防止過擬合。
  2. 第一層基模型的個數不能太小,因為一層模型個數等於第二層分類器的特徵維度。大家可以把勉強將其想象成神經網路的第一層神經元的個數,當然這個值也不是越多越好。
  3. 第一層的基模型必須準而不同",如果有一個性能很差的模型出現在第一層,將會嚴重影響整個模型融合的效果(筆者在實驗過程中就遇到這樣的坑)。

  通過上述的描述,大家沒有發現其實2層的stacking 其實和兩層的神經網路有些相像,只不過stacking將神經網路第一層的神經元換成了強大的機器學習模型。

7.3 Stacking實驗

  資料準備

  
from sklearn.datasets import make_classification
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier as GBDT
from sklearn.ensemble import ExtraTreesClassifier as ET
from sklearn.ensemble import RandomForestClassifier as RF
from sklearn.ensemble import AdaBoostClassifier as ADA
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
import numpy as np
x,y = make_classification(n_samples=6000)
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.5)
View Code

  定義第一層模型
  由於Stacking的第一層最後選擇比較強的模型,所以這裡筆者選了四個本身就是整合模型的強模型,GBDT,RandomForest,ExtraTrees,和 Adaboost。

  
### 第一層模型
clfs = [ GBDT(n_estimators=100),
       RF(n_estimators=100),
       ET(n_estimators=100),
       ADA(n_estimators=100)
]
X_train_stack  = np.zeros((X_train.shape[0], len(clfs)))
X_test_stack = np.zeros((X_test.shape[0], len(clfs))) 
View Code

資料輸入第一層模型,輸出即將餵給第二層模型特徵
6折交叉驗證,同時通過第一層的強模型訓練預測生成餵給第二層的特徵資料。

  
### 6折stacking
n_folds = 6
skf = StratifiedKFold(n_splits=n_folds, shuffle=True, random_state=1)
for i,clf in enumerate(clfs):
#     print("分類器:{}".format(clf))
    X_stack_test_n = np.zeros((X_test.shape[0], n_folds))
    for j,(train_index,test_index) in enumerate(skf.split(X_train,y_train)):
                tr_x = X_train[train_index]
                tr_y = y_train[train_index]
                clf.fit(tr_x, tr_y)
                #生成stacking訓練資料集
                X_train_stack [test_index, i] = clf.predict_proba(X_train[test_index])[:,1]
                X_stack_test_n[:,j] = clf.predict_proba(X_test)[:,1]
    #生成stacking測試資料集
    X_test_stack[:,i] = X_stack_test_n.mean(axis=1) 
View Code

  用第一層模型的輸出特徵,訓練第二層模型
  為了防止過擬合,第二層選擇了一個簡單的Logistics迴歸模型。輸出Stacking模型的auc得分。

  
###第二層模型LR
clf_second = LogisticRegression(solver="lbfgs")
clf_second.fit(X_train_stack,y_train)
pred = clf_second.predict_proba(X_test_stack)[:,1]
roc_auc_score(y_test,pred)#0.9946
View Code

  同時筆者對比了第一層四個基模型的得分情況。
  GBDT分類器效能

  
###GBDT分類器
clf_1 = clfs[0]
clf_1.fit(X_train,y_train)
pred_1 = clf_1.predict_proba(X_test)[:,1]
roc_auc_score(y_test,pred_1)#0.9922
View Code

  隨機森林分類器效能

  
###隨機森林分類器
clf_2 = clfs[1]
clf_2.fit(X_train,y_train)
pred_2 = clf_2.predict_proba(X_test)[:,1]
roc_auc_score(y_test,pred_2)#0.9944
ExtraTrees分類器效能
View Code

  ExtraTrees分類器效能

  
###ExtraTrees分類器
clf_3 = clfs[2]
clf_3.fit(X_train,y_train)
pred_3 = clf_3.predict_proba(X_test)[:,1]
roc_auc_score(y_test,pred_3)#0.9930
View Code

  AdaBoost分類器效能

  
###AdaBoost分類器
clf_4 = clfs[3]
clf_4.fit(X_train,y_train)
pred_4 = clf_4.predict_proba(X_test)[:,1]
roc_auc_score(y_test,pred_4)#0.9875
View Code

  

8 整合學習之結合策略

  本節就對整合學習之結合策略做一個總結。假定得到的 $T$ 個弱學習器是$\{h_1,h_2,...h_T\}$。

8.1 平均法

  對於數值類的迴歸預測問題,通常使用的結合策略是平均法,即對於若干個弱學習器的輸出進行平均得到最終的預測輸出。
  最簡單的平均是算術平均,也就是說最終預測是

    $H(x) = \frac{1}{T}\sum\limits_{1}^{T}h_i(x)$

  如果每個弱學習器有一個權重$w$,則最終預測是

    $H(x) = \sum\limits_{i=1}^{T}w_ih_i(x)$

  其中 $w_i$ 是個體學習器 $h_i$ 的權重,通常有

    $w_i \geq 0 ,\;\;\; \sum\limits_{i=1}^{T}w_i = 1$

8.2 投票法

  對於分類問題的預測,通常使用的是投票法。假設預測類別是 $\{c_1,c_2,...c_K\}$ ,對於任意一個預測樣本 $x$, $T$ 個弱學習器的預測結果分別是 $(h_1(x), h_2(x)...h_T(x))$。
  稍微複雜的投票法是絕對多數投票法,也就是常說的要票過半數。在相對多數投票法的基礎上,不光要求獲得最高票,還要求票過半數。否則會拒絕預測。
  更加複雜的是加權投票法,和加權平均法一樣,每個弱學習器的分類票數要乘以一個權重,最終將各個類別的加權票數求和,最大的值對應的類別為最終類別。

8.3 學習法

  投票法和平均法相對比較簡單,但是可能學習誤差較大,於是就有了學習法。對於學習法,代表方法是 Stacking,當使用 Stacking 的結合策略時, 不是對弱學習器的結果做簡單的邏輯處理,而是再加上一層學習器,也就是說,將訓練集弱學習器的學習結果作為輸入,將訓練集的輸出作為輸出,重新訓練一個學習器來得到最終結果。
  在這種情況下,將弱學習器稱為初級學習器,將用於結合的學習器稱為次級學習器。對於測試集,首先用初級學習器預測一次,得到次級學習器的輸入樣本,再用次級學習器預測一次,得到最終的預測結果。