1、集成學習
集成學習就是合併多個分類器的預測。通常會在一個項目快結束的時候使用集成算法,一旦創建了一些好的分類器,就可使用集成把它們合併成一個更好的分類器。
著名的集成方法:投票分類、bogging、pasting、boosting、stacking、和一些其它算法。node
1.1 投票分類(少數服從多數)
使人驚奇的是這種投票分類器得出的結果常常會比集成中最好的一個分類器結果更好。
事實上,即便每個分類器都是一個弱學習器(意味着它們也就比瞎猜好點),集成後仍然是一個強學習器(高準確率),只要有足夠數量的弱學習者,他們就足夠多樣化。git
若是每個分類器都在同一個數據集上訓練,會致使犯同一種類型的錯誤。相比較而言,每一個分類器在不一樣的數據集上訓練,集成後的結果會更好。
下面使用moons數據集,訓練三個分類器,使用集成算法。github
from sklearn.datasets import make_moons from sklearn.model_selection import train_test_split moons = make_moons(noise=0.3, random_state=0) X, y = moons X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4, random_state=42) # print(X_train[10], y_train[0])
[-0.65805008 -0.12944211] 0
from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import VotingClassifier #軟投票/多數規則分類器 from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC log_clf = LogisticRegression() rnd_clf = RandomForestClassifier() svm_clf = SVC() voting_clf = VotingClassifier(estimators=[("lr", log_clf), ("rf", rnd_clf), ("svc", svm_clf)], voting="hard") #voting:"soft"/"hard" #硬投票,默認"hrad"。"hard",使用預測的類標籤進行多數規則投票。 #軟投票,"soft",基於預測機率之和的argmax來預測類別標籤,這推薦用於通過良好校準的分類器的集合。 # voting_clf.fit(X_train, y_train)
測一下準確率:算法
from sklearn.metrics import accuracy_score #分類準確度得分 for 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.875 RandomForestClassifier 0.925 SVC 0.95 VotingClassifier 0.95
1.2 Bagging和Pasting
對每個分類器都使用相同的訓練算法,可是在不一樣的訓練集上去訓練它們。有放回採樣被稱爲裝袋(Bagging,是 bootstrap aggregating 的縮寫)。無放回採樣稱爲粘貼(pasting)bootstrap
聚合函數一般對分類是統計模式(例如硬投票分類器),對迴歸是平均數組
API:對分類是BaggingClassifier
對於迴歸是`BaggingRegressordom
接下來的代碼訓練了一個 500 個決策樹分類器的集成,每個都是在數據集上有放回採樣 100 個訓練實例下進行訓練(這是 Bagging 的例子,若是你想嘗試 Pasting,就設置bootstrap=False)函數
n_jobs參數告訴 sklearn 用於訓練和預測所須要 CPU 核的數量。(-1 表明着 sklearn 會使用全部空閒核)學習
整體而言,Bagging 一般會致使更好的模型優化
from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier bag_clf = BaggingClassifier(DecisionTreeClassifier(), n_estimators=500, max_samples=50, oob_score=True, bootstrap=True, n_jobs=-1) bag_clf.fit(X_train, y_train)
BaggingClassifier(base_estimator=DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None, 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'), bootstrap=True, bootstrap_features=False, max_features=1.0, max_samples=50, n_estimators=500, n_jobs=-1, oob_score=True, random_state=None, verbose=0, warm_start=False)
- 在 sklearn 中,你能夠在訓練後須要建立一個
BaggingClassifier
來自動評估時設置oob_score=True
來自動評估。而不須要使用交叉驗證或者使用單獨的驗證集
bag_clf.oob_score_
0.8833333333333333
# 比較一下 y_pred = bag_clf.predict(X_test) accuracy_score(y_test, y_pred)
0.95
1.3 隨機貼片和隨機子空間
BaggingClassifier也支持採樣特徵。它被兩個超參數max_features和bootstrap_features控制。他們的工做方式和max_samples和bootstrap同樣,但這是對於特徵採樣而不是實例採樣。所以,每個分類器都會被在隨機的輸入特徵內進行訓練。
當你在處理高維度輸入下(例如圖片)此方法尤爲有效。對訓練實例和特徵的採樣被叫作隨機貼片。保留了全部的訓練實例(例如bootstrap=False和max_samples=1.0),可是對特徵採樣(bootstrap_features=True而且/或者max_features小於 1.0)叫作隨機子空間。
採樣特徵致使更多的預測多樣性,用高誤差換低方差。
1.4 boosting(提高)
提高(Boosting,最初稱爲假設加強)指的是能夠將幾個弱學習者組合成強學習者的集成方法。
對於大多數的提高方法的思想就是按順序去訓練分類器,每個都要嘗試修正前面的分類。
現現在已經有不少的提高方法了,但最著名的就是 Adaboost(適應性提高,是 Adaptive Boosting 的簡稱) 和 Gradient Boosting(梯度提高)。讓咱們先從 Adaboost 提及。
1.4.1 Adaboost
使一個新的分類器去修正以前分類結果的方法就是對以前分類結果不對的訓練實例多加關注。這致使新的預測因子愈來愈多地聚焦於這種狀況。這是 Adaboost 使用的技術。
舉個例子,去構建一個 Adaboost 分類器,第一個基分類器(例如一個決策樹)被訓練而後在訓練集上作預測,在誤分類訓練實例上的權重就增長了。第二個分類機使用更新過的權重而後再一次訓練,權重更新,以此類推
sklearn 一般使用 Adaboost 的多分類版本 SAMME(這就表明了 分段加建模使用多類指數損失函數)。若是隻有兩類別,那麼 SAMME 是與 Adaboost 相同的。若是分類器能夠預測類別機率(例如若是它們有predict_proba()),若是 sklearn 可使用 SAMME 叫作SAMME.R的變量(R 表明「REAL」),這種依賴於類別機率的一般比依賴於分類器的更好。
from sklearn.ensemble import AdaBoostClassifier ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), n_estimators=200,algorithm="SAMME.R", learning_rate=0.5) ada_clf.fit(X_train, y_train)
AdaBoostClassifier(algorithm='SAMME.R', base_estimator=DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=1, 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'), learning_rate=0.5, n_estimators=200, random_state=None)
1.4.2 梯度提高(Gradient Boosting)
另外一個很是著名的提高算法是梯度提高。與 Adaboost 同樣,梯度提高也是經過向集成中逐步增長分類器運行的,每個分類器都修正以前的分類結果。然而,它並不像 Adaboost 那樣每一次迭代都更改實例的權重,這個方法是去使用新的分類器去擬合前面分類器預測的殘差 。
(1)以決策樹迴歸詳解
from sklearn.tree import DecisionTreeRegressor # 第一個分類器 tree_reg1 = DecisionTreeRegressor(max_depth=2) tree_reg1.fit(X, y) # 在第一個分類器的殘差上運行第二個分類器 y2 = y - tree_reg1.predict(X) tree_reg2 = DecisionTreeRegressor(max_depth=2) tree_reg2.fit(X, y2) # 在第二個分類器的殘差上運行第三個分類器 y3 = y2 - tree_reg1.predict(X) tree_reg3 = DecisionTreeRegressor(max_depth=2) ree_reg3.fit(X, y3) # 它能夠經過集成全部樹的預測來在一個新的實例上進行預測。 y_pred = sum(tree.predict(X_new) for tree in (tree_reg1, tree_reg2, tree_reg3))
(2)使用sklearn自帶分類器實現
- 超參數
learning_rate
確立了每一個樹的貢獻。若是你把它設置爲一個很小的樹,例
如 0.1,在集成中就須要更多的樹去擬合訓練集,但預測一般會更好。這個正則化技術叫作 shrinkage
from sklearn.ensemble import GradientBoostingRegressor gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=3, learning_rate=1.0) gbrt.fit(X, y)
(3)更好的梯度提高
爲了找到樹的最優數量,最簡單使用這個技術的方法就是使用staged_predict():它在訓練的每一個階段(用一棵樹,兩棵樹等)返回一個迭代器。接下來的代碼用 120 個樹訓練了一個 GBRT 集成,而後在訓練的每一個階段驗證錯誤以找到樹的最佳數量,最後使用 GBRT 樹的最優數量訓練另外一個集成:
import numpy as np from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error from sklearn.ensemble import GradientBoostingRegressor X_train, X_val, y_train, y_val = train_test_split(X, y) gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=120) gbrt.fit(X_train, y_train) errors = [mean_squared_error(y_val, y_pred) for y_pred in gbrt.staged_predict(X_val)] bst_n_estimators = np.argmin(errors) ## np.argmin表示最小值在數組中所在的位置 gbrt_best = GradientBoostingRegressor(max_depth=2,n_estimators=bst_n_estimators) gbrt_best.fit(X_train, y_train)
GradientBoostingRegressor(alpha=0.9, criterion='friedman_mse', init=None, learning_rate=0.1, loss='ls', max_depth=2, 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, n_estimators=119, n_iter_no_change=None, presort='auto', random_state=None, subsample=1.0, tol=0.0001, validation_fraction=0.1, verbose=0, warm_start=False)
(4)第二種更好的梯度提高
你也能夠早早的中止訓練來實現早停(與先在一大堆樹中訓練,而後再回頭去找最優數目相反)。你能夠經過設置warm_start=True來實現 ,這使得當fit()方法被調用時 sklearn 保留現有樹,並容許增量訓練。接下來的代碼在當一行中的五次迭代驗證錯誤沒有改善時會中止訓練:
gbrt = GradientBoostingRegressor(max_depth=2, warm_start=True) min_val_error = float("inf") error_going_up = 0 for n_estimators in range(1, 120): gbrt.n_estimators = n_estimators gbrt.fit(X_train, y_train) y_pred = gbrt.predict(X_val) val_error = mean_squared_error(y_val, y_pred) if val_error < min_val_error: min_val_error = val_error error_going_up = 0 else: error_going_up += 1 if error_going_up == 5:
1.5 Stacking
另一個集成方法叫作 Stacking(stacked generalization 的縮寫)。
這個算法基於一個簡單的想法:不使用瑣碎的函數(如硬投票)來聚合集合中全部分類器的預測,而是本身訓練一個模型來執行這個聚合。
sklearn 並不直接支持 stacking ,可是你本身組建是很容易的(看接下來的練習)。或者你也可使用開源的項目例如 brew (網址爲 <https: brew="" github.com="" viisar="">)</https:>
2、 隨機森林
2.1 實現隨機森林
隨機森林是決策樹的一種集成,**一般是經過 bagging 方法(有時是 pasting 方法)**進行訓練,一般用max_samples設置爲訓練集的大小與創建一個BaggingClassifier而後把它放入 DecisionTreeClassifier 相反,你可使用更方便的也是對決策樹優化夠的RandomForestClassifier(對於迴歸是RandomForestRegressor)。接下來的代碼訓練了帶有 50個樹(每一個被限制爲 16 葉子結點)的決策森林,使用全部空閒的 CPU 核:
from sklearn.ensemble import RandomForestClassifier rnd_clf = RandomForestClassifier(n_estimators=50, max_leaf_nodes=16, n_jobs=-1) rnd_clf.fit(X_train, y_train) y_pred_rf = rnd_clf.predict(X_test)
2.2 極端隨機樹
當你在隨機森林上生長樹時,在每一個結點分裂時只考慮隨機特徵集上的特徵(正如以前討論過的同樣)。相比於找到更好的特徵咱們能夠經過使用對特徵使用隨機閾值使樹更加隨機(像規則決策樹同樣)。
這種極端隨機的樹被簡稱爲 Extremely Randomized Trees(極端隨機樹),或者更簡單的稱爲 Extra-Tree。再一次用高誤差換低方差。它還使得 Extra-Tree 比規則的隨機森林更快地訓練,由於在每一個節點上找到每一個特徵的最佳閾值是生長樹最耗時的任務之一。
你可使用 sklearn 的ExtraTreesClassifier來建立一個 Extra-Tree 分類器。他的 API 跟RandomForestClassifier是相同的,類似的, ExtraTreesRegressor 跟RandomForestRegressor也是相同的 API。
咱們很難去分辨ExtraTreesClassifier和RandomForestClassifier到底哪一個更好。一般狀況下是經過交叉驗證來比較它們(使用網格搜索調整超參數)。
2.3 特徵重要度
若是你觀察一個單一決策樹,重要的特徵會出如今更靠近根部的位置,而不重要的特徵會常常出如今靠近葉子的位置。所以咱們能夠經過計算一個特徵在森林的所有樹中出現的平均深度來預測特徵的重要性。sklearn 在訓練後會自動計算每一個特徵的重要度。你能夠經過feature_importances_變量來查看結果。下面以鳶尾花數據爲例,得出最重要的特徵是花瓣長度(44%)和寬度(42%)。而萼片長度和寬度相對比較是不重要的(分別爲 11% 和 2%)
from sklearn.datasets import load_iris iris = load_iris() 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.10318363296580253 sepal width (cm) 0.024861953583854814 petal length (cm) 0.43069959942052854 petal width (cm) 0.4412548140298142