1. 程式人生 > >Stacking思想的Python3程式碼再現

Stacking思想的Python3程式碼再現

Stacking思想的程式碼再現

本文源於對Stacking思想的理解,嘗試使用Python3.5,在Spyder中將其思想轉化為程式碼實現,並將本文內容安排如下:
1.Stacking原理(巨集觀和微觀解釋)
2.使用本文Stacking程式碼測試Iris資料集

  1. Stacking原理圖
    1.1.網上廣為接受的原理圖:(巨集觀)
    在這裡插入圖片描述
    【巨集觀圖】將訓練集劃分成了X_train和X_test兩個集合。然後將X_train按k折交叉驗證(這裡k=5)來均等劃分,藍色的4折作為小的X_train’,橙色的1折作為小的X_test’,使用model1對X_train進行k=5的交叉驗證,X_train’訓練模型後使用,X_test’來做交叉驗證的測試對模型進行調參。即:外圈迴圈為5個模型,內圈迴圈做5折交叉驗證:5折中隨機選定一折做小訓練街,其餘做測試集合,訓練模型時,分別傳入X_test’和整個X_test進行訓練。如此重複劃分和訓練驗證測試5次。針對每一個模型會有兩個輸出的label(即new feature):5組橙色的Learn和5組綠色的Predict。對於每一個模型預測出來的5組橙色的Learn沿著縱向拼接成一個列向量即;對於每一個模型預測出來的5組綠色的Predict將其取Average記為predict’;5個模型拼接出5組橙色的new feature,每組new feature由橙色的5個Learn縱向拼接成,將5組橙色的new feature沿著橫向拼接起來作為新的new_feature_X_train。5個模型拼接出5組綠色的Predict,沿著橫向進行拼接作為新的new_feature_X_test。
    1.2.原理圖剖析(微觀)
    為了方便讀著理解如下將每個模型的內圈迴圈操作進行放大,方便理解,後續簡稱【區域性圖】。實質上就是一個k=5的k折交叉驗證。 最後將每一次訓練驗證的label沿著列的方向重新拼接起來作為一整列的新特徵。同步的由於每一輪交叉驗證中X_test都會傳入模型做預測產生了5組綠色的label列,這裡對5組label列取平均記為predict’。
    在這裡插入圖片描述

    1.3.使用新的模型來訓練訓練集new_feature_X_train,傳入標籤為y_train,再將new_feature_X_test作為驗證集,將驗證的結果predict1與y_test做對比計算得分即可。定義第6個模型clf6來訓練new_feature_X_train,並預測new_feature_X_test。詳情如下圖所示:
    在這裡插入圖片描述
    2.iris資料集上做驗證測試
    2.1.iris.data.shape=() #(150, 4)
    即:iris.data中有150個樣本,每個樣本由一個4維屬性構成的array陣列來表示。現在現將iris.data劃分資料集,均等換分為5份,即:X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.2,random_state=10),由此獲得X_train.shape=(120,4),X_test.shape=(30,4);y_train.shape=(120,1),y_test.shape=(30,1)。按照區域性圖中的原理將X_train做k=5折交叉驗證:將X_train,y_train都劃分為5等份,每份120/5=24,隨機選出一折作為小測試集X_test’(X_test’.shape=(24,4)),其餘4折作為小訓練集X_train’(X_train’.shape=(96,4))來訓練模型,從y_train的5份劃分中隨機選一份作為訓練標籤y_train’(y_train’.shape=(24,4))。每一輪驗證中clf.fit(X_train’,y_train’),
    new_predict1=clf.predict(X_test’);#驗證集是交叉訓練的測試集
    new_predict2=clf.predict(X_test); #驗證集是原來的X_test的測試集
    將每一輪的結果存入相應的list中以備拼接或者取平均用即可。
    2.1.詳細程式碼

"""Stacking 思想的實現"""
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cross_validation import cross_val_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble.gradient_boosting import GradientBoostingClassifier
from sklearn.naive_bayes import GaussianNB 
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
import warnings
from numpy import hstack,vstack,array,nan
warnings.filterwarnings('ignore')
from sklearn import datasets
iris=datasets.load_iris()
X=iris.data #訓練特徵
Y=iris.target #測試特診
#4:1是為了方便做交叉驗證
X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.2,random_state=10)
#歸一化處理
ss=StandardScaler()
X_train=ss.fit_transform(X_train)
X_test=ss.transform(X_test)
#clf1=LogisticRegression()
#clf1.fit(X_train,y_train)
#y_predict=clf1.predict(X_test)

"""1.1.獲得新特徵"""
new_feature=[] #裝每個模型產生的新特徵列
new_label_test=[]
#模型模組
clf1=LogisticRegression()
#clf1.fit(XXXtrain,YYYtrain)
#y_predict=clf1.predict(XXXtest)
clf2=KNeighborsClassifier()
clf3=GaussianNB()
clf4=RandomForestClassifier()
#將訓練集劃分成5份
set_Train=[]
set_Test=[]
#將X_train和y_train拆成5折以備後續做5折交叉驗證使用
for k in range(5):
    span=int(X_train.shape[0]/5)
    i=k*span
    j=(k+1)*span
    #將X_train和y_train均劃分成為5分被後續交叉驗證使用
    set_Train.append(X_train[i:j])
    set_Test.append(y_train[i:j])

model=[clf1,clf2,clf3,clf4]
#clf1.__class__.__bases__ #基本函式族
for index,clf in enumerate(model):
    #print(index,'======',clf)
    model_list=[] #將每一輪交叉驗證的預測label存入其中,再轉為array做轉置.
    label_list=[] #總的測試集對應的預測標籤
    #k折交叉驗證
    for k in range(5):
        ##選擇做交叉驗證的測試集
        XXtest=[]
        XXtest.append(set_Train[k])
        #選擇做交叉驗證訓練的訓練集
        XXtrain=[]
        YYtest=[]
        for kk in range(5):
            if kk==k:
                continue
            else:
                XXtrain.append(set_Train[kk])
                YYtest.append(set_Test[kk])
        #模型的訓練
        XXXtrain=array(vstack((XXtrain[0],XXtrain[1],XXtrain[2],XXtrain[3]))) 
        YYYtrain=array(hstack((YYtest[0],YYtest[1],YYtest[2],YYtest[3])))
        XXXtest=array(vstack(XXtest)) #XXtest.shape=1*24*4,不是想要的96x4
        clf.fit(XXXtrain,YYYtrain)
        y_predict=clf.predict(XXXtest)
        model_list.append(y_predict) #將第k折驗證中第k折為測試集的預測標籤儲存起來
        test_y_pred=clf.predict(X_test)
        label_list.append(test_y_pred)
        #拼接資料集時候是hstack還是vstack可以試試看
    new_k_feature=array(hstack((model_list[0],model_list[1],model_list[2],model_list[3],model_list[4]))) #hstack() takes 1 positional argument,所以引數使用一個tuple來封裝
    new_feature.append(new_k_feature)
    new_k_test=array(vstack((label_list[0],label_list[1],label_list[2],label_list[3],label_list[4]))).T #hstack() takes 1 positional argument,所以引數使用一個tuple來封裝
    new_label_test.append(array(list(map(int,list(map(round,new_k_test.mean(axis=1)))))))

#將5個基模型訓練好的預分類標籤組合成為新的特徵供後續使用(X_train')
newfeature_from_train=array(vstack((new_feature[0],new_feature[1],new_feature[2],new_feature[3]))).T #拼接完成後做轉置

#將交叉驗證獲得的label拼接起來(X_test')
predict_from_test_average=array(vstack((new_label_test[0],new_label_test[1],new_label_test[2],new_label_test[3]))).T

"""1.3.meta_classifier 模型"""
clf5=GradientBoostingClassifier()
clf5.fit(newfeature_from_train,y_train)
predict1=clf5.predict(predict_from_test_average)
predict1

Score=accuracy_score(y_test,predict1)
Score 

#result1: predict1
predict1
Out[152]: 
array([1, 2, 0, 1, 0, 1, 2, 1, 0, 1, 1, 2, 1, 0, 0, 2, 1, 0, 0, 0, 2, 2,
       2, 0, 1, 0, 1, 1, 1, 2])
#result2: Score
Score=accuracy_score(y_test,predict1)
Score
Out[153]: 0.9666666666666667

雷鋒網:https://www.leiphone.com/news/201709/zYIOJqMzR0mJARzj.html
劉建平部落格(非常多sklearn的好文章):https://www.cnblogs.com/pinard/p/9032759.html