Stacking思想的Python3程式碼再現
阿新 • • 發佈:2018-11-05
Stacking思想的程式碼再現
本文源於對Stacking思想的理解,嘗試使用Python3.5,在Spyder中將其思想轉化為程式碼實現,並將本文內容安排如下:
1.Stacking原理(巨集觀和微觀解釋)
2.使用本文Stacking程式碼測試Iris資料集
- 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