
Stacking在比賽中是很常用的技巧, 但看了很多資料還是很難理解.
后來自己youtube上找到一個PyData的分享, 總算明白了.
我的困惑點(diǎn)是, 我不理解為什么下一個模型要用到上一個模型的預(yù)測. 而第一個模型預(yù)測又不一定正確, 那為啥后面還要用他當(dāng)訓(xùn)練數(shù)據(jù)?
直到我看到PyData的視頻里面有講到一個詞: meta-estimator, 聯(lián)系自己做過的model fusion, 并且大概了解過的meta-learning的基本概念,瞬間茅塞頓開. 其實(shí)本質(zhì)上stacking就是用下一個模型去針對上一個模型預(yù)測的結(jié)果進(jìn)行學(xué)習(xí), 注意這里訓(xùn)練的輸入是上一個模型的預(yù)測結(jié)果, 換句話說, 就是我下一個模型學(xué)習(xí)的目標(biāo)是找到上一個模型預(yù)測結(jié)果和真實(shí)結(jié)果之間的模式, 通過學(xué)習(xí)這種模式可以優(yōu)化最終的結(jié)果.
What is a stacked model?
原話:
Also called model ensembling or blending, model stacking combines the outputs of-
multiple models(called base estimators) by training a higher-
level model(called the meta-estimator) on the output.
Works with classifiers and regressors alike.
簡而言之, 就是一個元學(xué)習(xí)器. 而所謂元學(xué)習(xí)就是指學(xué)習(xí)如何學(xué)習(xí). 換句話說, 本質(zhì)上學(xué)習(xí)器是學(xué)習(xí)我們具體任務(wù)輸入和輸出的關(guān)系, 例如我們要預(yù)測房價變化趨勢Y_hat, 那么輸入(features)可能是一些市場供需關(guān)系變量X, 而元學(xué)習(xí)是學(xué)習(xí)房價變化趨勢Y_hat和真實(shí)的Y之間的關(guān)系.
當(dāng)然stacking也不是唯一的方式, 之前在做圖像識別任務(wù)時就用過Naive Bayesian Fusion Scheme, 效果也能提升,并且理解也很直觀.
他們?yōu)槭裁磜ork?
拿CNN圖像分類來說, 不同結(jié)構(gòu)的模型他們的錯誤不一定重疊(not necessarily overlapped), 所以我們就可以對于各個模型各取所長, 然后把他們的結(jié)果結(jié)合再輸出.
一般流程

每個基模型(例如Base Model 1是XGBoost, Base Model 2是RandomForest, Base Model 3是K-NN...)在train set做Cross Validation, 得到train samples的y_hat

各個模型在test set上做prediction, 得到所有test samples的y_hat.

得到不同基模型的y_hat后, 把他們的train set部分的y_hat作為features, 所有的y作為label, 訓(xùn)練出一個模型. 最終y_hat_final由test set中的y_hat作為模型輸入得到, 這里需要注意的是test set中的y_hat因?yàn)闆]有CV, 所以單個模型的每個CV fold輸出會重疊, 因此這里取所有fold的平均.
為什么要用Cross Validation?
本質(zhì)是為了得到模型的un-leaky的預(yù)測y_hat. 高層的model要訓(xùn)練的是base model的輸出y_hat, 那么如果我不用CV, 那我只能用全部的訓(xùn)練集訓(xùn)練, 再預(yù)測一遍訓(xùn)練集,那么我的結(jié)果一定是過擬合的.
另外一個問題, 每個CV部分要不要refit?
所謂refit就是用缺失的那個fold再放回去訓(xùn)練, 來預(yù)測test set(當(dāng)然在stacking中, 放回去之前一定是已經(jīng)得到了那個fold的y_hat了). refit一般情況會增強(qiáng)模型的泛化能力(因?yàn)樗娺^更多的sample), 但需要考慮到, 因?yàn)榛诓煌?xùn)練數(shù)據(jù), refit之后你得到的模型和之前你預(yù)測fold的模型是不同的, 那么在stacking的步驟里, 得到的training中y_hat,y之間的關(guān)系就和test中的失去聯(lián)系.
最后一個問題, 是不是一定得CV?
答案時否定的. 之前看到京東一個比賽的baseline的操作是把對所有訓(xùn)練數(shù)據(jù)預(yù)測結(jié)果直接當(dāng)做一個下一次(層)stacking的新feature. 這樣很簡單粗暴, 簡單說就是: 循環(huán)得自己吃自己的屎. 直觀的理解: 第一次吃東西不消化, 可能拉出來的東西還有些沒消化的, 所以再吃一遍.
WHEN TO USE
- Juicing a little more accuracy of your model (juicing很形象...擰毛巾既視感)
- 更多模型更加flexibility (靈活, 不同模型對于y有不同的assumption, 可以靈活得把他們組合利用.)
- 表示我真的盡力了... 我都已經(jīng)把所有能用的模型都用了...
什么時候最好別用
- 數(shù)據(jù)太多了
- 需要解釋性. (對于結(jié)果再組合, 影響了模型最終結(jié)果的解釋性)
- 需要知道數(shù)據(jù)的產(chǎn)生過程.
A FEW TIPS
- 基模型之間需要結(jié)構(gòu)差異化 (回憶前文的假設(shè)——不同結(jié)構(gòu)模型之間的犯的錯不一定會重疊)
- 選擇處理相關(guān)屬性的model. (每個基模型都在預(yù)測y, 所以他們的y_hat之間的相關(guān)行會非常高, 所以需要選擇對于輸入相關(guān)性不敏感的明細(xì)做stacking, 例如樹模型)
- 簡單的元學(xué)習(xí)器能提高解釋性. (分類: L2-logistic regression, 回歸: Non-negative LS...)
- 用連續(xù)的輸出作為元學(xué)習(xí)的輸入. (對于分類來說, 基學(xué)習(xí)器輸出概率而不是label, 元學(xué)習(xí)器就會多了很多信息.)
GOOD NEWS
Stacking實(shí)現(xiàn)不難, 不過對于伸手黨來說, 效率第一.
這里介紹一下別人已經(jīng)造好的輪子: civismlext
注意: 該輪子對于基模型需要滿足 sklearn-compatible, 即 有fit和predict方法.
安裝
$ pip install civisml-extensions
例子
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from civismlext.stacking import StackedClassifier
# Note that the final estimator 'metalr' is the meta-estimator
estlist = [('rf', RandomForestClassifier()),
('lr', LogisticRegression()),
('metalr', LogisticRegression())]
mysm = StackedClassifier(estlist)
# Set some parameters, if you didn't set them at instantiation
mysm.set_params(rf__random_state=7, lr__random_state=8,
metalr__random_state=9, metalr__C=10**7)
# Fit
mysm.fit(Xtrain, ytrain)
# Predict!
ypred = mysm.predict_proba(Xtest)
以上.