集成學(xué)習(xí)系列(七)-Stacking原理及Python實(shí)現(xiàn)

之前參加了一個(gè)螞蟻金服的數(shù)據(jù)挖掘比賽,最后初賽拿到了37名,全是靠的stacking呀,不過懶癌晚期患者直到現(xiàn)在才把學(xué)到的東西整理出來(lái),簡(jiǎn)直無(wú)藥可救了。

1、Stacking原理

stacking 就是當(dāng)用初始訓(xùn)練數(shù)據(jù)學(xué)習(xí)出若干個(gè)基學(xué)習(xí)器后,將這幾個(gè)學(xué)習(xí)器的預(yù)測(cè)結(jié)果作為新的訓(xùn)練集,來(lái)學(xué)習(xí)一個(gè)新的學(xué)習(xí)器。

他具體是怎么實(shí)現(xiàn)的呢,我們來(lái)通過代碼了解一下吧,代碼來(lái)源于github
https://github.com/log0/vertebral/blob/master/stacked_generalization.py

2、Stacking分類應(yīng)用

這里我們用二分類的例子做介紹。
例如我們用 RandomForestClassifier, ExtraTreesClassifier, GradientBoostingClassifier 作為第一層學(xué)習(xí)器(當(dāng)然這里我們可以添加更多的分類器,也可以用不同的特征組合但是同樣的學(xué)習(xí)方法作為基分類器):

clfs = [
        RandomForestClassifier(n_estimators = n_trees, criterion = 'gini'),
        ExtraTreesClassifier(n_estimators = n_trees * 2, criterion = 'gini'),
        GradientBoostingClassifier(n_estimators = n_trees),
    ]

接著要訓(xùn)練第一層學(xué)習(xí)器,并得到第二層學(xué)習(xí)器所需要的數(shù)據(jù),這里會(huì)用到 k 折交叉驗(yàn)證。我們首先會(huì)將數(shù)據(jù)集進(jìn)行一個(gè)劃分,比如使用80%的訓(xùn)練數(shù)據(jù)來(lái)訓(xùn)練,20%的數(shù)據(jù)用來(lái)測(cè)試,

dev_cutoff = len(Y) * 4/5
    X_dev = X[:dev_cutoff]
    Y_dev = Y[:dev_cutoff]
    X_test = X[dev_cutoff:]
    Y_test = Y[dev_cutoff:]

然后對(duì)訓(xùn)練數(shù)據(jù)通過交叉驗(yàn)證訓(xùn)練 clf,并得到第二層的訓(xùn)練數(shù)據(jù) blend_train,同時(shí),在每個(gè)基分類器的每一折交叉驗(yàn)證中,我們都會(huì)對(duì)測(cè)試數(shù)據(jù)進(jìn)行一次預(yù)測(cè),以得到我們blend_test,二者的定義如下:

 blend_train = np.zeros((X_dev.shape[0], len(clfs))) # Number of training data x Number of classifiers
blend_test = np.zeros((X_test.shape[0], len(clfs))) # Number of testing data x Number of classifiers

按照上面說的,blend_train基于下面的方法得到,注意,下圖是對(duì)于一個(gè)分類器來(lái)說的,所以每個(gè)分類器得到的blend_train的行數(shù)與用于訓(xùn)練的數(shù)據(jù)一樣多,所以blend_train的shape為X_dev.shape[0]*len(clfs),即訓(xùn)練集長(zhǎng)度 * 基分類器個(gè)數(shù):

而對(duì)于第二輪的測(cè)試集blend_test來(lái)說,由于每次交叉驗(yàn)證的過程中都要進(jìn)行一次預(yù)測(cè),假設(shè)我們是5折交叉驗(yàn)證,那么對(duì)于每個(gè)分類器來(lái)說,得到的blend_test的shape是測(cè)試集行數(shù) * 交叉驗(yàn)證折數(shù),此時(shí)的做法是,對(duì)axis=1方向取平均值,以得到測(cè)試集行數(shù) * 1 的測(cè)試數(shù)據(jù),所以總的blend_test就是測(cè)試集行數(shù) * 基分類器個(gè)數(shù),可以跟blend_train保持一致:

得到blend_train 和 blend_test的代碼如下:

for j, clf in enumerate(clfs):
        print 'Training classifier [%s]' % (j)
        blend_test_j = np.zeros((X_test.shape[0], len(skf))) # Number of testing data x Number of folds , we will take the mean of the predictions later
        for i, (train_index, cv_index) in enumerate(skf):
            print 'Fold [%s]' % (i)
            
            # This is the training and validation set
            X_train = X_dev[train_index]
            Y_train = Y_dev[train_index]
            X_cv = X_dev[cv_index]
            Y_cv = Y_dev[cv_index]
            
            clf.fit(X_train, Y_train)
            
            # This output will be the basis for our blended classifier to train against,
            # which is also the output of our classifiers
            blend_train[cv_index, j] = clf.predict(X_cv)
            blend_test_j[:, i] = clf.predict(X_test)
        # Take the mean of the predictions of the cross validation set
        blend_test[:, j] = blend_test_j.mean(1)
    

接著我們就可以用 blend_train, Y_dev 去訓(xùn)練第二層的學(xué)習(xí)器 LogisticRegression(當(dāng)然也可以是別的分類器,比如lightGBM,XGBoost):

 bclf = LogisticRegression()
bclf.fit(blend_train, Y_dev)

最后,基于我們訓(xùn)練的二級(jí)分類器,我們可以預(yù)測(cè)測(cè)試集 blend_test,并得到 score:

Y_test_predict = bclf.predict(blend_test)
score = metrics.accuracy_score(Y_test, Y_test_predict)
print 'Accuracy = %s' % (score)

如果是多分類怎么辦呢,我們這里就不能用predict方法啦,我么要用的是predict_proba方法,得到基分類器對(duì)每個(gè)類的預(yù)測(cè)概率代入二級(jí)分類器中訓(xùn)練,修改的部分代碼如下:

blend_train = np.zeros((np.array(X_dev.values.tolist()).shape[0], num_classes*len(clfs)),dtype=np.float32)  # Number of training data x Number of classifiers
blend_test = np.zeros((np.array(X_test.values.tolist()).shape[0], num_classes*len(clfs)),dtype=np.float32)  # Number of testing data x Number of classifiers

    # For each classifier, we train the number of fold times (=len(skf))
    for j, clf in enumerate(clfs):
        for i, (train_index, cv_index) in enumerate(skf):
            print('Fold [%s]' % (i))

            # This is the training and validation set
            X_train = X_dev[train_index]
            Y_train = Y_dev[train_index]
            X_cv = X_dev[cv_index]

            X_train = np.concatenate((X_train, ret_x),axis=0)
            Y_train = np.concatenate((Y_train, ret_y),axis=0)
            clf.fit(X_train, Y_train)
            blend_train[cv_index, j*num_classes:(j+1)*num_classes] = clf.predict_proba(X_cv)
            blend_test[:, j*num_classes:(j+1)*num_classes] += clf.predict_proba(X_test)
blend_test = blend_test / float(n_folds)

上面的代碼修改的主要就是blend_train和blend_test的shape,可以看到,對(duì)于多分類問題來(lái)說,二者的第二維的shape不再是基分類器的數(shù)量,而是class的數(shù)量*基分類器的數(shù)量,這是大家要注意的,否則可能不會(huì)得到我們想要的結(jié)果。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • [TOC] About Trs 只是閱讀過程中對(duì)其中一些進(jìn)行注腳而已,更確切的內(nèi)容還是英文原文來(lái)的清晰,有些翻譯反...
    mrlevo520閱讀 1,318評(píng)論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評(píng)論 19 139
  • 前言: 以斯坦福cs231n課程的python編程任務(wù)為主線,展開對(duì)該課程主要內(nèi)容的理解和部分?jǐn)?shù)學(xué)推導(dǎo)。該課程相關(guān)...
    卑鄙的我_閱讀 3,499評(píng)論 0 2
  • 人生如一葉扁舟,有時(shí)會(huì)遇到風(fēng)浪;人生如一片天空,有時(shí)會(huì)烏云密布;人生如一條路,有時(shí)也會(huì)滿地荊棘。然而,我們須知風(fēng)雨...
    夢(mèng)未來(lái)閱讀 223評(píng)論 0 0
  • 大喊大叫的基督教界的
    就是難上加難閱讀 184評(píng)論 0 0

友情鏈接更多精彩內(nèi)容