监督学习 | 集成学习 之Bagging、随机森林及Sklearn实现
文章目錄
- 集成學習
- 1. 投票分類器
- 1.1 硬投票法
- 1.2 軟投票法
- 2. Bagging & Pasting
- 2.1 包外評估
- 2.2 Random Patches 和 隨機子空間
- 3. 隨機森林
- 3.1 極端隨機樹
- 3.2 特征重要性
- 參考資料
相關文章:
機器學習 | 目錄
監督學習 | 決策樹原理及Python實現
監督學習 | 決策樹之Sklearn實現
監督學習 | 集成學習之AdaBoost原理及Slearn實現
集成學習
集成學習(ensemble learning)通過構建并結合多個學習器來完成學習任務,有時也被稱為多分類器系統(multi-classifier system)、基于委員會的學習(committee-based learning)等。
下圖顯示出集成學習的一般結構:先產生一組“個體學習器”(individual learner),再用某種策略將它們結合起來,此時集成中只包括同種類型的個體學習器,例如“決策樹集成”中全是決策樹,“神經網絡集成”中全是神經網絡,這樣的集成是“同質的”(homogeneous)。同質集合中的個體學習器亦稱“基學習器”(base learner),相應的學習算法稱為“基學習算法”(base learning algorithm)。
集成也可以包含不同類型的個體學習器,例如同時包含決策樹和神經網絡,這樣的集成是“異質”的(heterogenous)。異質集成中的個體學習器由不同的學習算法生成,這時不再有基學習算法;相應的,個體學習器一般不稱為基學習器,常稱為“組件學習器”(component learner)或直接稱個體學習器。
圖1 集成學習示意圖集成學習通過將多個學習器進行結合,常可獲得比單一學習器顯著優越的泛化性能。這對“弱學習器”(weak learner)尤為明顯,因此集成學習都是針對弱學習器進行的,而基學習器有時也被直接稱為弱學習器。但需要注意的是,雖然從理論上來說使用弱學習器集成足以獲得更好的性能,但在實踐中處于種種考慮,例如希望使用較少的個體學習器,或是重用關于常見學習器的一些經驗等,人們往往還會使用比較強的學習器。
弱學習器:常指泛化能力略優于隨機猜測的學習器;例如在二分類問題上精度率高于 50% 的分類器。
根據個體學習器的生成方式,目前的集成學習方法大致可分為兩大類,即個體學習器間存在強依賴關系、必須串行生成的序列化方法(Boosting,降低偏差),以及個體學習器間不存在強依賴關系、可同時生成的并行化方法(Bagging、隨機森林,降低方差)。[1]
表1 集成算法分類| 基學習器(同質) | Bagging、隨機森林 | Bagging、隨機森林 | AdaBooting |
| 組件學習器(異質) | \ | 投票分類器 | \ |
1. 投票分類器
1.1 硬投票法
假設你已經訓練好了一些分類器,每個分類器的準確率約為 80% 。大概包括:一個邏輯回歸分類器、一個 SVM 分類器、一個隨機森林分類器、一個 K-近鄰分類器,如下圖所示:
圖2 訓練多重分類器這時,要創建出一個更好的分類器,最簡單的辦法就是聚合每個分類器的預測,然后將得到票最多的結果最為預測類別。這種大多數投票分類器被稱為硬投票分類器。
圖3 硬投票分類器預測當預測器盡可能互相獨立時,集成方法的效果最優。獲得多種分類器的方法之一就是使用不同的算法進行訓練。這會增加它們犯不同類型錯誤的機會,從而提升集成的準確率。
Sklearn 實現:
Sklearn中的 VotingClassifier 類可以實現投票分類器。
from sklearn.ensemble import VotingClassifierVotingClassifier(estimators, voting='hard', weights=None, n_jobs=None, flatten_transform=True)參數設置:
estimator: slist of (string, estimator) tuples
Invoking the fit method on the VotingClassifier will fit clones of those original estimators that will be stored in the class attribute self.estimators_. An estimator can be set to None or 'drop' using set_params.voting: str, {‘hard’, ‘soft’} (default=’hard’)
If ‘hard’, uses predicted class labels for majority rule voting. Else if ‘soft’, predicts the class label based on the argmax of the sums of the predicted probabilities, which is recommended for an ensemble of well-calibrated classifiers.weights: array-like, shape (n_classifiers,), optional (default=None)
Sequence of weights (float or int) to weight the occurrences of predicted class labels (hard voting) or class probabilities before averaging (soft voting). Uses uniform weights if None.n_jobs: int or None, optional (default=None)
The number of jobs to run in parallel for fit. None means 1 unless in a joblib.parallel_backend context. -1 means using all processors. See Glossary for more details.【并行 CPU 數量,-1 為使用所有可用 CPU】flatten_transform: bool, optional (default=True)
Affects shape of transform output only when voting=’soft’ If voting=’soft’ and flatten_transform=True, transform method returns matrix with shape (n_samples, n_classifiers * n_classes). If flatten_transform=False, it returns (n_classifiers, n_samples, n_classes). # 1. 導入數據: import numpy as np from sklearn.model_selection import train_test_split from sklearn.datasets import make_moonsX, y = make_moons(n_samples=500, noise=0.30, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)# 2. 訓練個體預測器: from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVClog_clf = LogisticRegression(solver="liblinear", random_state=42) rnd_clf = RandomForestClassifier(n_estimators=10, random_state=42) svm_clf = SVC(gamma="auto", random_state=42)# 3. 導入硬投票分類器并擬合: from sklearn.ensemble import VotingClassifiervoting_clf = VotingClassifier(estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],voting='hard') voting_clf.fit(X_train, y_train)# 4. 看看每個分類器在測試集上的準確率,可以看到投票分類器略勝于所有個體分類器。 from sklearn.metrics import accuracy_scorefor clf in (log_clf, rnd_clf, svm_clf, voting_clf):clf.fit(X_train, y_train)y_pred = clf.predict(X_test)print(clf.__class__.__name__, accuracy_score(y_test, y_pred)) LogisticRegression 0.864 RandomForestClassifier 0.872 SVC 0.888 VotingClassifier 0.8961.2 軟投票法
如果所有分類器都能夠估算出類別的概率(即有 predict_proba() 方法),那么可以將概率在所有單個分類器傻姑娘平均,然后將平均概率最高的類別作為預測,這被稱為軟投票法。通常來說,它比硬投票法的表現更優,因為它給予那些高度自信的投票更高的權重。
Sklearn 實現:
from sklearn.ensemble import VotingClassifiervoting_clf = VotingClassifier(estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],voting='soft') voting_clf.fit(X_train, y_train)注意!需要確保所有分類器都可以估算出概率。默認情況下,SVC 類是不行的,所以需要將其超參數 probability 設為 True(這會導致 SVC 使用交叉驗證來估算類別概率,減慢訓練速度)。
# 1. 導入數據 import numpy as np from sklearn.model_selection import train_test_split from sklearn.datasets import make_moonsX, y = make_moons(n_samples=500, noise=0.30, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)# 2. 訓練個體分類器: from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVClog_clf = LogisticRegression(solver="liblinear", random_state=42) rnd_clf = RandomForestClassifier(n_estimators=10, random_state=42) svm_clf = SVC(gamma="auto", probability=True, random_state=42)# 3. 導入軟投票分類器并擬合: voting_clf = VotingClassifier(estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],voting='soft') voting_clf.fit(X_train, y_train)from sklearn.metrics import accuracy_scorefor clf in (log_clf, rnd_clf, svm_clf, voting_clf):clf.fit(X_train, y_train)y_pred = clf.predict(X_test)print(clf.__class__.__name__, accuracy_score(y_test, y_pred)) LogisticRegression 0.864 RandomForestClassifier 0.872 SVC 0.888 VotingClassifier 0.912可以看見,軟投票器的準確率從硬投票器的 89.6% 提升到了 91.2%。
2. Bagging & Pasting
旗面提到,獲得不同種類分類器的方法之一是使用不同的訓練算法。還有另一種方法是每個個體學習器使用的算法相同(基學習器),但是在不同的訓練集隨機子集上進行訓練。
-
采樣時如果將樣本放回,這種方法叫作 bagging(bootstrap aggregating,自舉匯聚法)。
-
采樣時如果樣本不放回,這種方法叫作 pasting。
換句話說,bagging 和 pasting 都允許訓練實例在多個基學習器中被采樣,但是只有 bagging 允許訓練實例被同一個基學習器多次采樣。
采樣過程和訓練過程如下圖所示:
圖4 pasting/bagging 訓練集采集和訓練一旦預測器訓練完成,集成就可以通過簡單地聚合所有預測器的預測,來對新實例做出預測。聚合函數通常是統計法(即硬投票法)用于分類,或是平均法用于回歸;在 Sklearn 中,如果基學習器能夠估算類別概率(SVM 需添加超參數 probability=True),則將使用軟投票法。
每個基學習器單獨的偏差都高于原始訓練集上訓練的偏差,但是通過聚合,同時降低了偏差和方法。總的來說,最終結果是,于直接在原始訓練集上訓練的單個基學習器相比,集成的偏差相近,但是方差更低。
如圖 4 所示,可以通過不同的 CPU 內核甚至是不同的服務器,并行地訓練集基學習器。類似地,預測也可以并行。這正是 bagging 和 pasting 方法流行的原因之一,它們非常易于拓展。
Slearn實現:
Sklearn 提供了一個簡單的 API,可用 BaggingClassifier 類進行 bagging 和 pasting (或 BaggingRegressor 用于回歸)。
from sklearn.ensemble import BaggingClassifierBaggingClassifier(base_estimator=None, n_estimators=10, max_samples=1.0, max_features=1.0, bootstrap=True, bootstrap_features=False, oob_score=False, warm_start=False, n_jobs=None, random_state=None, verbose=0)[source]?參數設置:
base_estimator: 基學習器
n_estimators: 基學習器數量
max_samples: 0.0~1.0,每個基學習器的訓練樣本量 【對樣本進行抽樣】
bootstrap: True,默認 bagging,想要使用 pasting 可以設置為 False 【抽樣樣本是否放回】
max_features:int or float, optional (default=1.0) 【對特征進行抽樣】(2.2)
bootstrap_features:False,默認 bagging,想要使用 pasting 可以設置為 False 【抽樣特征是否放回】(2.2)
n_jobs: CPU 核數,-1 為使用所有內核
oob_score: False,包外評估(2.1)
如果基學習器能夠估算類別概率(SVM 需添加超參數 probability=True),則將使用軟投票法。
下面使用決策樹作為基學習器,進行 Bagging 集成學習:
# 導入數據 import numpy as np from sklearn.model_selection import train_test_split from sklearn.datasets import make_moonsX, y = make_moons(n_samples=500, noise=0.30, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)# 以 500 個決策樹作為基學習器,創建并擬合 Bagging 集成學習器 from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifierbag_clf = BaggingClassifier(DecisionTreeClassifier(random_state=42), n_estimators=500,max_samples=100,bootstrap=True, n_jobs=-1, random_state=42) bag_clf.fit(X_train, y_train) y_pred = bag_clf.predict(X_test)from sklearn.metrics import accuracy_score print(accuracy_score(y_test, y_pred)) 0.904可以看到,使用決策樹作為基學習器的 Bagging 集成算法(隨機森林)的準確率與投票分類器相仿,我們來比較一下同單一的決策樹相比,集成算法的準確率和邊界:
tree_clf = DecisionTreeClassifier(random_state=42) tree_clf.fit(X_train, y_train) y_pred_tree = tree_clf.predict(X_test) print(accuracy_score(y_test, y_pred_tree)) 0.856 from matplotlib.colors import ListedColormapdef plot_decision_boundary(clf, X, y, axes=[-1.5, 2.5, -1, 1.5], alpha=0.5, contour=True):x1s = np.linspace(axes[0], axes[1], 100)x2s = np.linspace(axes[2], axes[3], 100)x1, x2 = np.meshgrid(x1s, x2s)X_new = np.c_[x1.ravel(), x2.ravel()]y_pred = clf.predict(X_new).reshape(x1.shape)custom_cmap = ListedColormap(['#fafab0','#9898ff','#a0faa0'])plt.contourf(x1, x2, y_pred, alpha=0.3, cmap=custom_cmap)if contour:custom_cmap2 = ListedColormap(['#7d7d58','#4c4c7f','#507d50'])plt.contour(x1, x2, y_pred, cmap=custom_cmap2, alpha=0.8)plt.plot(X[:, 0][y==0], X[:, 1][y==0], "yo", alpha=alpha)plt.plot(X[:, 0][y==1], X[:, 1][y==1], "bs", alpha=alpha)plt.axis(axes)plt.xlabel(r"$x_1$", fontsize=18)plt.ylabel(r"$x_2$", fontsize=18, rotation=0) import matplotlib.pyplot as plt plt.figure(figsize=(11,4)) plt.subplot(121) plot_decision_boundary(tree_clf, X, y) plt.title("Decision Tree", fontsize=14) plt.subplot(122) plot_decision_boundary(bag_clf, X, y) plt.title("Decision Trees with Bagging", fontsize=14) plt.show() 圖5 單個決策樹與 500 個決策樹的 bagging 集成對比圖 5 比較了兩種決策邊界,一個是單個的決策樹,一個是由 500 個決策樹組成的 bagging 集成,均在衛星數據集上訓練完成。可以看出,集成預測的泛化效果很可能比單獨的決策樹要好一些;二者偏差相近,但是集成的方差更小(兩邊訓練集上的錯誤數量差不多,但是集成的決策邊界更規則)。
2.1 包外評估
對于任意給定的基學習器,使用 bagging,有些實例可能會被采樣多次,而有些實例則可能根本不被采用。BaggingClassifier 默認采樣 m 個訓練實例,然后放回樣本(bootstrap=True),m 是訓練集的大小。這意味著對每個預測器來說,平均只對 63% 的訓練實例進行采樣。剩余 37% 未被采樣的訓練實例稱為包外(oob)實例。注意,對于所有基學習器來說,這是不一樣的 37%。
隨著 m 增長,這個比率接近 1?exp(?1)≈63.2121-exp(-1) \approx 63.212%1?exp(?1)≈63.212
既然基學習器在訓練的時候從未見過這些包外實例,正好可以用這些實例進行評估,從而不需要單獨的驗證集或是交叉驗證。將每個訓練器在其包外實例上的評估結果進行平均,就可以得到對集成的評估。
Sklearn實現:
在 Sklearn 中,創建 BaggingClassifier 時,設置 oob_score=True,就可以在訓練結束后自動進行包外評估。
# 通過變量 oob_score_ 獲得最終評估分數 bag_clf = BaggingClassifier(DecisionTreeClassifier(random_state=42), n_estimators=500,oob_score=True,bootstrap=True, n_jobs=-1, random_state=42) bag_clf.fit(X_train, y_train) bag_clf.oob_score_ 0.8986666666666666根據包外評估結果,這個 BaggingClassifier 分類器很可能在測試集上達到約 89.87%的準確率,通過下面的驗證,我們得到在測試集上的準確率為 91.2%,與上面結果非常接近。
from sklearn.metrics import accuracy_score y_pred = bag_clf.predict(X_test) print(accuracy_score(y_test, y_pred)) 0.912每個訓練實例的包外決策函數也可以通過變量 oob_decision_function_ 獲得。本例中(基學習器具備 predict_proba() 方法),決策函數返回的是每個實例的類別概率。例如,包外評估估計,第二個訓練實例有 60.6% 的概率屬于正類(以及 39.4% 的概率屬于負類):
bag_clf.oob_decision_function_[:10] array([[0.32352941, 0.67647059],[0.35625 , 0.64375 ],[1. , 0. ],[0. , 1. ],[0. , 1. ],[0.06145251, 0.93854749],[0.35465116, 0.64534884],[0.01142857, 0.98857143],[0.98930481, 0.01069519],[0.97409326, 0.02590674]])2.2 Random Patches 和 隨機子空間
BaggingClassifier 也支持對特稱進行抽樣(之前是對數據進行抽樣),這通過兩個超參數決定:“max_samples”和“bootstrap_features”。它們的工作方式跟 max_samples 和 bootstrap 相同,只是抽樣對象不再是實例,而是特征。因此,每個基學習器將用輸入特征的隨機子集進行訓練。
這對于處理高維輸入(例如圖像)特別有用。對訓練實例和特征都進行抽樣,這被稱為 Random Patches 方法。
而保留所有訓練實例(即 bootstrap=Flase 并且 max_sample=1.0)但是對特征進行抽樣(即 bootstrap_features=True 并且/或 max_features<1.0),這被稱為隨機子空間法。
對特征抽樣給基學習器帶來更大多多樣性,所以以略高一點的偏差換取來更低的方差。
3. 隨機森林
隨機森林是決策樹(無剪枝)的集成,隨機森林里單顆樹的生長過程中,每個節點在分裂時僅考慮一個隨機子集包含的特征。通常用 bagging (有時也可能是 pasting)方法訓練(如2. Bagging & Pasting 一樣)。訓練集大小通過 max_samples 來設置。除了先構建一個 BaggingClassifier 然后將結果傳輸到 DecisionTreeClassifier,還有一種方法就是使用 RandomForestClassifier 類,這種方法更方便,對決策樹更優化(同樣,對于回歸任務也有一個 RadomForestRegressor 類)。
Sklearn 實現:
from sklearn.ensemble import RandomForestClassifierRandomForestClassifier(n_estimators=100, criterion='gini', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None, ccp_alpha=0.0)參數設置:
除了少量例外,RandomForestClassifier 具有 DecisionTreeClassifier 以及 BaggingClassifier 的所有超參數,前者用來控制樹的生長,后者用來控制集成本身。
少量例外:沒有splitter(強制為 random),沒有 presort(強制為 False),沒有 max_samples(強制為1.0),沒有 base_estimator(強制為 DecisionTreeClassifier 與給定超參數)
# BaggingClassifier 實現from sklearn.datasets import make_moonsX, y = make_moons(n_samples=500, noise=0.30, random_state=42) X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)bag_clf = BaggingClassifier(DecisionTreeClassifier(splitter="random", max_leaf_nodes=16, random_state=42),n_estimators=500, max_samples=1.0, bootstrap=True, n_jobs=-1, random_state=42)bag_clf.fit(X_train, y_train) y_pred = bag_clf.predict(X_test) # RandomForestClassifier 實現from sklearn.ensemble import RandomForestClassifierrnd_clf = RandomForestClassifier(n_estimators=500, max_leaf_nodes=16, n_jobs=-1, random_state=42) rnd_clf.fit(X_train, y_train)y_pred_rf = rnd_clf.predict(X_test) # 比較兩種方法的差距np.sum(y_pred == y_pred_rf) / len(y_pred) # almost identical predictions 0.9763.1 極端隨機樹
隨機森林里單顆樹的生長過程中,每個節點在分裂時僅考慮一個隨機子集包含的特征。如果我們對每個特征使用隨機閾值,而不是搜索得出的最佳閾值(如常規決策樹),則可能讓決策樹生長得更加隨機。
這種極端隨機的決策樹組成的森林,被稱為極端隨機樹集成(Extra-Trees)。同樣,它也是以更高的偏差換取了更低的方差極端隨機樹訓練起來比常規隨機森林要快很多,因為在每個節點上找到每個特征的最佳閾值時決策樹生長中最耗時的任務之一。
使用 Sklearn 的 ExtraTreesClassifier 的 API 與 RandomForestClassifier 相同。同理,ExtraTreesRegressor 的 API 與 RandomForestRegressor 的API 也相同。
通常來說,很難預先知道 RandomForestClassifier 與 ExtraTreesClassifier 誰好誰差,唯一的方法就是兩種都嘗試一遍,然后使用交叉驗證(還需要使用網絡搜索調超參數)進行比較。
3.2 特征重要性
最后,如果查看單個決策樹會發現,重要的特征更可能出現在靠近跟節點的位置,而不重要的特征通常出現在葉節點的位置(甚至根本不出現)。因此,通過計算一個特征在森林所有樹上的平均深度,可以估算出一個特征的重要程度。Sklearn 在訓練結束后自動計算每個特征的重要性。通過變量 feature_importances_ 可以訪問到這個計算結果。
下面在鳶尾花數據集上訓練了一個 RandomForestClassifier,并輸出了各個特征的重要性。看起來最重要的特征是花瓣長度(44%)和寬度(42%),而花萼的長度和寬度則相對不那么重要(分別是 11%和 2%)
from sklearn.datasets import load_iris iris=load_iris()from sklearn.ensemble import RandomForestClassifier rnd_clf=RandomForestClassifier(n_estimators=500, n_jobs=-1) rnd_clf.fit(iris['data'], iris['target'])for name, score in zip(iris['feature_names'], rnd_clf.feature_importances_):print(name,score) sepal length (cm) 0.11051994534871025 sepal width (cm) 0.02132805477543799 petal length (cm) 0.41963589720955286 petal width (cm) 0.44851610266629877所以,如果想要快速了解什么是真正的特征,隨機森領是一個非常便利的方法,特別是當你需要執行特征選擇的時候。[3]
參考資料
[1] 周志華. 機器學習[M]. 北京: 清華大學出版社, 2016: 171-172.
[2] Aurelien Geron, 王靜源, 賈瑋, 邊蕤, 邱俊濤. 機器學習實戰:基于 Scikit-Learn 和 TensorFlow[M]. 北京: 機械工業出版社, 2018: 165-168.
[3] Aurelien Geron, 王靜源, 賈瑋, 邊蕤, 邱俊濤. 機器學習實戰:基于 Scikit-Learn 和 TensorFlow[M]. 北京: 機械工業出版社, 2018: 169-174.
總結
以上是生活随笔為你收集整理的监督学习 | 集成学习 之Bagging、随机森林及Sklearn实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 区域提取
- 下一篇: GPB | 陈润生/何顺民团队发布新版S