集成學習:隨機森林和GBDT

集成學習:隨機森林和GBDT


[外鏈圖片轉存失敗(img-23PmTXbA-1567001324533)(images/suijisenlin.gif)]

王境澤的機器學習技巧


什麼是集成學習(Voting Classifier)?

同一數據,同時應用多種差異模型,將預測結果用某種方式投票選出最佳結果

例如:新出的電影好不好看?根據其他人評價自行判斷

日常工作應用中,監督學習算法的選擇:

  • 如果爲了模型的可解釋性,如數據分析報告(準確率不重要),一般使用獨立模型(線性迴歸和邏輯迴歸)
  • 如果爲了模型的性能
    • 中小型數據(表格):集成學習
    • 大型/海量數據(圖片,音頻、視頻):深度學習

算法準確率:集成學習(隨機森林,GBDT)是僅次於深度學習的第二大算法

  • 深度學習需要海量數據支持,集成學習不需要大量數據,更簡單,應用更廣泛
  • 非常常用
  • 其他機器學習算法無論性能還是可解釋性都不如上述三類算法,實際工作很少使用
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
# 噪點參數0.3
X, y = datasets.make_moons(n_samples=500, noise=0.3, random_state=42)
plt.scatter(X[y==0,0], X[y==0,1], alpha=0.3)
plt.scatter(X[y==1,0], X[y==1,1], alpha=0.3)
<matplotlib.collections.PathCollection at 0x11906e80>

[外鏈圖片轉存失敗(img-jRiZvp8T-1567001324539)(output_4_1.png)]

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
from sklearn.neighbors import KNeighborsClassifier  # KNN

knn_clf = KNeighborsClassifier()
knn_clf.fit(X_train, y_train)
knn_clf.score(X_test, y_test)
0.912
from sklearn.tree import DecisionTreeClassifier  # 決策樹

dt_clf = DecisionTreeClassifier(random_state=666)
dt_clf.fit(X_train, y_train)
dt_clf.score(X_test, y_test)
0.864
from sklearn.linear_model import LogisticRegression  # 邏輯迴歸

log_clf = LogisticRegression(solver='lbfgs')
log_clf.fit(X_train, y_train)
log_clf.score(X_test, y_test)
0.864

手動集成三種算法學習結果

y_predict1 = knn_clf.predict(X_test)
y_predict1

y_predict2 = dt_clf.predict(X_test)
y_predict2

y_predict3 = log_clf.predict(X_test)
y_predict3
array([1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1,
       1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0,
       0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
       0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0,
       1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1,
       1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0], dtype=int64)
# 000,001 011,111
y_predict1 + y_predict2 + y_predict3
# 0,1, 2, 3
# 0, 1 = 0
# 2, 3 = 1

y_predict = ((y_predict1 + y_predict2 + y_predict3) >= 2).astype(np.int)
y_predict
array([1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1,
       1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0,
       0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0,
       0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0,
       1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1,
       1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0])
from sklearn.metrics import accuracy_score
accuracy_score(y_test, y_predict)
0.92

使用Voting Classifier自動集成學習

建議先分別執行各個算法,調好參數後再統一集成到一起

from sklearn.ensemble import VotingClassifier
voting_clf = VotingClassifier(
    estimators=[
        ('df_clf', DecisionTreeClassifier(random_state=222)),
        ('knn_clf', KNeighborsClassifier()),
        ('log_clf', LogisticRegression(solver='lbfgs')),
    ],
    voting='hard'
)
voting_clf.fit(X_train, y_train)
VotingClassifier(estimators=[('df_clf',
                              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=222,
                                                     splitter='best')),
                             ('knn_clf',
                              KNeighborsClassifier(a...
                                                   n_jobs=None, n_neighbors=5,
                                                   p=2, weights='uniform')),
                             ('log_clf',
                              LogisticRegression(C=1.0, class_weight=None,
                                                 dual=False, fit_intercept=True,
                                                 intercept_scaling=1,
                                                 l1_ratio=None, max_iter=100,
                                                 multi_class='warn',
                                                 n_jobs=None, penalty='l2',
                                                 random_state=None,
                                                 solver='lbfgs', tol=0.0001,
                                                 verbose=0,
                                                 warm_start=False))],
                 flatten_transform=True, n_jobs=None, voting='hard',
                 weights=None)
voting_clf.predict(X_test)
array([1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1,
       1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0,
       0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0,
       0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0,
       1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1,
       1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0], dtype=int64)
voting_clf.score(X_test, y_test)
0.928

參數voting值

  • hard
  • soft

例:某數據有2種分類,使用五種模型訓練並預測,得到結果爲:

模型1:A 99%;B 1%
模型2:A 49%;B 51%
模型3:A 40%;B 60%
模型4:A 90%;B 10%
模型5:A 30%;B 70%
  • hard voting模式:考慮投票數。
    • A:2票
    • B:3票
    • 最終結果爲B
  • soft voting模式:考慮投票權重
    • A = (0.99+0.49+0.4+0.9+0.3)/5 = 0.616
    • B = (0.01+0.51+0.6+0.1+0.7)/5 = 0.384
    • 最終結果爲A

soft voting要求集成的每個模型都能估計概率,否則無法運算(kNN、決策樹、邏輯迴歸都可以)

voting_clf = VotingClassifier(
    estimators=[
        ('df_clf',  DecisionTreeClassifier(random_state=666)),
        ('knn_clf', KNeighborsClassifier()),
        ('log_clf', LogisticRegression(solver='lbfgs')),
    ],
    voting='soft',
)
voting_clf.fit(X_train, y_train)
voting_clf.score(X_test, y_test)
0.888

更好的集成學習方式

現有的集成學習方式,能用於集成的模型太少,想要提高集成學習的準確率需要:

  • 創建和集成更多子模型
  • 子模型之間不能一致,要有差異性

子模型不需要太高的準確率,只要足夠多,就可以極大提升最終模型準確率

例如:每個子模型有60%準確率

  • 如果只有一個子模型,準確率60%
  • 如果有3個子模型:$ 0.6{3}+c{2}_{3}\cdot 0.6^{2}\cdot 0.4 =0.648 $
  • 如果有500個子模型:$ \sum {500}_{i=251}C{i}_{500}\cdot 0.6^{i}\cdot 0.4^{500-i} =0.9999 $

注意:子模型的準確率最好高於平均準確率

0.6 ** 3 + (2*3/2*1) * 0.6**2 * 0.4
0.648

如何產生大量有差異的子模型?

  • 機器學習算法就那麼點,就算所有算法和所有算法的參數都用上,也無法生成大量子模型
  • 隨機抽樣方式,每個子模型只抽取一部分樣本進行訓練
    • 例如:所有子模型都用一個算法,訓練集500條數據,每個子模型隨機抽取100條進行訓練,可以生成任意多個子模型
    • 子模型算法基本只使用決策樹算法,因爲決策樹大量的剪枝方式可以生成差異更大的模型,優於其他模型

兩種採樣方式:

Bagging:放回採樣(bootstrap),更常用,能製造更多子模型
Pasting:不放回採樣

使用Bagging方式集成學習

這裏Bagging方式集成學習只使用決策樹模型,

通過改變訓練數據生成子模型,決策樹大量的剪枝方式可以生成差異更大的模型,優於其他模型

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
bagging_clf = BaggingClassifier(
    DecisionTreeClassifier(),  # 集成的模型
    n_estimators=500,  # 集成多少個子模型
    max_samples=100,  # 每個子模型需要多少訓練數據
    bootstrap=True  # 放回抽樣
)
bagging_clf.fit(X_train, y_train)
bagging_clf.score(X_test, y_test)
0.92

子模型越多,準確率越高,模型訓練越慢

bagging_clf = BaggingClassifier(
    DecisionTreeClassifier(),  # 集成的模型
    n_estimators=5000,  # 集成多少個子模型
    max_samples=100,  # 每個子模型需要多少訓練數據
    bootstrap=True)  # 放回採樣

bagging_clf.fit(X_train, y_train)
bagging_clf.score(X_test, y_test)
0.912

沒有99%那麼多,因爲一些子模型準確率會低於均值,數據抽取次數過多,有大量相似模型


OOB:out of bag

放回採樣導致一部分樣本始終沒有被用於訓練

平均約有37%的樣本沒有被用到

所以不需要分離測試集,直接使用沒有被用過的樣本數據做測試集即可

bagging_clf = BaggingClassifier(
    DecisionTreeClassifier(),
    n_estimators=500,
    max_samples=100,
    bootstrap=True,
    oob_score=True)  # OOB爲True

bagging_clf.fit(X, y)  # 訓練數據採用全部樣本數據,不需要測試集
bagging_clf.oob_score_  # 調用OOB方法計算準確率
0.916

n_jobs 並行化處理

Bagging非常易於並行化處理

每個子模型可以獨立訓練,使用獨立cpu內核,加快速度

注意:如果訓練時間非常久,同時使用所有內核 n_jobs=-1, 非常容易卡死,訓練完成後才能恢復運算

%%time
bagging_clf = BaggingClassifier(
    DecisionTreeClassifier(),
    n_estimators=500,
    max_samples=100,
    bootstrap=True,
    oob_score=True)

bagging_clf.fit(X, y)
Wall time: 2.82 s





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=100, n_estimators=500, n_jobs=None,
                  oob_score=True, random_state=None, verbose=0,
                  warm_start=False)
%%time
bagging_clf = BaggingClassifier(
    DecisionTreeClassifier(),
    n_estimators=500,
    max_samples=100,
    bootstrap=True,
    oob_score=True,
    n_jobs=-1)  # 使用全部cpu內核

bagging_clf.fit(X, y)

更多Bagging方式

除了針對樣本數據進行隨機採樣,還有更多方式

  • 針對特徵進行隨機採樣,Random Subspaces
  • 既針對樣本、又針對特徵進行隨機採樣,Random Patches

bootstrap_features 針對特徵隨機取樣

random_subspaces_clf = BaggingClassifier(
    DecisionTreeClassifier(),
    n_estimators=500,
    max_samples=500,  # 關閉樣本隨機採樣,因爲子模型需要數據,設爲全部500條,不再選取部分數據
    bootstrap=True,
    oob_score=True,
    max_features=1,  # 隨機取1列特徵(因爲數據一共就2列特徵)
    bootstrap_features=True)  # 對特徵隨機採樣,放回採樣

random_subspaces_clf.fit(X, y)
random_subspaces_clf.oob_score_
0.834

既對樣本、又對特徵進行隨機採樣

random_patches_clf = BaggingClassifier(
    DecisionTreeClassifier(),
    n_estimators=500,
    max_samples=100,  # 打開樣本隨機採樣
    bootstrap=True,
    oob_score=True,
    max_features=1,  # 隨機取1列特徵(因爲數據一共就2列特徵)
    bootstrap_features=True)  # 對特徵隨機採樣,放回採樣

random_patches_clf.fit(X, y)
random_patches_clf.oob_score_
0.856

隨機森林

上面使用決策樹、以Bagging集成學習的方式,就是隨機森林

除了手動集成學習外,sklearn自帶一個隨機森林類,可以方便的創建隨機森林模型

隨機森林模型集成了決策樹和Bagging分類器,所以擁有決策樹和BaggingClassifier的所有參數

############################################################
from sklearn.ensemble import RandomForestClassifier
rf_clf = RandomForestClassifier(
    n_estimators=500,  # 500棵樹
    oob_score=True,  # 使用未被抽取的數據做測試集
    random_state=666,  # 隨機數種子固定
#     n_jobs=-1)  # 所有cpu內核並行運算
)
rf_clf.fit(X, y)
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
                       max_depth=None, max_features='auto', 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=500,
                       n_jobs=None, oob_score=True, random_state=666, verbose=0,
                       warm_start=False)
rf_clf.oob_score_
0.896

調節參數,提升準確率

rf_clf2 = RandomForestClassifier(
    n_estimators=500,
    max_leaf_nodes=16,  # 每個決策樹最多有幾個葉子節點
    oob_score=True,
    random_state=666,
    n_jobs=-1)

rf_clf2.fit(X, y)
rf_clf2.oob_score_
0.92
# help(RandomForestClassifier)

集成學習解決迴歸問題的子庫

from sklearn.ensemble import BaggingRegressor
from sklearn.ensemble import RandomForestRegressor  # 迴歸隨機森林

上面的集成學習算法叫Bagging

使用Bagging方式集成學習

  • Bagging:集成多個模型(並行)
    • 數據集每次抽取若干數據,用於子模型
    • 若干子模型同時進行訓練,和預測
    • 採用投票方式算出集成後的預測結果
  • Boosting:每個模型都在嘗試增強(Boosting)整體效果(串行)
    • 同一時間只有一個模型,只使用一個數據集
    • 每次訓練預測完成後,增加錯誤數據權重,降低預測正確數據權重,然後重新訓練
    • 迭代循環,直到準確率達到一定標準

Ada Boosting

[外鏈圖片轉存失敗(img-aBQMuefN-1567001324544)(images/adaboosting.png)]

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
ada_clf = AdaBoostClassifier(
    DecisionTreeClassifier(max_depth=2),  # 基礎學習算法
    n_estimators=500)

ada_clf.fit(X_train, y_train)
AdaBoostClassifier(algorithm='SAMME.R',
                   base_estimator=DecisionTreeClassifier(class_weight=None,
                                                         criterion='gini',
                                                         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,
                                                         presort=False,
                                                         random_state=None,
                                                         splitter='best'),
                   learning_rate=1.0, n_estimators=500, random_state=None)
ada_clf.score(X_test, y_test)
0.856

Gradient Boosting,(GBDT,更強)

  • 訓練模型m1,產生錯誤e1
  • 針對e1訓練模型m2,產生錯誤e2
  • 針對e2訓練模型m3, 產生錯誤e3…
  • 最終預測結果是:m1+m2+m3…

[外鏈圖片轉存失敗(img-eu2N16PR-1567001324550)(images/gboosting.png)]

from sklearn.ensemble import GradientBoostingClassifier

# Gradient Boosting就是以決策樹爲基礎的,不需要寫,設好集成子模型數量就行
gb_clf = GradientBoostingClassifier(max_depth=3, n_estimators=30)
gb_clf.fit(X_train, y_train)
gb_clf.score(X_test, y_test)
0.92

總結

scikit-learn自帶的常用集成算法:

  • Bagging:隨機森林
  • Boosting:GBDT

不過實際工作和比賽中,我們更常用的時專用集成學習庫

其他常用Boosting算法實現,如:XGboost,LightGBM(這兩個庫都是Boosting算法中的GBDT第三方實現),廣泛應用於各種數據科學機器學習競賽中

  • 運算速度更快
  • 準確率更高

sklearn不帶,需要另行安裝


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章