1. 程式人生 > >《Python機器學習》筆記(六)

《Python機器學習》筆記(六)

後者 mean 子空間 otl 計算模型 lencod pytho 兩個 show

模型評估與參數調優實戰

基於流水線的工作流

一個方便使用的工具:scikit-learn中的Pipline類。它使得我們可以擬合出包含任意多個處理步驟的模型,並將模型用於新數據的預測。

加載威斯康星乳腺癌數據集

1.使用pandas從UCI網站直接讀取數據集

import pandas as pd
df=pd.read_csv(https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data,header=None)


2.接下來,將數據集的30個特征的賦值給一個Numpy的數組對象X.使用scikit-learn中的LabelEncoder類,我們可以將類標從原始的字符串表示(M或者B)轉換為整數:

from sklearn.preprocessing import LabelEncoder
X=df.loc[:,2:].values
y=df.loc[:,1].values
le=LabelEncoder()
y=le.fit_transform(y)

轉換後的類標(診斷結果)存儲在一個數組y中,此時惡性腫瘤和良性腫瘤分別被標識為類1和類0,我們可以通過調用LabelEncoder的transform方法來顯示虛擬類標(0和1)

3.在構建第一個流水線模型鉗,先將數據集劃分為訓練數據集(原始數據集80%的數據)和一個單獨的測試數據集(原數據集的20%的數據)

from sklearn.cross_validation import train_test_split
X_train,X_test,y_train,y_test
=train_test_split(X,y,test_size=0.2,random_state=1)

在流水線中集成數據轉換及評估操作

我們想通過PCA,將最初的30維數據壓縮到一個二維的子空間上。我們無需在訓練數據集和測試集上分別及逆行模型擬合、數據轉換,而是通過流水線將StandardScaler、PCA,以及LogisticRegression對象串聯起來:

from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline pipe_lr=Pipeline([(scl,StandardScaler()),(pca,PCA(n_components=2)),(clf,LogisticRegression(random_state=1))]) pipe_lr.fit(X_train,y_train) print(Test Accuracy:%.3f%pipe_lr.score(X_test,y_test))


Pipline對象采用元祖的序列作為輸入,其中每個元祖中的第一個值為一個字符串,它可以是任意標識符,我們通過它來訪問流水線中的元素,而元祖的第二個值則為scikit-learn中的一個轉換器或者評估器

流水線中包含了scikit-learn中用於數據預處理的類,最後還包括了一個評估器。在前面的示例代碼中,流水線中有兩個預處理環節,分別是用於數據縮放和轉換的的StandardScaler及PCA,最後還有一個作為評估器的邏輯斯蒂回歸分類器。在流水線pipe_lr上執行fit方法時,StandardScaler會在訓練數據上執行fit和transform操作,經過轉換後的訓練數據將傳遞給流水線上的下一個對象——PCA。與前面的步驟類似,PCA會在前一步轉換後的輸入數據上執行fit和transform操作,並將處理過的數據傳遞給流水線中的最後一個對象——評估器。我們應該註意到:流水線中沒有限定中間步驟的數量。流水線的工作方式可用下圖來描述:

技術分享圖片

使用K折交叉驗證評估模型性能

構建機器學習模型的一個關鍵步驟就是在新數據上對模型的性能進行評估。

常用的交叉驗證技術:holdout交叉驗證和k折交叉驗證。

holdout交叉驗證

holdout交叉驗證是評估機器學習模型泛化性能的一個經典且常用的方法。通過holdout方法,我們將最初的數據集劃分為訓練數據集和測試數據集:前者用於模型的訓練,後者用於性能的評估。然而,在典型的機器學習應用中,為進一步提高模型在預測未知數據上的性能,我們還要對不同參數設置進行調優和比較。該過程稱為模型選擇,指的是針對給定分類問題我們調整參數以尋求最優值(也稱為超參)的過程。

使用holdout進行模型選擇更好的方法是將數據劃分為三個部分:訓練數據集、驗證數據集和測試數據集。訓練數據集用於不同模型的擬合,模型在驗證數據集上的性能表現作為模型選擇的標準。使用模型訓練及模型選擇階段不曾使用的數據作為測試數據集的優勢在於:評估模型應用於新數據上能夠獲得較小偏差。下圖是holdout交叉驗證的一些概念。

技術分享圖片

holdout方法的一個缺點在於:模型性能的評估對訓練數據集劃分為訓練及驗證子集的方法是敏感的;評估的結果會隨樣本的不同而發生變化。

k折交叉驗證

在k折交叉驗證中,我們不重復地隨機將訓練數據集劃分為k個,其中k-1個用於模型訓練,剩余的1個用於測試。重復此過程k次,我們就得到了k個模型及對模型性能的評價。

基於這些獨立且不同的數據子集上得到的模型性能評價結果,我們可以計算出其平均性能。與holdout方法相比,這樣得到的結果對數據劃分方法的敏感性相對較低。通常情況下,我們將k折交叉驗證用於模型的調優,也就是找到使得模型泛化性能最優的超參值。一旦找到了滿意的超參值,我們就可以在全部的訓練數據上重新訓練模型,並使用獨立的測試數據對模型性能做出最終評估。

由於k折交叉驗證使用了無重復抽樣技術,該方法的優勢在於(每次叠代過程中)每個樣本點只有一次被劃入訓練數據集或測試數據集的機會,與holdout方法相比,這將使得模型性能的評估具有較小的方差

import numpy as np
from sklearn.cross_validation import StratifiedKFold
kfold=StratifiedKFold(y=y_train,n_folds=10,random_state=1)
scores=[]
for k,(train,test) in enumerate(kfold):
    pipe_lr.fit(X_train[train],y_train[train])
    score=pipe_lr.score(X_train[test],y_train[test])
    scores.append(score)
    print(Fold:%s,Class dist.:%s,Acc:%.3f%(k+1,np.bincount(y_train[train]),score))


首先,我們用訓練集中的類標y_train來初始化sklearn.cross_validation模塊下的StratifiedKfold叠代器,並通過n_folds參數來設置塊的數量。當我們使用kfold叠代器在k個塊中進行循環時,使用train中返回的索引去擬合前面所構建的邏輯斯蒂回歸流水線。通過pile_lr流水線,我們可以保證每次叠代中樣本都得到適當的縮放(如標準化)。然後使用test索引計算模型的準確率,並將其存儲在score列表中,用於計算平均準確率以及性能評估標準差。

通過學習及驗證曲線來調試算法

兩個有助於提高學習算法性能的簡單但功能強大的判定工具:學習曲線與驗證曲線。

使用學習曲線判定偏差和方差問題

如果一個模型在給定訓練數據上構造得過於復雜——模型中有太多的自由度或者參數——這時模型可能對訓練數據過擬合,而對未知數據泛化能力低下。通常情況下,收集更多的訓練樣本有助於降低模型的過擬合程度。但在實踐中,收集更多的數據會帶來高昂的成本,或者根本不可行。通過將模型的訓練及準確性驗證看作是訓練數據集大小的函數,並繪制其圖像,我們可以很容易看出模型是面臨高方差還是高偏差的問題,以及收集更多的數據是否有助於解決問題。討論模型常見的兩個問題:

技術分享圖片

左上圖像顯示的是一個高偏差模型。此模型的訓練準確率和交叉驗證準確率都很低,這表明此模型未能很好地擬合數據。解決此問題的常用方法是增加模型中參數的數量。右上方圖像中的模型面臨高方差的問題,表明訓練準確度與交叉驗證準確度之間有很大差別。針對此類過擬合問題,我們可以收集更多的訓練數據或者降低模型的復雜度,如增加正則化的參數。

如何使用scikit-learn中的學習曲線函數評估模型:

import matplotlib.pyplot as plt
from sklearn.learning_curve import  learning_curve
pipe_lr=Pipeline([(scl,StandardScaler()),(clf,LogisticRegression(penalty=l2,random_state=0))])
train_size,train_scores,test_scores=learning_curve(estimator=pipe_lr,X=X_train,y=y_train,train_sizes=np.linspace(0.1,1,10),cv=10,n_jobs=1)
train_mean=np.mean(train_scores,axis=1)
train_std=np.std(train_scores,axis=1)
test_mean=np.mean(test_scores,axis=1)
test_std=np.std(test_scores,axis=1)
plt.plot(train_size,train_mean,color=blue,marker=o,markersize=5,label=training accuracy)
plt.fill_between(train_size,train_mean+train_std,train_mean-train_std,alpha=0.15,color=blue)
plt.plot(train_size,test_mean,color=green,linestyle=--,marker=s,markersize=5,label=validation accuracy)
plt.fill_between(train_size,test_mean+test_std,test_mean-test_std,alpha=0.15,color=green)
plt.grid()
plt.xlabel(Number of training samples)
plt.ylabel(Accuracy)
plt.legend(loc=lower right)
plt.ylim([0.8,1.0])
plt.show()


通過learning_curve函數的train_size參數,我們可以控制用於生成學習曲線的樣本的絕對或相對數量。在此,通過設置train_sizes=np.linspace(0.1,1,10)來使用訓練數據集上等距間隔的10個樣本。默認情況下,learning_curve函數使用分層k折交叉驗證來計算交叉驗證的準確性,通過cv參數將k的值設置為10.然後,我們可以簡單地通過不同規模訓練集上返回地交叉驗證和測試評分來計算平均地準確率,並且我們使用matplotlib的plot函數繪制出準確率圖像。此外,在繪制圖像時,我們通過fill_between函數加入了平均準確率標準差的信息,用於表示評價結果的方差。

通過驗證曲線來判定過擬合與欠擬合

驗證曲線是一種通過定位過擬合或欠擬合等諸多問題所在,來幫助提高模型性能的有效工具。驗證曲線與學習曲線相似,不過繪制的不是樣本大小與訓練準確率、測試準確率之間的關系函數,而是準確率與模型參數之間的關系。

from sklearn.learning_curve import  validation_curve
param_range=[0.001,0.01,0.1,1,10,100]
train_scores,test_scores=validation_curve(estimator=pipe_lr,X=X_train,y=y_train,param_name=clf__C,param_range=param_range,cv=10)
train_mean=np.mean(train_scores,axis=1)
train_std=np.std(train_scores,axis=1)
test_mean=np.mean(test_scores,axis=1)
test_std=np.std(test_scores,axis=1)
plt.plot(param_range,train_mean,color=blue,marker=o,markersize=5,label=training accuracy)
plt.fill_between(param_range,train_mean+train_std,train_mean-train_std,alpha=0.15,color=blue)
plt.plot(param_range,test_mean,color=green,linestyle=--,marker=s,markersize=5,label=validation accuracy)
plt.fill_between(param_range,test_mean+test_std,test_mean-test_std,alpha=0.15,color=green)
plt.grid()
plt.xscale(log)
plt.legend(loc=lower right)
plt.xlabel(Parameter C)
plt.ylabel(Accuracy)
plt.ylim([0.8,1])
plt.show()


與learning_curve函數類似,如果我們使用的是分類算法,則validation_curve函數默認使用分層k折交叉驗證來評估模型的性能。在validation_curve函數內,我們可以指定想要驗證的參數。

使用網格搜索調優機器學習模型

在機器學習中,有兩類參數:一類通過訓練數據學習得到的參數。另一類即為調優參數,也稱超參。一種功能強大的超參數優化技巧:網格搜索,它通過尋找最優的超參值得組合以進一步提高模型得性能。

使用網格搜索調優超參

網格搜索法非常簡單,它通過對我們指定得不同超參列表進行暴力窮舉搜索,並計算估計每個組合對模型性能的影響,以獲得參數的最優組合

from sklearn.grid_search import GridSearchCV
from sklearn.svm import SVC
pipe_svc=Pipeline([(scl,StandardScaler()),(clf,SVC(random_state=1))])
param_range=[0.0001,0.001,0.01,0.1,1,10,100,1000]
param_grid=[{clf__C:param_range,clf__kernel:[linear]},{clf__C:param_range,clf__gamma:param_range,clf__kernel:[rbf]}]
gs=GridSearchCV(estimator=pipe_svc,param_grid=param_grid,scoring=accuracy,cv=10,n_jobs=-1)
gs=gs.fit(X_train,y_train)
print(gs.best_score_)
print(gs.best_params_)

使用上述代碼,我們初始化了一個sklearn.grid_search模塊下的GridSearchCV對象,用於對支持向量機流水線的訓練與調優。我們將GridSearchCV的param_grid參數以字典的方式定義為待調優的參數。對於線性SVM來說,我們只需調優正則化參數(C);對基於RBF的核SVM,我們同時需要調優C和gamma參數。請註意此處的gamma是針對核SVM特別定義的。在訓練數據集上完成網格搜索後,可以通過best_score_屬性得到最優模型的性能評分,具體參數信息可以通過best_params_屬性得到。

通過嵌套交叉驗證選擇算法

結合網格搜索進行k折交叉驗證,通過超參數值得改動對機器學習模型進行調優,這是一種有效提高機器學習模型性能的方法。如果要在不同機器學習算法中做出選擇,則推薦另一種方法——嵌套交叉驗證,在一項對誤差估計的偏差情形研究中,使用嵌套交叉驗證,估計得真是誤差與在測試集上得到的結果幾乎沒有差距。

在嵌套交叉驗證的外圍循環中,我們將數據劃分為訓練塊及測試塊;而在用於模型選擇的內部循環中,我們則基於這些訓練塊使用k折交叉驗證。在完成模型的選擇後,測試塊用於模型性能的評估。下圖通過5個外圍塊 及2個內部模塊解釋了嵌套交叉驗證的概念,也稱為5×2交叉驗證。

技術分享圖片




《Python機器學習》筆記(六)