簡介
集成學(xué)習(xí),顧名思義就是將多種學(xué)習(xí)器或算法結(jié)合在一起,共同做出決策。這符合人類集思廣益的做法,在業(yè)界也是應(yīng)用最為廣泛的方法之一。注意,集成學(xué)習(xí)的本質(zhì)是如何找到不同的模型,并且將它們有機(jī)地進(jìn)行集成的方法。它是一種方法論,而不是一種具體的算法。
集成學(xué)習(xí)是一大類模型融合策略和方法的統(tǒng)稱,其中包含多種集成學(xué)習(xí)的思想。
集成學(xué)習(xí)的核心是要求各個(gè)子模型之間必須具有多樣性,或者說差異性,同時(shí)子模型本身要具有超過隨機(jī)猜測的準(zhǔn)確性,即“好而不同”,否則集成是沒有意義的。集成模型如下圖所示:

數(shù)據(jù)集行列采樣
把訓(xùn)練數(shù)據(jù)集看成一張二維表,如下圖所示,其中不同的矩形框住了不同的數(shù)據(jù)子集,如果使用這些數(shù)據(jù)子集就能訓(xùn)練出不同的模型?!靶小鄙系淖兓?,稱為行采樣?!傲小鄙系淖兓?,稱為隨機(jī)采列,如隨機(jī)森林的隨機(jī)取列的方法。通過隨機(jī)樣本和隨機(jī)特征能夠得到不同的隨機(jī)子集,它們是構(gòu)造多樣性模型的數(shù)據(jù)原料。
這樣的目的是在做集成學(xué)習(xí)的是,能夠讓不同的子學(xué)習(xí)器學(xué)習(xí)到數(shù)據(jù)的多樣性,從而構(gòu)建出多種學(xué)習(xí)大都不同數(shù)據(jù)分布特征的模型,再進(jìn)行集成的時(shí)候效果會更好。即增加了模型之間的差異性,多樣性。

算法的同質(zhì)和異質(zhì)
構(gòu)建“好而不同”的模型,除了上述的隨機(jī)樣本和隨機(jī)特征,不同的算法也是關(guān)鍵。當(dāng)子模型都是基于同一種模型構(gòu)建而成的,稱這樣的集成是同質(zhì)的。例如隨機(jī)森林算法中的基模型都是決策樹,隨機(jī)森林是不同決策樹組成的森林,所以隨機(jī)森林是同質(zhì)的。
當(dāng)子模型基于不同算法構(gòu)建成的,稱這樣的集成是異質(zhì)的,例如使用Stacking方法時(shí),是將多個(gè)不同性質(zhì)的模型結(jié)合起來。比如FackBook經(jīng)典的GBDT+LR的組合。

集成方法
集成學(xué)習(xí)構(gòu)造的是一個(gè)層次化的模型組織,層次化的組合結(jié)構(gòu)必然涉及如何組織、頂層如何匯聚這兩個(gè)步驟。目前常見的匯聚方法有投票組合法,例如Bagging;有關(guān)錯(cuò)誤樣例的方法例如Boosting等。本文主要介紹這兩種主流的集成學(xué)習(xí)方法。
Bagging方法
Bagging是“Bootstrap Aggregating”的組合縮寫,全稱翻譯為“自舉聚合”。使用Bagging方法集成模型,正如這兩個(gè)單詞的意思一樣,一共分為兩步:
- 采樣行采樣,且是有放回的隨機(jī)采樣來擴(kuò)充數(shù)據(jù)集
- 使用投票組合法來集成各個(gè)子模型
有放回的隨機(jī)采樣得到的樣本稱為Bootstrap樣本。有放回采樣的特點(diǎn)是每個(gè)樣本都可能會被重復(fù)抽中,有的樣本可能一直未被抽中。換句話說,Bagging集成方法中某些樣本在一個(gè)訓(xùn)練樣本中出現(xiàn)了多次,而有的樣本則一直未被訓(xùn)練。通過對訓(xùn)練樣本多次采樣,并分別訓(xùn)練出多個(gè)不同模型,然后進(jìn)行綜合,來減小集成分類器的方差。但是這都基于一個(gè)前提,那就是在樣本量足夠的情況下,有放回的采樣才靠譜。否則如果樣本很少,有放回的隨機(jī)采樣,最后構(gòu)造的樣本子集幾乎都是重復(fù)的數(shù)據(jù),那這樣無非是在無中生有,自欺欺人。
在進(jìn)行有放回的隨機(jī)采樣的時(shí)候,加入訓(xùn)練樣本總數(shù)為,當(dāng)
趨于無窮大時(shí),可得到樣本中某一個(gè)樣本一直未被抽樣到的概率為0.368,計(jì)算方式如下:
這是一個(gè)不低的占比,常用來被作為測試。使用Bagging方法本身就能提供模型性能估計(jì),而不必使用交叉驗(yàn)證。使用有放回的隨機(jī)采樣得到不同的樣本子集之后,針對每一個(gè)子集都訓(xùn)練一個(gè)模型,每個(gè)模型都進(jìn)行單獨(dú)學(xué)習(xí),學(xué)習(xí)的內(nèi)容可以相同,也可以不同,也可以部分重疊。但是由于個(gè)體之間存在差異性,最終做出的判斷不會完全一致。在最終做決策時(shí),每個(gè)個(gè)體單獨(dú)作出判斷,再通過投票的方式做出最后的集體決策。Bagging的集成過程如下:

Bagging集成方法中最具有代表性的算法就是隨機(jī)森林(Random Forest),可以認(rèn)為RF算法是Bagging模型的集大成者,具有廣泛的應(yīng)用。它具有以下特性:
- 使用隨機(jī)樣本和隨機(jī)特征,即隨機(jī)行和列,減少了基模型的相關(guān)性
- 使用實(shí)現(xiàn)簡單、高效和高精度的決策樹作為基模型
- 可以解決分類和回歸問題,也可以直接處理分類和數(shù)值特征
- Bagging抗過擬合和穩(wěn)定的特性,使得隨機(jī)森林能在偏差和方差之間權(quán)衡
sklearn中包含了隨機(jī)森林(Random Forest)的實(shí)現(xiàn),使用RF來進(jìn)行鶯尾花分類的代碼如下:
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
iris = load_iris()
X_train, X_test, Y_train, Y_test = train_test_split(iris.data, iris.target, random_state=2)
clf = RandomForestClassifier(max_depth=2, random_state=0)
clf.fit(X_train, Y_train)
X_pred = clf.predict(X_test)
print("accuracy rate: ", accuracy_score(Y_test, X_pred))


Boosting方法
Boosting方法訓(xùn)練基分類器時(shí)采用串行的方式,各個(gè)基分類器之間有依賴。它的基本思路是將基分類器層層疊加,每一層在訓(xùn)練的時(shí)候,對前一層基分類器分錯(cuò)的樣本,給予更高的權(quán)重。測試時(shí),根據(jù)各層分類器的結(jié)果的加權(quán)得到最終結(jié)果。
Boosting的過程很類似于人類學(xué)習(xí)的過程,我們學(xué)習(xí)新知識的過 程往往是迭代式的,第一遍學(xué)習(xí)的時(shí)候,我們會記住一部分知識,但往往也會犯 一些錯(cuò)誤,對于這些錯(cuò)誤,我們的印象會很深。第二遍學(xué)習(xí)的時(shí)候,就會針對犯 過錯(cuò)誤的知識加強(qiáng)學(xué)習(xí),以減少類似的錯(cuò)誤發(fā)生。不斷循環(huán)往復(fù),直到犯錯(cuò)誤的次數(shù)減少到很低的程度。

Boosting方法中最具代表性的算法是AdaBoost(自適應(yīng)提升)算法,其核心是不斷構(gòu)建新的模型,后一級模型訓(xùn)練的樣本是根據(jù)前一級模型預(yù)測錯(cuò)誤情況調(diào)整各個(gè)樣本的權(quán)重之后形成的新樣本,是一個(gè)串行的迭代過程。其中的迭代次數(shù)和基模型數(shù)量事先指定。隨著迭代次數(shù)的增加,經(jīng)驗(yàn)風(fēng)險(xiǎn)趨近于0。Adaboost算法的流程如下圖:

Sklearn中也有對應(yīng)的Adaboost算法的實(shí)現(xiàn),如下:
import numpy as np
from sklearn.datasets import make_moons
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
n = 200
x, y = make_moons(n, noise=0.1, random_state=42)
X_train, X_test, Y_train, Y_test = train_test_split(x, y, random_state=2)
# 單顆決策樹
clf = DecisionTreeClassifier(max_depth=3)
# adaboost算法
ada = AdaBoostClassifier(clf, # 基分類器為決策樹
n_estimators=10, # 一共使用10個(gè)
learning_rate=0.2,
random_state=4
)
# 使用單決策樹進(jìn)行擬合
clf.fit(X_train, Y_train)
X_pred = clf.predict(X_test)
print("single decision tree accuracy rate: ", accuracy_score(Y_test, X_pred))
# 使用adaBoost算法,包含10棵決策樹
ada.fit(X_train, Y_train)
X_pred_1 = ada.predict(X_test)
print("adaBoost accuracy rate: ", accuracy_score(Y_test, X_pred_1))
可以看到adaBoost使用了10棵樹,準(zhǔn)確率是要比單顆決策樹提升了不少。
當(dāng)然Boosting學(xué)習(xí)方法中還包括梯度提升樹等學(xué)習(xí)算法,這里不贅述,讀者有興趣可以參考GBDT原理分析以及XGBoost代碼實(shí)踐。
Boosting和Bagging的方差與偏差分析
集成學(xué)習(xí)可以有效地提升弱學(xué)習(xí)器的性能,即所謂的“三個(gè)臭皮匠賽過一個(gè)諸葛亮”。那集成學(xué)習(xí)是如何做到的?本節(jié)將從偏差和方差的角度來解釋這背后的原理。
首先需要了解一下偏差和方差的基本概念:
-
偏差指的是由所有采樣得到的大小為m的訓(xùn)練數(shù)據(jù)集訓(xùn)練出的所有模型的輸出的平均值和真實(shí)模型輸出之間的差別。
偏差通常是由于我們對學(xué)習(xí)算法做了錯(cuò)誤的假設(shè)所導(dǎo)致的,比如真實(shí)模型是某個(gè)二次函數(shù),但我們假設(shè)模型是一次函數(shù)。 由偏差帶來的誤差通常在訓(xùn)練誤差上就能體現(xiàn)出來。 -
方差指的是由所有采樣得到的大小為m的訓(xùn)練數(shù)據(jù)集訓(xùn)練出的所有模型的輸出的方差。
方差通常是由于模型的復(fù)雜度相對于訓(xùn)練樣本數(shù)m過高導(dǎo)致的,比如一共有100個(gè)訓(xùn)練樣本,而我們假設(shè)模型是階數(shù)不大于200的多項(xiàng)式函數(shù)。由方差帶來的誤差通常體現(xiàn)在測試誤差相對于訓(xùn)練誤差的增量上。
上述定義不夠直觀,直白點(diǎn)說,偏差代表了模型輸出結(jié)果的準(zhǔn)確程度,方差代表了模型輸出結(jié)構(gòu)的分散程度。
為了更清晰的理解偏差和方差,我們用一個(gè)射擊的例子來進(jìn)一步描述這二者的區(qū)別和聯(lián)系。假設(shè)一次射擊就是一個(gè)機(jī)器學(xué) 習(xí)模型對一個(gè)樣本進(jìn)行預(yù)測。射中靶心位置代表預(yù)測準(zhǔn)確,偏離靶心越遠(yuǎn)代表預(yù) 測誤差越大。 我們通過n次采樣得到n個(gè)大小為m的訓(xùn)練樣本集合,訓(xùn)練出n個(gè)模 型,對同一個(gè)樣本做預(yù)測,相當(dāng)于我們做了n次射擊,射擊結(jié)果如圖所示。我們最期望的結(jié)果就是左上角的結(jié)果,射擊結(jié)果又準(zhǔn)確又集中,說明模型的偏差和 方差都很小;右上圖雖然射擊結(jié)果的中心在靶心周圍,但分布比較分散,說明模 型的偏差較小但方差較大;同理,左下圖說明模型方差較小,偏差較大;右下圖 說明模型方差較大,偏差也較大。偏差和方差示意圖
先說結(jié)論,Bagging能夠提高弱分類器性能的原因是降低了方差,Boosting能夠提升弱分類器性能的原因是降低了偏差。
對于Bagging方法,假設(shè)有個(gè)獨(dú)立的隨機(jī)變量
,各自的方差記為
,那么它們的均值對應(yīng)方差為
。推導(dǎo)過程具體可以參考概率論,為什么樣本均值的方差為n分之D(X)?。這說明,模型平均能夠起到降低模型估計(jì)方差的效果。
再從模型的角度理解這個(gè)問題,對個(gè)獨(dú)立不相關(guān)的模型的預(yù)測結(jié)果取平均, 方差是原來單個(gè)模型的
。這個(gè)描述不甚嚴(yán)謹(jǐn),但原理已經(jīng)講得很清楚了。當(dāng)然,模型之間不可能完全獨(dú)立。為了追求模型的獨(dú)立性,諸多Bagging的方法做了 不同的改進(jìn)。比如在隨機(jī)森林算法中,每次選取節(jié)點(diǎn)分裂屬性時(shí),會隨機(jī)抽取一個(gè)屬性子集,而不是從所有屬性中選取最優(yōu)屬性,這就是為了避免弱分類器之間過強(qiáng)的相關(guān)性。通過訓(xùn)練集的重采樣也能夠帶來弱分類器之間的一定獨(dú)立性,從而降低Bagging后模型的方差。
Bagging方法增加了子模型之間的獨(dú)立性,在集成之后降低了模型的方差。
對于Boosting方法,在訓(xùn)練好一個(gè)弱分類器后,我們需要計(jì)算弱分類器的錯(cuò)誤或者殘差,作為下一個(gè)分類器的輸入。這個(gè)過程本身就是在不斷減小損失函數(shù),來使模型不斷逼近“靶心”,使得模型偏差不斷降低,即每一輪都能提高模型預(yù)測的準(zhǔn)確率。但Boosting的過程并不會顯著降低方差。這是因?yàn)锽oosting的訓(xùn)練過程使得各弱分類器之間是強(qiáng)相關(guān)的,缺乏獨(dú)立性,所以并不會對降低方差有作用。
關(guān)于泛化誤差、偏差、方差和模型復(fù)雜度的關(guān)系如下圖所示。不難看出,方 差和偏差是相輔相成,矛盾又統(tǒng)一的,二者并不能完全獨(dú)立的存在。對于給定的 學(xué)習(xí)任務(wù)和訓(xùn)練數(shù)據(jù)集,我們需要對模型的復(fù)雜度做合理的假設(shè)。如果模型復(fù)雜度過低,雖然方差很小,但是偏差會很高;如果模型復(fù)雜度過高,雖然偏差降低了,但是方差會很高。所以需要綜合考慮偏差和方差選擇合適復(fù)雜度的模型進(jìn)行訓(xùn)練。Boosting方法串行迭代迭代計(jì)算,增加了弱分類器的準(zhǔn)確率,減少了偏差。

參考
- 《機(jī)器學(xué)習(xí)--軟件工程的實(shí)現(xiàn)與方法》
- 《百面機(jī)器學(xué)習(xí)》
- https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html
