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

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

1、Stacking原理

stacking 就是當用初始訓練數(shù)據學習出若干個基學習器后,將這幾個學習器的預測結果作為新的訓練集,來學習一個新的學習器。

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

2、Stacking分類應用

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

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

接著要訓練第一層學習器,并得到第二層學習器所需要的數(shù)據,這里會用到 k 折交叉驗證。我們首先會將數(shù)據集進行一個劃分,比如使用80%的訓練數(shù)據來訓練,20%的數(shù)據用來測試,

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:]

然后對訓練數(shù)據通過交叉驗證訓練 clf,并得到第二層的訓練數(shù)據 blend_train,同時,在每個基分類器的每一折交叉驗證中,我們都會對測試數(shù)據進行一次預測,以得到我們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基于下面的方法得到,注意,下圖是對于一個分類器來說的,所以每個分類器得到的blend_train的行數(shù)與用于訓練的數(shù)據一樣多,所以blend_train的shape為X_dev.shape[0]*len(clfs),即訓練集長度 * 基分類器個數(shù):

而對于第二輪的測試集blend_test來說,由于每次交叉驗證的過程中都要進行一次預測,假設我們是5折交叉驗證,那么對于每個分類器來說,得到的blend_test的shape是測試集行數(shù) * 交叉驗證折數(shù),此時的做法是,對axis=1方向取平均值,以得到測試集行數(shù) * 1 的測試數(shù)據,所以總的blend_test就是測試集行數(shù) * 基分類器個數(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 去訓練第二層的學習器 LogisticRegression(當然也可以是別的分類器,比如lightGBM,XGBoost):

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

最后,基于我們訓練的二級分類器,我們可以預測測試集 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方法,得到基分類器對每個類的預測概率代入二級分類器中訓練,修改的部分代碼如下:

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,可以看到,對于多分類問題來說,二者的第二維的shape不再是基分類器的數(shù)量,而是class的數(shù)量*基分類器的數(shù)量,這是大家要注意的,否則可能不會得到我們想要的結果。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

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