Bagging 與Pasting
我們之前提到過,其中一個獲取一組不同分類器的方法是使用完全不同的訓練算法。另一個方法是為每個預測器使用同樣的訓練算法,但是在訓練集的不同的隨機子集上進行訓練。在數據抽樣時,如果是從數據中重復抽樣(有放回),這種方法就叫bagging(bootstrap aggregating 的簡稱,引導聚合)。當抽樣是數據不放回采樣時,這個稱為pasting。
換句話說,bagging與pasting都允許訓練數據條目被多個預測器多次采樣,但是僅有bagging允許訓練數據條目被同一個預測器多次采樣。在pasting中,每個預測器僅能對同一條訓練數據條目采樣一次。Bagging的采樣與訓練的過程如下圖所示:

在所有預測器都訓練好后,集成器可以對一條新數據做預測,它會簡單地聚集所有預測器的預測值。這個聚集方法通常在分類問題中是一個統計模型(也就是說,使用出現最頻繁的預測,與投票分類器中的硬投票類似),而在回歸問題中是一個平均值。每個單獨預測器的bias(偏差值)相對於他們在原始訓練集上訓練的bias會更高,不過集成會同時減少bias與variance(方差)。一般來說,集成的結果與單個模型,兩者的bias值較為接近,但是集成的variance會更低。
在上圖中我們也可以看到,模型可以並行進行訓練,使用不同的CPU核或是不同的服務器。類似的,預測也可以並行完成。這也是為什么當今bagging與pasting如此令人受歡迎的原因之一:它們的擴展性非常好。
Sk-learn中的Bagging與Pasting
Sk-learn提供了一個簡單的API用於bagging與pasting,BaggingClassifier類(或BaggingRegressor類做回歸任務)。下面的代碼訓練一個由500棵決策樹組成的集成:每個均在100條隨機采樣的訓練數據條目上進行訓練,且數據采樣有放回(也就是bagging的例子,如果要用pasting,指定bootstrap=False即可)。n_jobs 參數指定sk-learn在訓練與預測時使用的CPU核數(-1表示使用所有可用資源):
from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier bag_clf = BaggingClassifier( DecisionTreeClassifier(), n_estimators=500, max_samples=100, bootstrap=True, n_jobs=-1) bag_clf.fit(X_train, y_train) y_pred = bag_clf.predict(X_test)
在BaggingClassifier中,如果基於的基本分類器是可以估計類別概率的話(例如它包含predict_proba() 方法),則BaggingClassifier 會自動執行軟投票(soft voting),而不是硬投票。在上面的例子中,基本分類器是決策樹,所以它執行的是軟投票。
下圖對比了單個決策樹的決策邊界與bagging集成500棵樹(上面的代碼)的決策邊界,兩者均在moon數據集上進行訓練。我們可以看到,集成預測的泛化性能會更好:集成與單個決策樹的bias差不多,但是集成的variance更小。

Bootstraping在每個模型使用的訓練子集中引入了更多的多樣性,所以bagging最終的bias會稍高於pasting一些;但是額外的多樣性也意味着最終模型之間的相關性會更小,所以集成的variance會減少。總之,bagging一般相對於pasting會產生更好的模型,這也是為什么我們一般傾向於使用bagging。不夠如果有足夠的時間和CPU的話,我們可以使用交叉驗證來評估bagging與pasting的性能,並選擇其中表現最好的那個。
Out-of-Bag評估
使用bagging時,有些數據條目可能會被任一模型采樣多次,而其他數據條目可能從來都不會被采樣。默認情況下,BaggingClassifier會以有放回(bootstrap=True)的方式采樣m條訓練數據,這里m為訓練集的大小。也就是說,對每個模型來說,平均大約僅有63%的訓練數據條目會被采樣到。剩下大約37% 的(沒有被采樣的)訓練數據條目稱為out-of-bag(oob)實例。
由於模型在訓練中並不會看到oob實例,所以可以使用這些實例對模型進行評估,而不需要使用額外的驗證集。我們可以通過取每個模型的oob評估的平均,作為集成的評估。
在sk-learn 中,我們在創建BagginClassifier時可以設置 oob_score=True,這樣可以在訓練結束后
啟用一個自動的oob評估。下面的代碼是展示的這個例子,評估結果分數可以通過oob_score_變量獲取:
bag_clf = BaggingClassifier( DecisionTreeClassifier(), n_estimators=500, bootstrap=True, n_jobs=-1, oob_score=True ) bag_clf.fit(X_train, y_train) bag_clf.oob_score_ >0.8986666666666666
根據oob的評估結果,這個BaggingClassfier可能會在測試集上達到89.8%的准確率,下面我們驗證一下:
from sklearn.metrics import accuracy_score y_pred = bag_clf.predict(X_test) accuracy_score(y_test, y_pred) >0.904
在測試集上的准確度為90.4%,結果比較接近。
對每條訓練集的oob決策函數也可以通過oob_decision_funcsion_ 變量獲取。在上面的這個例子中(由於base estimator 有 predict_proba() 方法),決策函數會對每條訓練數據返回它屬於某個類別的概率。例如,oob 評估第一條訓練數據有58.6%的概率屬於正類,41.4%的概率屬於負類。
bag_clf.oob_decision_function_ >array([[0.41361257, 0.58638743], [0.37016575, 0.62983425], [1. , 0. ], [0. , 1. ], …
