交叉驗證是什么?
Cross Validation是一種評估模型性能的重要方法,主要用于在多個模型中(不同種類模型或同一種類不同超參數(shù)組合)挑選出在當前問題場景下表現(xiàn)最優(yōu)的模型(model selection)。cv主要分為以下兩類:
-
k折,K-fold
k折交叉驗證是最基本的cv方法,具體方法為,將訓練集隨機等分為k份,取其中一份為驗證集評估模型,其余k-1份為訓練集訓練模型,重復該步驟k次,每次都取一份不同的子集為驗證集,最終得到k個不同的模型(不是對一個模型迭代k次)和k個評分,綜合這k個模型的表現(xiàn)(平均得分或其他)評估模型在當前問題中的優(yōu)劣。
cv.png
k值的選取很有講究,k越大,在訓練集上的Bias就會越小,但訓練集越大會導致Variance越大,同時花費的時間越長,所以選取適當大小的k很重要,經(jīng)驗值(empirical value)是k=10。 -
留一法,Leave one out(LOO)
留一法每次在訓練集的N個樣本中選一個不同的樣本作為驗證集,其余樣本為訓練集,訓練得到N-1個不同的模型。LOOCV是特殊的K-fold,當K=N時,二者相同。
還有一種叫holdout,其實算不上真正的cv,流程圖如下

這種方法受數(shù)據(jù)集分割方式的影響較大,不能較為客觀的反映出模型的優(yōu)劣。
為什么需要cv?
在訓練集(train set)上訓練得到的模型表現(xiàn)良好,但在測試集(test set)的預測結果不盡如人意,這就說明模型可能出現(xiàn)了過擬合(overfitting),bias低而variance高,在未知數(shù)據(jù)上的泛化能力差。
一個改進方案是,在訓練集的基礎上進一步劃分出新的訓練集和驗證集(validate set),在新訓練集訓練模型,在驗證集測試模型,不斷調整初始模型(超參數(shù)等),使得訓練得到的模型在驗證集上的表現(xiàn)最好,最后放到測試集上得到這個最優(yōu)模型的評估結果。
這個方案的問題在于模型的表現(xiàn)依賴于驗證集的劃分,可能使某些特殊樣本被劃入驗證集,導致模型的表現(xiàn)出現(xiàn)異常(偏好或偏差)。而且訓練集劃了一部分給驗證集后,訓練模型能得到的數(shù)據(jù)就變少了,也會影響訓練效果。因為通常來說,訓練數(shù)據(jù)越多,越能反映出數(shù)據(jù)的真實分布,模型訓練的效果就越好,越可能得到無偏估計。
交叉驗證思想應運而生,交叉驗證可以充分使用所有的訓練數(shù)據(jù)用于評估模型。
嵌套交叉驗證?
嵌套交叉驗證(Nested Cross Validation)第一次看到是在"Python Machine Learning 2nd Edition"(Sebastian Raschka)這本書中,說要將調參和模型選擇結合起來比較好的方式是嵌套交叉驗證,其挑選的模型在訓練集和測試集上的誤差估計幾乎沒有出入。(原文:the true error of the estimate is almost unbiased relative to the test set when nested cross-validation is used)
嵌套交叉驗證流程圖如下(也被稱作5*2 cross-validation):

內層交叉驗證(innner loop):用于模型選擇,可以進行特征工程處理數(shù)據(jù)。
外層交叉驗證(outer loop):用于模型評估,使用所有數(shù)據(jù)集進行分割,而不僅是訓練集,且用Stratified K-Fold保證類別比例不變。外層每一折都使用內層得到的最優(yōu)參數(shù)組合進行訓練。
演示代碼:
gs = GridSearchCV(estimator=pipe_svc, ... param_grid=param_grid, ... scoring='accuracy', ... cv=2)
scores = cross_val_score(gs, X_train, y_train, ... scoring='accuracy', cv=5)
嵌套交叉驗證可以看做是GridSearchCV的升級版,普通GridSearchCV訓練的模型只在一部分數(shù)據(jù)上進行測試,而嵌套交叉驗證可以使模型在全部數(shù)據(jù)上進行測試,能更好的說明模型的泛化能力。

常見問題
CV的模型是否要先經(jīng)過訓練?
之前在"Hands-On Machine Learning with Scikit-Learn and TensorFlow" - Chapter3. Classification - Measuring Accuracy Using Cross-Validation中(Page83)看到,筆者在cv的時候使用了之前在全量訓練集上訓練過的模型作為了cv的初始模型clone_clf = clone(sgd_clf),個人覺得這里有點問題,從多方查到的資料來看,初始模型是不能預先訓練的,至多傳入超參數(shù)組合。
CV是否輸出模型?
交叉驗證并非用于建立具體模型,而是用于模型選擇(model selection),cv中間過程產(chǎn)生的誤差最小的模型并不一定是最優(yōu)的,可能只是表面現(xiàn)象,因為只使用了一部分數(shù)據(jù)進行訓練模型,且驗證集的劃分也不一定客觀。。當選定模型后,需要在全部訓練集上重新訓練模型;為什么不使用cv過程中產(chǎn)生的最優(yōu)模型?
CV和網(wǎng)格搜索?
scikit learn庫中的GridSearchCV可以方便地嘗試不同的超參數(shù)(hyper parameter),得到最優(yōu)組合。GridSearchCV中的cv參數(shù)(默認為3-fold)利用交叉驗證為某一超參數(shù)組合打出合理的評分。GridSearchCV可以得到最優(yōu)模型,通過best_estimator_查看,best_params_可以查看最優(yōu)超參數(shù)組合。
