1. 程式人生 > >整合學習總結 & Stacking方法詳解

整合學習總結 & Stacking方法詳解

整合學習主要分為 bagging, boosting 和 stacking方法。本文主要是介紹stacking方法及其應用。但是在總結之前還是先回顧一下繼承學習。

這部分主要轉自知乎

1. Bagging方法:

給定一個大小為n的訓練集 D,Bagging演算法從中均勻、有放回地選出 m個大小為 n' 的子集Di,作為新的訓練集。在這 m個訓練集上使用分類、迴歸等演算法,則可得到 m個模型,再通過取平均值、取多數票等方法綜合產生預測結果,即可得到Bagging的結果。

(轉自知乎)

2. Boosting 方法

加入的過程中,通常根據它們的上一輪的分類準確率給予不同的權重。加和弱學習者之後,資料通常會被重新加權,來強化對之前分類錯誤資料點的分類,其中一個經典的提升演算法例子是AdaBoost。

(來自知乎)

3. Stacking 方法:

將訓練好的所有基模型對整個訓練集進行預測,第j個基模型對第i個訓練樣本的預測值將作為新的訓練集中第i個樣本的第j個特徵值,最後基於新的訓練集進行訓練。同理,預測的過程也要先經過所有基模型的預測形成新的測試集,最後再對測試集進行預測:

下面我們介紹一款功能強大的stacking利器,mlxtend庫,它可以很快地完成對sklearn模型地stacking。

主要有以下幾種使用方法吧:

I. 最基本的使用方法,即使用前面分類器產生的特徵輸出作為最後總的meta-classifier的輸入資料

from sklearn import datasets

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

from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB 
from sklearn.ensemble import RandomForestClassifier
from mlxtend.classifier import StackingClassifier
import numpy as np

clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3], 
                          meta_classifier=lr)

print('3-fold cross validation:\n')

for clf, label in zip([clf1, clf2, clf3, sclf], 
                      ['KNN', 
                       'Random Forest', 
                       'Naive Bayes',
                       'StackingClassifier']):

    scores = model_selection.cross_val_score(clf, X, y, 
                                              cv=3, scoring='accuracy')
    print("Accuracy: %0.2f (+/- %0.2f) [%s]" 
          % (scores.mean(), scores.std(), label))


II. 另一種使用第一層基本分類器產生的類別概率值作為meta-classfier的輸入,這種情況下需要將StackingClassifier的引數設定為 use_probas=True。如果將引數設定為 average_probas=True,那麼這些基分類器對每一個類別產生的概率值會被平均,否則會拼接。

   例如有兩個基分類器產生的概率輸出為:

classifier 1: [0.2, 0.5, 0.3]

classifier 2: [0.3, 0.4, 0.4]

   1) average = True : 

產生的meta-feature 為:[0.25, 0.45, 0.35]

   2) average = False:

產生的meta-feature為:[0.2, 0.5, 0.3, 0.3, 0.4, 0.4]

from sklearn import datasets

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

from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB 
from sklearn.ensemble import RandomForestClassifier
from mlxtend.classifier import StackingClassifier
import numpy as np

clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],
                          use_probas=True,
                          average_probas=False,
                          meta_classifier=lr)

print('3-fold cross validation:\n')

for clf, label in zip([clf1, clf2, clf3, sclf], 
                      ['KNN', 
                       'Random Forest', 
                       'Naive Bayes',
                       'StackingClassifier']):

    scores = model_selection.cross_val_score(clf, X, y, 
                                              cv=3, scoring='accuracy')
    print("Accuracy: %0.2f (+/- %0.2f) [%s]" 
          % (scores.mean(), scores.std(), label))


III. 另外一種方法是對訓練基中的特徵維度進行操作的,這次不是給每一個基分類器全部的特徵,而是給不同的基分類器分不同的特徵,即比如基分類器1訓練前半部分特徵,基分類器2訓練後半部分特徵(可以通過sklearn 的pipelines 實現)。最終通過StackingClassifier組合起來。

from sklearn.datasets import load_iris
from mlxtend.classifier import StackingClassifier
from mlxtend.feature_selection import ColumnSelector
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression

iris = load_iris()
X = iris.data
y = iris.target

pipe1 = make_pipeline(ColumnSelector(cols=(0, 2)),
                      LogisticRegression())
pipe2 = make_pipeline(ColumnSelector(cols=(1, 2, 3)),
                      LogisticRegression())

sclf = StackingClassifier(classifiers=[pipe1, pipe2], 
                          meta_classifier=LogisticRegression())

sclf.fit(X, y)

StackingClassifier 使用API及引數解析:

StackingClassifier(classifiers, meta_classifier, use_probas=False, average_probas=False, verbose=0, use_features_in_secondary=False)

引數:

classifiers : 基分類器,陣列形式,[cl1, cl2, cl3]. 每個基分類器的屬性被儲存在類屬性 self.clfs_.
meta_classifier : 目標分類器,即將前面分類器合起來的分類器
use_probas : bool (default: False) ,如果設定為True, 那麼目標分類器的輸入就是前面分類輸出的類別概率值而不是類別標籤
average_probas : bool (default: False),用來設定上一個引數當使用概率值輸出的時候是否使用平均值。
verbose : int, optional (default=0)。用來控制使用過程中的日誌輸出,當 verbose = 0時,什麼也不輸出, verbose = 1,輸出迴歸器的序號和名字。verbose = 2,輸出詳細的引數資訊。verbose > 2, 自動將verbose設定為小於2的,verbose -2.
use_features_in_secondary : bool (default: False). 如果設定為True,那麼最終的目標分類器就被基分類器產生的資料和最初的資料集同時訓練。如果設定為False,最終的分類器只會使用基分類器產生的資料訓練。

屬性:
clfs_ : 每個基分類器的屬性,list, shape 為 [n_classifiers]。
meta_clf_ : 最終目標分類器的屬性

方法:

fit(X, y)
fit_transform(X, y=None, fit_params)
get_params(deep=True),如果是使用sklearn的GridSearch方法,那麼返回分類器的各項引數。
predict(X)
predict_proba(X)
score(X, y, sample_weight=None), 對於給定資料集和給定label,返回評價accuracy
set_params(params),設定分類器的引數,params的設定方法和sklearn的格式一樣

------------------------------------------EOF---------------------------------

參考文獻:

https://zhihu.com/question/29036379/answer/111637662

https://rasbt.github.io/mlxtend/user_guide/classifier/StackingClassifier/

https://zh.wikipedia.org/zh-hans/Bagging%E7%AE%97%E6%B3%95

Wolpert, David H. "Stacked generalization." Neural networks 5.2 (1992): 241-259.