2018/12/11

Ensemble Learning (集體學習)

13 Ensemble Learning (集體學習)

Ensemble Learning 指的是組合多個估計器使得集體的性能比個別估計器的性能都好。一般有三種常見的架構:
  • Bootstrap aggregating (Bagging)
  • Boosting
  • Stacking (short for stacked generalization, also called meta ensembling)
∎ Bias-Variance trad-off (偏差和變異的權衡)
在討論集體學習前得先討論Bias-Variance trad-off (偏差和變異的權衡),偏差是指在給定的一組訓練集中,估計器能正確估計出 label 的程度,偏差愈大表示錯誤愈多,而變異是指當估計器訓練完成後,以不同組的測試資料集進行測試時所表現的性能差異,變異大則表示對不同測試集表現不穩定,變異小表示不同測試集間的性能表現差異不大。其中的權衡表示偏差和變異是相互衝突的目標,當要降低偏差時往往會造成變異性大,而要降低變異時會造成偏差變大。

在機器學習中,給定一組訓練集後進行訓練,當要降低偏差,也就是要使估計都正確則需增加系統的複雜度,到一個極端是預測給定的訓練資料百分之百正確,但用其他資料測試則錯誤相當大,此情形就稱Overfit (過適配)。另一個極端是要低變異性,所以盡量低系統的複雜度,雖然對訓練集的預測錯誤不小,但用不同組的資料測試一樣錯誤不小,所以變異性不大,這種情形就稱Underfit (欠適配)。進一步以下圖說明此兩性能指標。
Bias-Variance trad-off 
圖中青色曲線表示對訓練集裡的錯誤會著模型的複雜度增加而減少,而紅色曲線表示當模型超過某一複雜度後對預測的資料的錯誤也會隨著複雜度增加而增加,也就是變異性增大,圖中也說明了複雜度低時是高偏差低變異,而複雜度高時是偏差高變異,所以我們必需在兩者間取得一權衡,如圖指出約略就是中度的複雜度。

∎ Bootstrap aggregating (Bagging)
Bootstrap 是引導的意思,而 Aggregating是指聚集,此方法使用Bootstrap re-sampling的方法將訓練集的資料重新取樣。給定一個大小為 $n$ 的訓練集 $D$,從中均勻、有放回地選出 $m$ 個大小為 $𝑛'$的子集 $𝐷_𝑖$ 作為新的訓練集。在$m$ 個訓練集上使用分類、回歸等算法,則可有所 $m$個模型,再通過取平均值、取多數決等方法即可得到Bagging的結果。下列程是re-sampling的例子
import numpy as np
sample = np.random.randint(low=1, high=200, size=20)
print('Original sample: %s' % sample)
print('Sample mean: %s' % sample.mean())
resamples = [np.random.choice(sample, size=sample.shape) for i in range(10)]
print('Number of bootstrap re-samples: %s' % len(resamples))
print('Example re-sample: %s' % resamples[0])
resample_means = np.array([resample.mean() for resample in resamples])
print('Mean of re-samples\' means: %s' % resample_means.mean())
Original sample: [150  86  63   4 117 141  92 183  32  79  87 125  74 140  63  26 181  39
  41 132]
Sample mean: 92.75
Number of bootstrap re-samples: 10
Example re-sample: [ 32   4  26  39 141  63  63 181 132  26 141  92   4  86   4 117 132 141
  74 125]
Mean of re-samples' means: 93.01

 如果$m$個訓練集用於Decision tree 就是 Random forest (隨機森林)

∎ Random forest (隨機森林)
在Decision tree中,在每個節點上要決定選取的特徵時是用資訊增益的方式計算,所以決策樹對訓練集的資料的偏差很小,但對於不同的測試集變異性很大,所以決策樹算是一種低偏差高變異的估計器。隨機森林就是用於降低決策樹的變異性。森林指的是很多樹,而樹就是decision tree,亦即運用很多樹於決策上,也就是用多種模型(models)。Random (隨機) 指森林裡的每顆樹,從原始的訓練集位上述re-sampling的方法產生多份不同的訓練集給每一個決策樹訓練。在訓練過程中,Decision tree 在所有的節點都選最佳分裂的特徵,而在Random forest 中每節點路機選幾個特徵,並中選取最佳特徵,這是在訓練過程中最重要的不同處。

以下是Decision tree 和 Random forest 的比較。
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
X, y = make_classification(n_samples=1000, n_features=100, n_informative=20, 
       n_clusters_per_class=2, random_state=11)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=11)
print(X_test.shape)
clf = DecisionTreeClassifier(random_state=11)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
print(classification_report(y_test, predictions))
(250, 100)
             precision    recall  f1-score   support

          0       0.73      0.66      0.69       127
          1       0.68      0.75      0.71       123

avg / total       0.71      0.70      0.70       250
產生1000個人造samples,  train_test_split 分割,$3/4$用於訓練,$1/4$用於測試,
引入classification_report。上面是 decision tree 的性能。 再用random forest求。
clf = RandomForestClassifier(n_estimators=10, random_state=11)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
print(classification_report(y_test, predictions))
 precision    recall  f1-score   support

          0       0.74      0.83      0.79       127
          1       0.80      0.70      0.75       123

avg / total       0.77      0.77      0.77       250
第一行constructor 中 n_estimators=10宣告10個估計器。由結果看所列的三種性能都有提升。

∎ Boosting (提升)
此種學習方式是使用很多weaker models (弱模型)再其平均或多數用以降低系統的偏差。weaker model 指模型的系統簡單估計不很準確,但集合多個簡單的模型後可使估計正確,且偏差小,就是謂的「三個臭皮匠勝過一個諸葛亮」 ,如下圖
weaker models
圖中示出A,B,C,D是四個weaker models,在集體運作的情況下性能就能改善。

 sklearn提供多種基於boosting 的修改估計器可用於分類和回歸,如AdaBoostClassifier, AdaBoostRegressor, GradientBoostingClassifier, and GradientBoostingRegressor. AdaBoost 為adaptive boosting 的混合字,是一迭代演算法,可使用任何基本估計器為weak estimators. 對每個實例給定權重,當先前訓練正確則降低權重,不正確則增加權重,不斷的迭代,使得整體訓練的結果正確,當完成很完美的性能時,或者是在一揩定的迭代次數,學習結束。以下是取自文獻裡使用AdaBoostClassifier的例子。
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
X, y = make_classification(n_samples=1000, n_features=50, n_informative=30, 
       n_clusters_per_class=3, random_state=11)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=11)

clf = DecisionTreeClassifier(random_state=11)
clf.fit(X_train, y_train)
print('Decision tree accuracy: %s' % clf.score(X_test, y_test))
Decision tree accuracy: 0.688
顯示基本Decision tree的性能是0.688。以此當AdaBoostClassifier的基本估計器
%matplotlib inline
clf = AdaBoostClassifier(n_estimators=50, random_state=11)
clf.fit(X_train, y_train)
# accuracies.append(clf.score(X_test, y_test))
myfont = matplotlib.font_manager.FontProperties(fname=r'C:/Windows/Fonts/msjh.ttf')
plt.title('整體正確率', fontproperties=myfont)
plt.ylabel('正確率',fontproperties=myfont)
plt.xlabel('基本估計器數目',fontproperties=myfont)
plt.plot(range(1, 51), [accuracy for accuracy in clf.staged_score(X_test, y_test)])

AdaBoostClassifier
一般來講,當基本估計器數目增加,性能都能提升。程式第一行是ipython的magic function,其功能是能「即時」畫圖,不用於最後輸入plt.show()。

∎ Stacking (堆疊)
是一種使用meta-estimator(變形化估計器),將基本預測器的結果再行估計,有時亦稱Bending(混合)。基本預測器可以是不同性質的 classfier,如 logistic regression, decision tree, KNN classifier等,需要第二層學習(混合層),此層使用比簡單的平均數或多數決更複雜的函數以決定輸出,如下圖
Stacking
圖中有三個異質模型,其輸出再經一個混合層(meta-model),最後才得到整體的輸出。CART 是指 Classification And Regression Trees for Machine Learning,而 SVR 是指 Support Vector Regression。

參考文獻
Gavin Hackeling, Mastering Machine Learning with scikit-learn, 2nd, Packt Publishing, 2017

沒有留言:

張貼留言