scikit-learn 集成算法

2023-02-20 13:43 更新

集成算法的目的是將幾個(gè)基估計(jì)器的預(yù)測與給定的學(xué)習(xí)算法結(jié)合起來,以提高單個(gè)估計(jì)器的通用性和魯棒性。

集成方法一般分為兩種:

  • 平均法(averaging methods)中,該方法的原理是構(gòu)建多個(gè)獨(dú)立的估計(jì)器,然后取它們的預(yù)測結(jié)果的平均。一般來說,組合之后的估計(jì)器是會比單個(gè)估計(jì)器要好的,因?yàn)樗姆讲顪p小了。

    示例: Bagging methods, Forests of randomized trees, …

  • 相反,在提升法(boosting methods)中,基估計(jì)器是按順序建立的,并且試圖減小組合估計(jì)器的偏差。其動機(jī)是將幾個(gè)弱模型結(jié)合起來,形成一個(gè)強(qiáng)大的整體。

    示例: AdaBoost, Gradient Tree Boosting, …

1.11.1 Bagging meta-estimator(Bagging 元-估計(jì)器)

在集成算法中, bagging方法形成了一類算法,它在原始訓(xùn)練集的隨機(jī)子集上建立幾個(gè)黑箱估計(jì)器的實(shí)例,然后將它們的個(gè)體預(yù)測聚合起來,形成最終的預(yù)測。這些方法通過在基本估計(jì)器(例如決策樹)的構(gòu)造過程中引入隨機(jī)化,然后將其集成起來,從而降低單個(gè)基本估計(jì)器(如決策樹)的方差。在許多情況下,bagging方法是一個(gè)非常簡單的方法可以用來改進(jìn)相對單一模型,而不需要調(diào)整底層。由于bagging方法提供了一種減少過度擬合的途徑,因此對強(qiáng)大模型和復(fù)雜模型(例如,充分生長的決策樹)最有效,與之對比的提升法在弱模型(例如淺層決策樹)上表現(xiàn)最好。

Bagging方法有許多不同的變種(flavours),但主要是因?yàn)樗鼈兲崛∮?xùn)練集的隨機(jī)子集的方式不同:

  • 如果抽取的數(shù)據(jù)集的隨機(jī)子集是樣本的隨機(jī)子集,我們叫做粘貼 (Pasting) [B1999] 。
  • 如果樣本抽取是有放回的,我們稱為 Bagging。 [B1996]
  • 如果抽取的數(shù)據(jù)集的隨機(jī)子集是特征的隨機(jī)子集,我們叫做隨機(jī)子空間 (Random Subspaces) [H1998]
  • 最后,如果基估計(jì)器構(gòu)建在對于樣本和特征抽取的子集之上時(shí),我們叫做隨機(jī)補(bǔ)丁 (Random Patches) [LG2012].

在 scikit-learn中, bagging方法都是BaggingClassifier 元估計(jì)器(Resp)提供的。(或者BaggingRegressor),基估計(jì)器和隨機(jī)子集的抽取策略作為參數(shù)由用戶指定。特別是, max_samplesmax_features控制子集的大小(就樣本和特征而言),而 bootstrapbootstrap_features控制的是樣本和特征是否是有放回。當(dāng)使用可用樣本的子集時(shí),可以通過設(shè)置 oob_score=True來估計(jì)袋外(out-of-bag)樣本的泛化精度。舉一個(gè)例子,下面的片段說明了如何實(shí)例化KNeighborsClassifier基估計(jì)器的bagging集成,每個(gè)估計(jì)器都建立在50%的樣本和50%的特征的隨機(jī)子集上。

>>> from sklearn.ensemble import BaggingClassifier
>>> from sklearn.neighbors import KNeighborsClassifier
>>> bagging = BaggingClassifier(KNeighborsClassifier(),
...                             max_samples=0.5, max_features=0.5)
示例
單個(gè)估計(jì)器 vs bagging:偏差-方差分解

參考

[B1999] L. Breiman, “Pasting small votes for classification in large databases and on-line”, Machine Learning, 36(1), 85-103, 1999.

[B1996] L. Breiman, “Bagging predictors”, Machine Learning, 24(2), 123-140, 1996.

[H1998] T. Ho, “The random subspace method for constructing decision forests”, Pattern Analysis and Machine Intelligence, 20(8), 832-844, 1998.

[LG2012] G. Louppe and P. Geurts, “Ensembles on Random Patches”, Machine Learning and Knowledge Discovery in Databases, 346-361, 2012.

1.11.2 由隨機(jī)樹組成的森林

sklearn.ensemble集成模塊包括兩種基于隨機(jī)決策樹的平均算法:RandomForest算法和Extra-Trees算法。這兩種算法都是專門為樹設(shè)計(jì)的擾動和組合技術(shù)(perturb-and-combine techniques)[B1998] 。這意味著在分類器構(gòu)造過程中引入隨機(jī)性來創(chuàng)建一組不同的分類器的集合。集成之后的預(yù)測是每個(gè)分類器的平均。

與其他分類器一樣,森林分類器(forest classifiers)必須擬合兩個(gè)數(shù)組:一個(gè)稀疏或密集的X數(shù)組, 包含訓(xùn)練樣本, 形狀是[n_samples, n_features], 還有數(shù)組Y, 形狀是 [n_samples], 包含訓(xùn)練樣本的目標(biāo)值(類標(biāo)簽):

>>> from sklearn.ensemble import RandomForestClassifier
>>> X = [[0, 0], [1, 1]]
>>> Y = [0, 1]
>>> clf = RandomForestClassifier(n_estimators=10)
>>> clf = clf.fit(X, Y)

和決策樹 decision trees一樣,樹的森林也擴(kuò)展到多輸出問題 multi-output problems(如果Y是一個(gè)形狀為([n_samples, n_outputs])的數(shù)組。

1.11.2.1 隨機(jī)森林

在隨機(jī)森林中(請參閱 RandomForestClassifierRandomForestRegressor類), 集成模型中的每棵樹構(gòu)建時(shí)的樣本都是由訓(xùn)練集經(jīng)過有放回抽樣(比如a bootstrap sample 自助式采樣法)得來的。

另外,在構(gòu)建樹的過程中進(jìn)行結(jié)點(diǎn)分割時(shí),選擇的分割點(diǎn)是所有特征的最佳分割點(diǎn),或特征的大小為 max_features 的隨機(jī)子集的最佳分割。(更多細(xì)節(jié)請看parameter tuning guidelines )。

這兩種隨機(jī)的目的是降低森林估計(jì)器的方差。事實(shí)上,單個(gè)決策樹通常表現(xiàn)出很高的方差,并且往往會過擬合。在森林中注入隨機(jī)性產(chǎn)生的決策樹具有一定的解耦預(yù)測誤差(decoupled prediction errors)。通過取這些預(yù)測的平均值,可以抵消掉一些誤差。隨機(jī)森林通過組合不同的樹來減少方差,有時(shí)以增加一點(diǎn)點(diǎn)偏差為代價(jià)。在實(shí)踐中,方差減少通常是值得關(guān)注的,因此產(chǎn)生了一個(gè)整體更好的模型。

與最初的出版物 [B2001]相比,scikit-learn實(shí)現(xiàn)通過平均它們的概率預(yù)測來組合分類器,而不是讓每個(gè)分類器為單個(gè)類別進(jìn)行投票。

1.11.2.2 極端隨機(jī)樹

在極端隨機(jī)樹(參見 ExtraTreesClassifierExtraTreesRegressor 類)中,計(jì)算分割點(diǎn)方法中的隨機(jī)性進(jìn)一步增強(qiáng)。與隨機(jī)森林中一樣,使用了候選特征的隨機(jī)子集,但不像隨機(jī)森林中是尋找最具區(qū)分度的閾值,而是對每個(gè)候選特征隨機(jī)繪制閾值,并選擇這些隨機(jī)生成的閾值中最佳的作為作為分割規(guī)則。這種做法通常能夠減少一點(diǎn)模型的方差,代價(jià)則是略微地增大偏差:

>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.datasets import make_blobs
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.tree import DecisionTreeClassifier

>>> X, y = make_blobs(n_samples=10000, n_features=10, centers=100,
...     random_state=0)

>>> clf = DecisionTreeClassifier(max_depth=None, min_samples_split=2,
...     random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.98...

>>> clf = RandomForestClassifier(n_estimators=10, max_depth=None,
...     min_samples_split=2, random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.999...

>>> clf = ExtraTreesClassifier(n_estimators=10, max_depth=None,
...     min_samples_split=2, random_state=0)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean() > 0.999
True


1.11.2.3 參數(shù)

使用這些方法時(shí)要調(diào)整的參數(shù)主要是 n_estimatorsmax_features。前者(n_estimators)是森林里樹的數(shù)量,通常數(shù)量越大,效果越好,但是計(jì)算時(shí)間也會隨之增加。此外要注意,當(dāng)樹的數(shù)量超過一個(gè)臨界值之后,算法的效果并不會很顯著地變好。后者(max_features)是分割節(jié)點(diǎn)時(shí)考慮的特征的隨機(jī)子集的大小。 這個(gè)值越低,方差減小得越多,但是偏差的增大也越多。 根據(jù)經(jīng)驗(yàn),回歸問題中使用 max_features = None (總是考慮所有的特征而不是一個(gè)子集), 分類問題使用 max_features = "sqrt" (隨機(jī)考慮 sqrt(n_features) 特征,其中 n_features 是數(shù)據(jù)中特征的個(gè)數(shù))是比較好的默認(rèn)值。 max_depth = Nonemin_samples_split = 2結(jié)合通常會有不錯的效果(即完全生長的樹)。 請記住,這些(默認(rèn))值通常不是最佳的,同時(shí)還可能消耗大量的內(nèi)存,最佳參數(shù)值應(yīng)由交叉驗(yàn)證獲得。 另外,請注意,在隨機(jī)森林中,默認(rèn)使用自助采樣法(bootstrap = True), 然而 extra-trees 的默認(rèn)策略是使用整個(gè)數(shù)據(jù)集(bootstrap = False)。 當(dāng)使用自助采樣法方法抽樣時(shí),泛化精度是可以通過剩余的或者袋外(out-of-bag) 的樣本來評估的,設(shè)置 oob_score = True 即可實(shí)現(xiàn)。

注意:默認(rèn)參數(shù)下模型復(fù)雜度是:O(M*N*log(N)) , 其中 M 是樹的數(shù)目, N 是樣本數(shù)。 可以通過設(shè)置以下參數(shù)來降低模型復(fù)雜度: min_samples_split ,?max_leaf_nodes ,?max_depthmin_samples_leaf。

1.11.2.4 并行化

最后,這個(gè)模塊還支持樹的并行構(gòu)建和預(yù)測結(jié)果的并行計(jì)算,這可以通過 n_jobs 參數(shù)實(shí)現(xiàn)。 如果設(shè)置 n_jobs = k ,則計(jì)算被劃分為 k 個(gè)作業(yè),并運(yùn)行在機(jī)器的 k 個(gè)核上。 如果設(shè)置 n_jobs = -1 ,則使用機(jī)器的所有核。 注意由于進(jìn)程間通信具有一定的開銷,這里的提速并不是線性的(即,使用 k 個(gè)作業(yè)不會快 k 倍)。 當(dāng)然,在建立大量的樹,或者構(gòu)建單個(gè)樹需要相當(dāng)長的時(shí)間(例如,在大數(shù)據(jù)集上)時(shí),(通過并行化)仍然可以實(shí)現(xiàn)顯著的加速。

示例
在iris數(shù)據(jù)集上繪制決策樹的決策面
基于平行樹的森林的像素重要性
Face completion with a multi-output estimators

參考

[B2001] Breiman, “Random Forests”, Machine Learning, 45(1), 5-32, 2001.

[B1998] Breiman, “Arcing Classifiers”, Annals of Statistics 1998.

P. Geurts, D. Ernst., and L. Wehenkel, “Extremely randomized trees”, Machine Learning, 63(1), 3-42, 2006.

1.11.2.5 特征重要性評估

特征對目標(biāo)變量預(yù)測的相對重要性可以通過(樹中的決策節(jié)點(diǎn)的)特征使用的相對順序(即深度)來進(jìn)行評估。 決策樹頂部使用的特征對輸入的大部分樣本的最終預(yù)測決策做出貢獻(xiàn);因此,可以使用接受每個(gè)特征對最終預(yù)測的貢獻(xiàn)的樣本比例來評估該 特征的相對重要性 。scikit-learn通過將特征貢獻(xiàn)的樣本比例與分割時(shí)產(chǎn)生的不純度減少相結(jié)合, 從而創(chuàng)建了對該特征的預(yù)測能力的標(biāo)準(zhǔn)化估計(jì)。

通過對多個(gè)隨機(jī)樹中的 預(yù)期貢獻(xiàn)率 (expected activity rates) 取平均,可以減少這種估計(jì)的 方差 ,并將其用于特征選擇。這被稱作平均純度減少,或MDI。關(guān)于MDI以及隨機(jī)森林特征重要性的更多信息,請參考[L2014]。

警告:在基于樹的模型上計(jì)算的基于不存度的特征重要性存在兩個(gè)缺陷,可能導(dǎo)致誤導(dǎo)性結(jié)論。首先,它們是根據(jù)從訓(xùn)練數(shù)據(jù)集派生出來的統(tǒng)計(jì)數(shù)據(jù)來計(jì)算的,因此不一定能告訴我們對于更好的預(yù)測保留的數(shù)據(jù)(held-out dataset), 到底哪些特征才是最重要的。其次,他們傾向于高基數(shù)特征,即具有許多不同值的特征。置換特征重要性Permutation feature importance是不受這些缺陷影響的基于不存度計(jì)算特征重要性的替代選項(xiàng)。這里兩種方法對獲取特征重要性進(jìn)行了探討::置換重要性與隨機(jī)森林特征重要性(MDI)。

下面的示例顯示了使用 ExtraTreesClassifier 模型對人臉識別任務(wù)的單個(gè)像素的相對重要性的顏色編碼表示。

  實(shí)際上,這些估計(jì)值存儲在一個(gè)已經(jīng)擬合的模型的屬性 feature_importances_上。這是一個(gè)大小為(n_features,)的數(shù)組,其值為正,總和為1.0。值越高,匹配特征對預(yù)測函數(shù)的貢獻(xiàn)就越重要。

示例
基于平行樹的森林的像素重要性
樹森林的特征重要性

參考

[L2014] G. Louppe, “Understanding Random Forests: From Theory to Practice”, PhD Thesis, U. of Liege, 2014.

1.11.2.6 完全隨機(jī)樹嵌入

RandomTreesEmbedding 實(shí)現(xiàn)了一個(gè)無監(jiān)督的數(shù)據(jù)轉(zhuǎn)換。 通過由完全隨機(jī)樹構(gòu)成的森林,RandomTreesEmbedding 使用數(shù)據(jù)最終歸屬的葉子節(jié)點(diǎn)的索引值對數(shù)據(jù)進(jìn)行編碼。 該索引以 one-of-K 方式編碼,最終形成一個(gè)高維的稀疏二值化編碼。 這種編碼可以被非常高效地計(jì)算出來,并且可以作為其他學(xué)習(xí)任務(wù)的基礎(chǔ)。 編碼的大小和稀疏度可以通過選擇樹的數(shù)量和每棵樹的最大深度來確定。對于集成中的每棵樹的,每個(gè)樣本對應(yīng)其中的一個(gè)葉節(jié)點(diǎn)。 編碼的大?。ňS度)最多為 n_estimators * 2 ** max_depth ,即森林中的葉子節(jié)點(diǎn)的最大數(shù)。

由于相鄰數(shù)據(jù)點(diǎn)更可能位于一顆樹的同一葉子中,該變換可以作為一種隱式地非參數(shù)密度估計(jì)。

示例
基于完全隨機(jī)樹的哈希特征變換
手寫數(shù)字上的流形學(xué)習(xí):局部線性嵌入,Isomap… 比較了手寫體數(shù)字的非線性降維技術(shù)。
樹集成的特征轉(zhuǎn)換 比較了基于樹的有監(jiān)督和無監(jiān)督特征變換.

也可以看這里:流形學(xué)習(xí)技術(shù)也可以用來導(dǎo)出特征空間的非線性表示,這些方法也側(cè)重于維數(shù)約簡。

1.11.3. AdaBoost

sklearn.ensemble 模塊包含了流行的提升算法 AdaBoost, 這個(gè)算法是由 Freund 和 Schapire 在 1995 年提出來的[FS1995]。

AdaBoost 的核心思想是用反復(fù)調(diào)整的數(shù)據(jù)來訓(xùn)練一系列的弱學(xué)習(xí)器(一個(gè)弱學(xué)習(xí)器模型僅僅比隨機(jī)猜測好一點(diǎn), 比如一個(gè)簡單的決策樹),由這些弱學(xué)習(xí)器的預(yù)測結(jié)果通過加權(quán)投票(或加權(quán)求和)的方式組合, 產(chǎn)生最終的預(yù)測結(jié)果。在每一次所謂的提升(boosting)迭代中,數(shù)據(jù)的修改由應(yīng)用于每一個(gè)訓(xùn)練樣本的(新) 的權(quán)重 組成。 初始化時(shí),將所有弱學(xué)習(xí)器的權(quán)重都設(shè)置為 ,因此第一次迭代僅僅是通過原始數(shù)據(jù)訓(xùn)練出一個(gè)弱學(xué)習(xí)器。在接下來的連續(xù)迭代中,樣本的權(quán)重逐個(gè)地被修改,學(xué)習(xí)算法也因此要重新應(yīng)用這些已經(jīng)修改的權(quán)重的數(shù)據(jù)。在給定的一個(gè)迭代中, 那些在上一輪迭代中被預(yù)測為錯誤結(jié)果的樣本的權(quán)重將會被增加,而那些被預(yù)測為正確結(jié)果的樣本的權(quán)重將會被降低。隨著迭代次數(shù)的增加,那些難以預(yù)測的樣例的影響將會越來越大,每一個(gè)隨后的弱學(xué)習(xí)器都將會被強(qiáng)迫更加關(guān)注那些在之前被錯誤預(yù)測的樣例[HTF]。


AdaBoost可以用于分類和回歸問題:

  • 對于多類分類, AdaBoostClassifier實(shí)現(xiàn)了AdaBoost-Samme和AdaBoost-SAMME.R[ZRH 2009]。
  • 對于回歸, AdaBoostRegressor實(shí)現(xiàn)了AdaBoost.R2[D 1997]。

1.11.3.1 使用方法

下面的示例演示如何為100個(gè)弱學(xué)習(xí)器擬合AdaBoost分類器:

>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.datasets import load_iris
>>> from sklearn.ensemble import AdaBoostClassifier

>>> X, y = load_iris(return_X_y=True)
>>> clf = AdaBoostClassifier(n_estimators=100)
>>> scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.9...

弱學(xué)習(xí)器的數(shù)量由參數(shù)n_estimators控制。learning_rate參數(shù)控制著弱學(xué)習(xí)者在最終組合中的貢獻(xiàn)。默認(rèn)情況下,弱學(xué)習(xí)器是決策樹。通過 base_estimator 參數(shù)可以指定不同的弱學(xué)習(xí)器。要獲得良好結(jié)果的主要參數(shù)是n_estimators和基估計(jì)器的復(fù)雜度(例如,它的深度 max_depth或考慮分裂的最小樣本數(shù)min_samples_split)。

示例
離散型與真實(shí)型AdaBoost 使用 AdaBoost-SAMME 和 AdaBoost-SAMME.R 比較 decision stump, decision tree(決策樹)和 boosted decision stump(增強(qiáng)決策樹)的分類錯誤
多類AdaBoost決策樹 展示了 AdaBoost-SAMME 和 AdaBoost-SAMME.R 在 multi-class (多類)問題上的性能。
兩類AdaBoost 展示了使用 AdaBoost-SAMME 的非線性可分兩類問題的決策邊界和決策函數(shù)值。
基于AdaBoost的決策樹回歸 使用 AdaBoost.R2 算法證明了回歸。

參考

  • [FS1995] Y. Freund, and R. Schapire, “A Decision-Theoretic Generalization of On-Line Learning and an Application to Boosting”, 1997.
  • [ZZRH2009] J. Zhu, H. Zou, S. Rosset, T. Hastie. “Multi-class AdaBoost”, 2009.
  • [D1997] Drucker. “Improving Regressors using Boosting Techniques”, 1997.
  • HTF(1,2,3) T. Hastie, R. Tibshirani and J. Friedman, “Elements of Statistical Learning Ed. 2”, Springer, 2009.

1.11.4 梯度樹提升

梯度樹提升Gradient Tree Boosting或梯度提升樹(Gradient Boosted Decision Trees,GBDT)是Booting對任意可微損失函數(shù)的推廣。GBDT是一種準(zhǔn)確有效的現(xiàn)成程序,可用于各種領(lǐng)域的回歸和分類問題,包括Web搜索、排名和生態(tài)領(lǐng)域。

集成模塊 sklearn.ensemble 通過梯度提升樹提供了分類和回歸的方法。

注意:在LightGBM (參看 [LightGBM])的啟發(fā)下,Scikit-learn 0.21引入了兩種新的梯度提升樹的實(shí)驗(yàn)實(shí)現(xiàn),即 HistGradientBoostingClassifierHistGradientBoostingRegressor。當(dāng)樣本數(shù)大于數(shù)萬個(gè)樣本時(shí),這些基于直方圖的估計(jì)可以比GradientBoostingClassifierGradientBoostingRegressor 快幾個(gè)數(shù)量級。他們還內(nèi)置了對缺失值的支持,從而避免了計(jì)算的需要。這些估計(jì)器將在下面基于直方圖的梯度提升Histogram-Based Gradient Boosting中更詳細(xì)地描述。

下面的指南重點(diǎn)介紹 GradientBoostingClassifierGradientBoostingRegressor,它們可能是小樣本大小的首選,因?yàn)樵谶@個(gè)設(shè)置中,裝箱可能會導(dǎo)致分割點(diǎn)過于接近。

下面介紹了 GradientBoostingClassifierGradientBoostingRegressor的用法和參數(shù)。這些估計(jì)器最重要的兩個(gè)參數(shù)是n_estimatorslearning_rate。

1.11.4.1 分類

GradientBoostingClassifier 既支持二分類,也支持多類分類。下面的示例說明了如何將梯度提升分類器與100個(gè)決策樹作為弱學(xué)習(xí)者進(jìn)行匹配:

>>> from sklearn.datasets import make_hastie_10_2
>>> from sklearn.ensemble import GradientBoostingClassifier

>>> X, y = make_hastie_10_2(random_state=0)
>>> X_train, X_test = X[:2000], X[2000:]
>>> y_train, y_test = y[:2000], y[2000:]

>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
...     max_depth=1, random_state=0).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.913...

弱學(xué)習(xí)器的數(shù)量(即回歸樹)由參數(shù)n_estimators控制,每棵樹的大小The size of each tree可以通過設(shè)置樹的深度max_depth來控制,也可以通過通過最大葉節(jié)點(diǎn)樹max_leaf_nodes數(shù)來控制。學(xué)習(xí)速率 learning_rate是一個(gè)范圍是(0.0,1.0]的一個(gè)超參數(shù),它通過shrinkage 來控制過擬合。

注意:超過兩類的分類問題需要在每一次迭代時(shí)推導(dǎo) n_classes 個(gè)回歸樹。因此,所有的需要推導(dǎo)的樹數(shù)量等于 n_classes * n_estimators 。對于擁有大量類別的數(shù)據(jù)集我們強(qiáng)烈推薦使用 HistGradientBoostingClassifier 來代替 GradientBoostingClassifier 。

1.11.4.2 回歸

對于回歸問題 GradientBoostingRegressor 支持一系列損失函數(shù),這些損失函數(shù)可以通過參數(shù) loss 來指定;對于回歸問題默認(rèn)的損失函數(shù)是最小二乘損失( 'ls' )。

>>> import numpy as np
>>> from sklearn.metrics import mean_squared_error
>>> from sklearn.datasets import make_friedman1
>>> from sklearn.ensemble import GradientBoostingRegressor

>>> X, y = make_friedman1(n_samples=1200, random_state=0, noise=1.0)
>>> X_train, X_test = X[:200], X[200:]
>>> y_train, y_test = y[:200], y[200:]
>>> est = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1,
...     max_depth=1, random_state=0, loss='ls').fit(X_train, y_train)
>>> mean_squared_error(y_test, est.predict(X_test))
5.00...

下圖顯示了將最小二乘損失和500個(gè)基學(xué)習(xí)器的GradientBoostingRegressor應(yīng)用于波士頓房價(jià)數(shù)據(jù)集(sklearn.datasets.load_boston)的結(jié)果。左邊的圖顯示了每次迭代時(shí)的訓(xùn)練和測試誤差。每一次迭代時(shí)的訓(xùn)練誤差都存儲在梯度提升模型的train_score_屬性中。每次迭代時(shí)的測試誤差可以通過staged_predict方法獲得,該方法返回在每個(gè)階段生成預(yù)測的生成器。這樣畫圖可以通過早期停止來確定樹的最優(yōu)數(shù)目(即 n_estimators)。右邊的圖顯示了基于不存度的特征重要性,它可以通過feature_importances_屬性獲得。


示例
梯度提升回歸
梯度提升袋外估計(jì)

1.11.4.3 訓(xùn)練額外的弱學(xué)習(xí)器

GradientBoostingRegressorGradientBoostingClassifier都支持 warm_start=True ,這允許您在已經(jīng)擬合的模型中添加更多的估計(jì)器

>>> _ = est.set_params(n_estimators=200, warm_start=True)  
# set warm_start and new nr of trees
>>> _ = est.fit(X_train, y_train) # fit additional 100 trees to est
>>> mean_squared_error(y_test, est.predict(X_test))
3.84...

1.11.4.4 控制樹的大小

回歸樹基學(xué)習(xí)器的大小定義了梯度提升模型可以捕捉到的變量交互的水平。一般來說,深度h的樹可以捕捉h階的相互作用。有兩種方法可以控制單個(gè)回歸樹的大小。

如果你指定 max_depth=h ,那么將會產(chǎn)生一個(gè)深度為 h 的完全二叉樹。這棵樹將會有(至多) 2**h 個(gè)葉子節(jié)點(diǎn)和 2**h - 1 個(gè)分割節(jié)點(diǎn)。

或者,您還可以通過參數(shù)max_leaf_nodes指定葉節(jié)點(diǎn)的數(shù)目來控制樹的大小。在這種情況下,樹將使用最佳優(yōu)先搜索來生長,這種搜索方式是通過每次選取對不純度提升最大的節(jié)點(diǎn)來首先展開。一棵 max_leaf_nodes=k 的樹擁有 k - 1 個(gè)切分節(jié)點(diǎn),因此可以模擬max_leaf_nodes - 1階的交互作用。

我們發(fā)現(xiàn) max_leaf_nodes=k 可以給出與 max_depth=k-1 品質(zhì)相當(dāng)?shù)慕Y(jié)果,但是其訓(xùn)練速度明顯更快,同時(shí)也會以多一點(diǎn)的訓(xùn)練誤差作為代價(jià)。參數(shù) max_leaf_nodes 對應(yīng)于文章 [F2001]中梯度提升章節(jié)中的變量 J ,同時(shí)與 R 語言的 gbm 包的參數(shù) interaction.depth 相關(guān),兩者間的關(guān)系是 max_leaf_nodes == interaction.depth + 1

1.11.4.5 數(shù)學(xué)公式

我們首先說GBRT的回歸,然后詳細(xì)介紹分類案例。

1.11.4.5.1 回歸

GBRT回歸器是一種加法模型,其對給定輸入的預(yù)測由以下形式給出:

其中,是在boosting中被稱為弱學(xué)習(xí)器的估計(jì)器。梯度樹提升采用固定大小的決策樹回歸器作為弱學(xué)習(xí)器。常數(shù)對應(yīng)n_estimators參數(shù)。

與其他提升算法類似,GBRT是以貪婪的方式構(gòu)建的:

其中新添加的樹中的是為了最小化損失的總和而擬合的,給定前面的集成器為

其中loss參數(shù)定義,詳見下一節(jié)。

默認(rèn)情況下,初始模型選擇使損失最小化的常數(shù):對于最小二乘損失,這是目標(biāo)值的經(jīng)驗(yàn)平均值。初始模型也可以通過init參數(shù)指定。

使用一階泰勒(Taylor)近似,的值可以近似為如下:

注意:簡要地說, 一階泰勒近似是:, 這里對應(yīng), 對應(yīng)。

是損失相對于第二個(gè)參數(shù)的導(dǎo)數(shù), 這里按計(jì)算。對于任何給定的,由于損失都是可微的,因此很容易計(jì)算出它的閉合形式。我們用表示。

除去常數(shù)項(xiàng),我們有:

如果被擬合來預(yù)測的值與負(fù)梯度成正比,則這是最小化的。因此,在每次迭代時(shí),被擬合的估計(jì)器用來預(yù)測樣本的負(fù)梯度。梯度在每次迭代中都會被更新。這可以看作是函數(shù)空間中的某種梯度下降。

注意:注意,對于一些損失,例如最小絕對偏差(LAD),其梯度為±1,擬合的預(yù)測的值不夠精確:這樣樹只能輸出整數(shù)值。因此,一旦樹被擬合,樹的葉子上的值就會被修改,使葉子上的能能最小化損失。更新是依賴于損失的:對于LAD損失,葉子的值將被更新為該葉中樣本的中值。

1.11.4.5.2 分類

梯度提升的分類非常類似于回歸的情況。然而,樹的總和 與預(yù)測不是同質(zhì)的:它不能是一個(gè)類,因?yàn)闃漕A(yù)測的是連續(xù)值。

到類或概率的映射依賴于損失。對于偏差(或?qū)?shù)損失), 屬于正類的概率被建模為,其中是sigmoid函數(shù)。

對于多類分類,K樹(對于K類)是在每一個(gè)迭代中構(gòu)建的。屬于k類的概率被建模為值的一個(gè)Softmax。

請注意,即使對于分類任務(wù),基估計(jì)器仍然是一個(gè)回歸器,而不是分類器。這是因?yàn)榛烙?jì)器被訓(xùn)練來預(yù)測(負(fù))梯度,這些梯度總是連續(xù)的。

1.11.4.6 損失函數(shù)

支持下面這些損失函數(shù),并可以使用參數(shù) loss指定這些函數(shù):

  • 回歸
    • 最小二乘('ls'):回歸的自然選擇,因?yàn)樗哂袃?yōu)越的計(jì)算特性。用目標(biāo)值的平均值給出了初始模型。
    • 最小絕對偏差('lad'):一個(gè)穩(wěn)健的回歸損失函數(shù)。初始模型由目標(biāo)值的中值給出。
    • Huber(‘Huber’):另一個(gè)結(jié)合最小二乘和最小絕對偏差的穩(wěn)健損失函數(shù);使用alpha控制異常值的靈敏度(詳見[F2001])。
    • Quantile ('quantile'):分位數(shù)回歸的損失函數(shù)。使用 0 < alpha < 1指定分位數(shù)。此損失函數(shù)可用于創(chuàng)建預(yù)測間隔 (參見梯度提升回歸的預(yù)測間隔 Prediction Intervals for Gradient Boosting Regression)
  • 分類
    • 二項(xiàng)偏差('deviance'):二分類的負(fù)二項(xiàng)式對數(shù)似然損失函數(shù)(提供概率估計(jì))。用對數(shù)比率給出了初始模型。
    • 多項(xiàng)偏差('deviance'):對于多分類問題的負(fù)的多項(xiàng)對數(shù)似然損失函數(shù)具有 n_classes個(gè)互斥的類。提供概率估計(jì)。 初始模型由每個(gè)類的先驗(yàn)概率給出.在每一次迭代中 n_classes 回歸樹被構(gòu)建,這使得 GBRT 在處理多類別數(shù)據(jù)集時(shí)相當(dāng)?shù)托А?/section>
    • 指數(shù)損失('exponential'):與 AdaBoostClassifier 具有相同的損失函數(shù)。與 'deviance' 相比,對被錯誤標(biāo)記的樣本的魯棒性較差,僅用于在二分類問題。

1.11.4.7 學(xué)習(xí)收縮率

[F2001] 提出了一種簡單的正則化策略,通過常數(shù)因子 來衡量每個(gè)弱學(xué)習(xí)器的貢獻(xiàn):

參數(shù)也稱為學(xué)習(xí)速率,因?yàn)樗梢钥s放步長、梯度下降過程;它可以通過 learning_rate參數(shù)來設(shè)置。

參數(shù)learning_raten_estimators(弱學(xué)習(xí)器的個(gè)數(shù))有很強(qiáng)的相互作用。較小的learning_rate值要求較多的弱學(xué)習(xí)者以保持一個(gè)恒定的訓(xùn)練誤差。經(jīng)驗(yàn)證據(jù)表明,較小的learning_rate有利于更好的測試誤差。[HTF]建議將學(xué)習(xí)速率設(shè)置為一個(gè)小常數(shù)(例如,learning_rate <= 0.1),并通過早期的停止選擇n_estimators。關(guān)于learning_raten_estimators 之間相互作用的更詳細(xì)的討論,見 [R2007]。

1.11.4.8 子采樣(Subsampling)

[F1999] 提出了隨機(jī)梯度提升,這種方法將梯度提升(gradient boosting)和 bootstrap averaging(bagging) 相結(jié)合。在每次迭代中,基分類器是通過抽取所有可利用訓(xùn)練集中一小部分的 subsample 訓(xùn)練得到的子樣本采用無放回的方式采樣。 subsample 參數(shù)的值一般設(shè)置為 0.5 。

下圖表明了收縮與否和子采樣對于模型擬合好壞的影響。我們可以明顯看到指定收縮率比沒有收縮擁有更好的表現(xiàn)。而將子采樣和收縮率相結(jié)合能進(jìn)一步的提高模型的準(zhǔn)確率。相反,使用子采樣而不使用收縮的結(jié)果十分糟糕。


另一種降低方差的策略是對隨機(jī)森林分類器中類似隨機(jī)分裂的特征進(jìn)行二次采樣。通過max_features參數(shù)可以控制子采樣特征的數(shù)量。

注意:使用一個(gè)較小的max_Feature值可以顯著減少運(yùn)行時(shí)。

隨機(jī)梯度提升允許計(jì)算測試偏差的袋外估計(jì)(Out-of-bag),方法是計(jì)算那些不在自助采樣之內(nèi)的樣本(比如袋外數(shù)據(jù))偏差的改進(jìn)。這些改進(jìn)存儲在屬性oob_improvement_中。如果將第階段添加到當(dāng)前的預(yù)測中,則 oob_improvement_[i]保存了在OOB樣本損失方面的改進(jìn)。袋外估計(jì)可以使用在模型選擇中,例如決定最優(yōu)迭代次數(shù)。 OOB 估計(jì)通常都很悲觀,因此我們推薦使用交叉驗(yàn)證來代替它,而當(dāng)交叉驗(yàn)證太耗時(shí)時(shí)我們就只能使用 OOB 了。

例子
梯度提升正則
梯度提升袋外估計(jì)
隨機(jī)森林的OOB

1.11.4.9 特征重要性的解釋

通過簡單的可視化樹結(jié)構(gòu),可以很容易地解釋單個(gè)決策樹。然而,梯度提升模型包含了數(shù)百棵回歸樹,因此它們很難通過對單個(gè)樹的可視化來進(jìn)行解釋。幸運(yùn)的是,已經(jīng)提出了一些技術(shù)來總結(jié)和解釋梯度提升模型。

通常,特性對預(yù)測目標(biāo)響應(yīng)的貢獻(xiàn)并不相同;在許多情況下,大多數(shù)特征實(shí)際上是無關(guān)的。在解釋模型時(shí),第一個(gè)問題通常是:重要的特征是什么,并且它們在預(yù)測目標(biāo)響應(yīng)方面有何貢獻(xiàn)?

單個(gè)決策樹本質(zhì)上通過選擇合適的分割點(diǎn)來進(jìn)行特征選擇。這些信息可以用來度量每個(gè)特征的重要性;基本思想是:在樹的分割點(diǎn)中使用某特征越頻繁,該特性就越重要。這種重要性的概念可以通過簡單地平均每個(gè)樹的基于不存度的特征重要性來擴(kuò)展到?jīng)Q策樹集成器上(更多細(xì)節(jié)請參見特征重要性評估Feature importance evaluation)。

一個(gè)擬合的梯度提升模型的特征重要性分?jǐn)?shù)可以通過feature_importances_屬性訪問:

>>> from sklearn.datasets import make_hastie_10_2
>>> from sklearn.ensemble import GradientBoostingClassifier

>>> X, y = make_hastie_10_2(random_state=0)
>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
...     max_depth=1, random_state=0).fit(X, y)
>>> clf.feature_importances_
array([0.10..., 0.10..., 0.11..., ...

請注意,這種特征重要性的計(jì)算是基于熵的,并且它不同于sklearn.inspection.permutation_importance,后者是基于特征的排列。

示例
梯度提升回歸

1.11.5 基于直方圖的梯度提升

Scikit-Leard0.21介紹了兩種新的梯度提升樹的實(shí)驗(yàn)實(shí)現(xiàn),即基于LightGBM(見[LightGBM])的HistGradientBoostingClassifierHistGradientBoostingRegressor。

當(dāng)樣本數(shù)大于數(shù)萬個(gè)樣本時(shí),這些基于直方圖的估計(jì)器可以比 GradientBoostingClassifierGradientBoostingRegressor 快幾個(gè)數(shù)量級。

他們還內(nèi)置了對缺失值的支持,從而避免了計(jì)算機(jī)的需要。

這些快速估計(jì)器首先將輸入樣本X放入整數(shù)值箱(通常為256個(gè)),這極大地減少了要考慮的分裂點(diǎn)數(shù),并允許算法在構(gòu)建樹時(shí)利用基于整數(shù)的數(shù)據(jù)結(jié)構(gòu)(直方圖)而不是依賴排序的連續(xù)值。這些估計(jì)器的API略有不同,對一些損失函數(shù)的 GradientBoostingClassifierGradientBoostingRegressor的實(shí)例將不再支持一些特性。

這些估計(jì)器仍然是實(shí)驗(yàn)性的:它們的預(yù)測和API可能在沒有任何反對周期的情況下發(fā)生變化。要使用它們,您需要顯式地導(dǎo)入enable_hist_gradient_boosting

>>> # explicitly require this experimental feature
>>> from sklearn.experimental import enable_hist_gradient_boosting  # noqa
>>> # now you can import normally from ensemble
>>> from sklearn.ensemble import HistGradientBoostingClassifier
示例
部分依賴圖

1.11.5.1 使用方法

大多數(shù)參數(shù)來自 GradientBoostingClassifierGradientBoostingRegressor。一個(gè)例外是max_iter參數(shù),該參數(shù)取代 n_estimators,并控制提升過程的迭代次數(shù):

>>> from sklearn.experimental import enable_hist_gradient_boosting
>>> from sklearn.ensemble import HistGradientBoostingClassifier
>>> from sklearn.datasets import make_hastie_10_2

>>> X, y = make_hastie_10_2(random_state=0)
>>> X_train, X_test = X[:2000], X[2000:]
>>> y_train, y_test = y[:2000], y[2000:]

>>> clf = HistGradientBoostingClassifier(max_iter=100).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.8965

可用的回歸損失有‘least_squares’, ‘least_absolute_deviation’(對異常值不太敏感)和 ‘poisson’(非常適合模型計(jì)數(shù)和頻率)。在分類方面,‘binary_crossentropy’ 用于二分類, ‘categorical_crossentropy’用于多分類。默認(rèn)情況下,損失函數(shù)是 ‘a(chǎn)uto’,并將更具傳入的y選擇合適的損失函數(shù)進(jìn)行fit

樹的大小可以通過 max_leaf_nodes, max_depth, 和 min_samples_leaf 參數(shù)來控制。

用于存儲數(shù)據(jù)的回收箱數(shù)量由max_bins參數(shù)控制。使用較少的垃圾箱作為一種形式的正規(guī)化。通常建議使用盡可能多的回收箱,這是默認(rèn)的。

用于裝數(shù)據(jù)的箱子數(shù)量由max_bins參數(shù)控制。使用較少的箱子可以作為一種正則化的形式。通常建議使用盡可能多的箱子,這是默認(rèn)的。

l2_regularization參數(shù)是損失函數(shù)上的正則化參數(shù),對應(yīng)于[XGBoost]方程(2)中的。

注意,如果樣本數(shù)大于10,000,則默認(rèn)啟用早期停止。早期停止行為通過 early-stopping, scoring, validation_fraction, n_iter_no_change, and tol參數(shù)來控制.使用一個(gè)隨意的scorer,或僅僅是訓(xùn)練或驗(yàn)證的損失是有可能早期停止的。注意,由于技術(shù)原因,使用 scorer比使用損失要慢得多。默認(rèn)情況下,如果訓(xùn)練集中至少有10,000個(gè)樣本,則使用驗(yàn)證損失執(zhí)行早期停止。

1.11.5.2 缺失值支持

HistGradientBoostingClassifierHistGradientBoostingRegressor內(nèi)建了缺失值支持。

在訓(xùn)練過程中,生長的樹根據(jù)潛在的增益,在每次分割時(shí)無論樣本是否含有缺失值都應(yīng)該被劃分到右邊或者左邊。因此,因此, 在預(yù)測時(shí),有缺失值的樣本也會被分配給左或右的子節(jié)點(diǎn):

>>> from sklearn.experimental import enable_hist_gradient_boosting  # noqa
>>> from sklearn.ensemble import HistGradientBoostingClassifier
>>> import numpy as np

>>> X = np.array([0, 1, 2, np.nan]).reshape(-1, 1)
>>> y = [0, 0, 1, 1]

>>> gbdt = HistGradientBoostingClassifier(min_samples_leaf=1).fit(X, y)
>>> gbdt.predict(X)
array([0, 0, 1, 1])

當(dāng)缺失模式具有預(yù)測性時(shí),可以根據(jù)特征值是否缺失進(jìn)行分割:

>>> X = np.array([0, np.nan, 1, 2, np.nan]).reshape(-1, 1)
>>> y = [0, 1, 0, 0, 1]
>>> gbdt = HistGradientBoostingClassifier(min_samples_leaf=1,
...                                       max_depth=2,
...                                       learning_rate=1,
...                                       max_iter=1).fit(X, y)
>>> gbdt.predict(X)
array([0, 1, 0, 0, 1])

如果在訓(xùn)練期間給定特征下沒有碰見缺失值,則會將有缺少值的樣本映射到具有最多樣本的那個(gè)子節(jié)點(diǎn)上。

1.11.5.3 樣本加權(quán)支持

HistGradientBoostingClassifierHistGradientBoostingRegressorfit的時(shí)候可以對樣本進(jìn)行加權(quán)。

下面的小示例演示了模型如何忽略樣本權(quán)重為零的樣本:

>>> X = [[1, 0],
...      [1, 0],
...      [1, 0],
...      [0, 1]]
>>> y = [0, 0, 1, 0]
>>> # ignore the first 2 training samples by setting their weight to 0
>>> sample_weight = [0, 0, 1, 1]
>>> gb = HistGradientBoostingClassifier(min_samples_leaf=1)
>>> gb.fit(X, y, sample_weight=sample_weight)
HistGradientBoostingClassifier(...)
>>> gb.predict([[1, 0]])
array([1])
>>> gb.predict_proba([[1, 0]])[0, 1]
0.99...

正如您所看到的,[1, 0]被輕松地歸為1,因?yàn)榍皟蓚€(gè)樣本由于其樣本權(quán)重而被忽略。

實(shí)現(xiàn)細(xì)節(jié):考慮樣本權(quán)重等于將梯度(和Hessians)乘以樣本權(quán)重。注意,二進(jìn)制階段(特別是分位數(shù)計(jì)算)沒有考慮權(quán)重。

1.11.5.4 單調(diào)約束

根據(jù)手頭的問題,您可能事先了解到,給定的特征通常會對目標(biāo)值產(chǎn)生積極(或負(fù)面)影響。例如,在其他條件相同的情況下,較高的信用評分應(yīng)該會增加獲得貸款批準(zhǔn)的可能性。單調(diào)約束允許您將這些先驗(yàn)知識集成到模型中。

正單調(diào)約束是形式的約束:

, 其中是具有兩個(gè)特征的預(yù)測器。

同樣,負(fù)單調(diào)約束的形式如下:

請注意,單調(diào)約束只約束輸出“所有其他條件相同”。事實(shí)上,下列關(guān)系并不是通過積極的約束而得到加強(qiáng)的:

您可以使用 monotonic_cst參數(shù)為每個(gè)特征指定一個(gè)單調(diào)約束。對于每個(gè)特征,值0表示沒有約束,而-1和1分別表示負(fù)約束和正約束:

>>> from sklearn.experimental import enable_hist_gradient_boosting  # noqa
>>> from sklearn.ensemble import HistGradientBoostingRegressor

... # positive, negative, and no constraint on the 3 features
>>> gbdt = HistGradientBoostingRegressor(monotonic_cst=[1, -1, 0])

在二分類中,施加單調(diào)約束意味著特征對屬于正類的概率有正/負(fù)的影響。對于多類分類,不支持單調(diào)約束。

示例
單調(diào)約束

1.11.5.5 低級并行

HistGradientBoostingClassifier and HistGradientBoostingRegressor通過Cython使用使用OpenMP并行化。有關(guān)如何控制線程數(shù)量的詳細(xì)信息,請參閱我們的 Parallelism說明。

以下部分并行化:

  • 將樣本從真實(shí)值映射到整數(shù)值箱(然而,找到bin閾值是連續(xù)的)
  • 構(gòu)建直方圖在特征上并行化
  • 在節(jié)點(diǎn)上找到最佳分割點(diǎn)的方法是在特征上并行化
  • 在fit期間,將樣本映射到左、右兩個(gè)子節(jié)點(diǎn),并在樣本上并行化
  • 梯度和Hessians計(jì)算在樣本上并行化
  • 預(yù)測在樣本上并行化

1.11.5.6 為什么它更快

梯度提升過程的瓶頸是決策樹的建立。構(gòu)建一個(gè)傳統(tǒng)的決策樹(如在其他GBDTs、GradientBoostingClassifierGradientBoostingRegressor中)需要在每個(gè)節(jié)點(diǎn)(針對每個(gè)特征)對樣本進(jìn)行排序。排序是必要的,以便能夠有效地計(jì)算一個(gè)分裂點(diǎn)的潛在增益。因此,分割單個(gè)節(jié)點(diǎn)的復(fù)雜度為,其中是節(jié)點(diǎn)上的樣本數(shù)。

相反,HistGradientBoostingClassifierHistGradientBoostingRegressor不需要對特征值進(jìn)行排序,而是使用名為histogram的數(shù)據(jù)結(jié)構(gòu),其中樣本是隱式排序的。構(gòu)造histogram的復(fù)雜度為,因此節(jié)點(diǎn)分裂過程的復(fù)雜度為,遠(yuǎn)遠(yuǎn)小于以前的算法。另外,我們不考慮個(gè)分裂點(diǎn),而是只考慮max_bins分裂點(diǎn),它要小得多。

為了建立histograms,輸入數(shù)據(jù)X需要被綁定到整數(shù)值的箱子中。這個(gè)裝箱過程確實(shí)需要對特征值進(jìn)行排序,但它只在提升過程開始時(shí)發(fā)生一次(而不是在每個(gè)節(jié)點(diǎn),不像GradientBoostingClassifierGradientBoostingRegressor

最后,HistGradientBoostingClassifierHistGradientBoostingRegressor的實(shí)現(xiàn)了許多并行化。

參考

[F1999] Friedmann, Jerome H., 2007, “Stochastic Gradient Boosting”

[R2007] G. Ridgeway, “Generalized Boosted Models: A guide to the gbm package”, 2007

[XGBoost] Tianqi Chen, Carlos Guestrin, “XGBoost: A Scalable Tree Boosting System”

LightGBM(1,2) Ke et. al. “LightGBM: A Highly Efficient Gradient BoostingDecision Tree”

1.11.6 投票分類器

VotingClassifier (投票分類器)的原理是結(jié)合了多個(gè)不同的機(jī)器學(xué)習(xí)分類器,并且采用多數(shù)表決(majority vote)(硬投票) 或者平均預(yù)測概率(軟投票)的方式來預(yù)測分類標(biāo)簽。 這樣的分類器可以用于一組同樣表現(xiàn)良好的模型,以便平衡它們各自的弱點(diǎn)。

1.11.6.1 多數(shù)類標(biāo)簽(多數(shù)/硬投票)

在多數(shù)投票中,對于每個(gè)特定樣本的預(yù)測類別標(biāo)簽是所有單獨(dú)分類器預(yù)測的類別標(biāo)簽中票數(shù)占據(jù)多數(shù)(模式)的類別標(biāo)簽。

例如,如果給定樣本的預(yù)測是

  • classifier 1 -> class 1
  • classifier 2 -> class 1
  • classifier 3 -> class 2

VotingClassifier( voting='hard')將根據(jù)多數(shù)類標(biāo)簽將示例分類為 “class 1”。

在平局的情況下, VotingClassifier將根據(jù)升序排序順序選擇類。例如,在下面的場景中

  • classifier 1 -> class 2
  • classifier 2 -> class 1

這種情況下, class 1 將會被指定為該樣本的類標(biāo)簽。

1.11.6.2 使用方法

下面的示例演示如何擬合多數(shù)規(guī)則分類器:

>>> from sklearn import datasets
>>> from sklearn.model_selection import cross_val_score
>>> from sklearn.linear_model import LogisticRegression
>>> from sklearn.naive_bayes import GaussianNB
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.ensemble import VotingClassifier

>>> iris = datasets.load_iris()
>>> X, y = iris.data[:, 1:3], iris.target

>>> clf1 = LogisticRegression(random_state=1)
>>> clf2 = RandomForestClassifier(n_estimators=50, random_state=1)
>>> clf3 = GaussianNB()

>>> eclf = VotingClassifier(
...     estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
...     voting='hard')

>>> for clf, label in zip([clf1, clf2, clf3, eclf], ['Logistic Regression', 'Random Forest', 'naive Bayes', 'Ensemble']):
...     scores = cross_val_score(clf, X, y, scoring='accuracy', cv=5)
...     print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
Accuracy: 0.95 (+/- 0.04) [Logistic Regression]
Accuracy: 0.94 (+/- 0.04) [Random Forest]
Accuracy: 0.91 (+/- 0.04) [naive Bayes]
Accuracy: 0.95 (+/- 0.04) [Ensemble]

1.11.6.3 加權(quán)平均概率(軟投票)

與多數(shù)投票(硬投票)相比,軟投票將類別標(biāo)簽返回為預(yù)測概率之和的 argmax 。

通過weights參數(shù),可以為每個(gè)分類器分配特定的權(quán)重。當(dāng)提供權(quán)值時(shí),收集每個(gè)分類器的預(yù)測類概率,乘以分類器權(quán)重,然后進(jìn)行平均。然后將具有最高平均概率的類別標(biāo)簽確定為最終類別標(biāo)簽。

為了用一個(gè)簡單的例子來說明這一點(diǎn),讓我們假設(shè)我們有3個(gè)分類器和一個(gè)3類分類問題,其中我們?yōu)樗蟹诸惼鞣峙湎嗟鹊臋?quán)重:w1=1, w2=1, w3=1。

然后計(jì)算樣本的加權(quán)平均概率如下:


這里,預(yù)測的類標(biāo)簽是2,因?yàn)樗哂凶罡叩钠骄怕省?/p>

下面的示例說明了在基于線性支持向量機(jī)、決策樹和K-最近鄰分類器的基礎(chǔ)上使用軟 VotingClassifier 時(shí),決策區(qū)域可能如何變化:

>>> from sklearn import datasets
>>> from sklearn.tree import DecisionTreeClassifier
>>> from sklearn.neighbors import KNeighborsClassifier
>>> from sklearn.svm import SVC
>>> from itertools import product
>>> from sklearn.ensemble import VotingClassifier

>>> # Loading some example data
>>> iris = datasets.load_iris()
>>> X = iris.data[:, [0, 2]]
>>> y = iris.target

>>> # Training classifiers
>>> clf1 = DecisionTreeClassifier(max_depth=4)
>>> clf2 = KNeighborsClassifier(n_neighbors=7)
>>> clf3 = SVC(kernel='rbf', probability=True)
>>> eclf = VotingClassifier(estimators=[('dt', clf1), ('knn', clf2), ('svc', clf3)],
...                         voting='soft', weights=[2, 1, 2])

>>> clf1 = clf1.fit(X, y)
>>> clf2 = clf2.fit(X, y)
>>> clf3 = clf3.fit(X, y)
>>> eclf = eclf.fit(X, y)


1.11.6.4 投票分類器(VotingClassifier)在網(wǎng)格搜索(GridSearchCV)的應(yīng)用

VotingClassifier還可以與 GridSearchCV一起使用,以調(diào)整單個(gè)估計(jì)器的超參數(shù):

>>> from sklearn.model_selection import GridSearchCV
>>> clf1 = LogisticRegression(random_state=1)
>>> clf2 = RandomForestClassifier(random_state=1)
>>> clf3 = GaussianNB()
>>> eclf = VotingClassifier(
...     estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
...     voting='soft'
... )

>>> params = {'lr__C': [1.0, 100.0], 'rf__n_estimators': [20, 200]}

>>> grid = GridSearchCV(estimator=eclf, param_grid=params, cv=5)
>>> grid = grid.fit(iris.data, iris.target)

1.11.6.5 使用方法

為了通過預(yù)測的類別概率來預(yù)測類別標(biāo)簽(投票分類器中的 scikit-learn estimators 必須支持 predict_proba方法):

>>> eclf = VotingClassifier(
...     estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
...     voting='soft'
... )

可選地,可以為各個(gè)分類器提供權(quán)重:

>>> eclf = VotingClassifier(
...     estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)],
...     voting='soft', weights=[2,5,1]
... )

1.11.7 投票回歸器

VotingRegressor的思想是將上不同的機(jī)器學(xué)習(xí)回歸器組合起來,并返回平均預(yù)測值。這樣的回歸器對于一組同樣表現(xiàn)良好的模型是有用的,以平衡它們各自的弱點(diǎn)。

1.11.7.1 使用方法

下面的示例演示如何擬合VotingRegressor:

>>> from sklearn.datasets import load_boston
>>> from sklearn.ensemble import GradientBoostingRegressor
>>> from sklearn.ensemble import RandomForestRegressor
>>> from sklearn.linear_model import LinearRegression
>>> from sklearn.ensemble import VotingRegressor

>>> # Loading some example data
>>> X, y = load_boston(return_X_y=True)

>>> # Training classifiers
>>> reg1 = GradientBoostingRegressor(random_state=1, n_estimators=10)
>>> reg2 = RandomForestRegressor(random_state=1, n_estimators=10)
>>> reg3 = LinearRegression()
>>> ereg = VotingRegressor(estimators=[('gb', reg1), ('rf', reg2), ('lr', reg3)])
>>> ereg = ereg.fit(X, y)

示例
繪制單獨(dú)與投票回歸預(yù)測

1.11.8 疊加泛化

疊加泛化是一種組合估計(jì)器減少偏差的方法 [W1992] [HTF]。更準(zhǔn)確地說,每一個(gè)估計(jì)器的預(yù)測被堆疊在一起,并作為最終估計(jì)器的輸入來計(jì)算預(yù)測。這個(gè)最終的估計(jì)器是通過交叉驗(yàn)證來訓(xùn)練的。

StackingClassifier and StackingRegressor 提供了適用于分類和回歸問題的策略。

estimators對應(yīng)于在估計(jì)器的列表, 它們在輸入數(shù)據(jù)上并行地堆疊在一起。它應(yīng)該是給出名字和估計(jì)器的列表:

>>> from sklearn.linear_model import RidgeCV, LassoCV
>>> from sklearn.svm import SVR
>>> estimators = [('ridge', RidgeCV()),
...               ('lasso', LassoCV(random_state=42)),
...               ('svr', SVR(C=1, gamma=1e-6))]

final_estimator將使用 estimators的預(yù)測作為輸入。當(dāng)使用StackingClassifier 或者StackingRegressor, 時(shí),它需要是一個(gè)分類器或回歸器:

>>> from sklearn.ensemble import GradientBoostingRegressor
>>> from sklearn.ensemble import StackingRegressor
>>> reg = StackingRegressor(
...     estimators=estimators,
...     final_estimator=GradientBoostingRegressor(random_state=42))

為了訓(xùn)練estimatorsfinal_estimator,需要對訓(xùn)練數(shù)據(jù)調(diào)用fit方法:

>>> from sklearn.datasets import load_boston
>>> X, y = load_boston(return_X_y=True)
>>> from sklearn.model_selection import train_test_split
>>> X_train, X_test, y_train, y_test = train_test_split(X, y,
...                                                     random_state=42)
>>> reg.fit(X_train, y_train)
StackingRegressor(...)

在訓(xùn)練過程中,estimators對整個(gè)訓(xùn)練數(shù)據(jù)X_train進(jìn)行擬合。它們將在調(diào)用 predict或“預(yù)測 predict_proba時(shí)被調(diào)用。為了推廣和避免過擬合,final_estimator在out-samples上被訓(xùn)練, 內(nèi)部使用 sklearn.model_selection.cross_val_predict。

對于 StackingClassifier,請注意, estimators的輸出由參數(shù)stack_method控制,并由每個(gè)估計(jì)器調(diào)用。該參數(shù)要么是字符串,即估計(jì)器方法名稱,要么是'auto',它將根據(jù)可用性自動識別可用的方法,并按偏好順序進(jìn)行測試:predict_proba, decision_function and predict

StackingRegressor and StackingClassifier可以用作任何其他的回歸者或分類器,通用方法predict, predict_proba, 和 decision_function ,例如:

>>> y_pred = reg.predict(X_test)
>>> from sklearn.metrics import r2_score
>>> print('R2 score: {:.2f}'.format(r2_score(y_test, y_pred)))
R2 score: 0.81

請注意,還可以使用 transform方法獲得堆疊 estimators的輸出:

>>> reg.transform(X_test[:5])
array([[28.78..., 28.43...  , 22.62...],
       [35.96..., 32.58..., 23.68...],
       [14.97..., 14.05..., 16.45...],
       [25.19..., 25.54..., 22.92...],
       [18.93..., 19.26..., 17.03... ]])

在實(shí)際應(yīng)用中,堆疊預(yù)測器預(yù)測的效果與基本層的最佳預(yù)測器一樣好,有時(shí)甚至通過將這些預(yù)測器的不同強(qiáng)度組合在一起而優(yōu)于這些預(yù)測器。然而,訓(xùn)練堆疊預(yù)測器在計(jì)算上是昂貴的。

注意: StackingClassifier,當(dāng)使用 stack_method_='predict_proba'時(shí),當(dāng)問題是二分類問題時(shí),將刪除第一列。實(shí)際上,每個(gè)估計(jì)器預(yù)測的兩個(gè)概率列都是完全共線的。

注意:可以通過向StackingClassifier 或者 StackingRegressor分配final_estimator來實(shí)現(xiàn)多個(gè)堆疊層:

>>> final_layer = StackingRegressor(
...     estimators=[('rf', RandomForestRegressor(random_state=42)),
...                 ('gbrt', GradientBoostingRegressor(random_state=42))],
...     final_estimator=RidgeCV()
...     )
>>> multi_layer_regressor = StackingRegressor(
...     estimators=[('ridge', RidgeCV()),
...                 ('lasso', LassoCV(random_state=42)),
...                 ('svr', SVR(C=1, gamma=1e-6, kernel='rbf'))],
...     final_estimator=final_layer
... )
>>> multi_layer_regressor.fit(X_train, y_train)
StackingRegressor(...)
>>> print('R2 score: {:.2f}'
...       .format(multi_layer_regressor.score(X_test, y_test)))
R2 score: 0.83

參考:

[W1992] Wolpert, David H. “Stacked generalization.” Neural networks 5.2 (1992): 241-259.


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號