1. 程式人生 > >sklearn之Cross-validation、GridSearchCV,以及訓練集(train)、測試集(test)、驗證集(validate)的辨析

sklearn之Cross-validation、GridSearchCV,以及訓練集(train)、測試集(test)、驗證集(validate)的辨析

1.訓練集(train)、測試集(test)、驗證集(validate)

對於初學者而言,訓練集、測試集、驗證集這三個詞可能會讓你很迷糊,特別是後兩者。這裡我儘量用簡單的話說一下我自己的理解,希望可以講明白:

        對於機器學習模型訓練而言,一般是分為訓練集和測試集的。訓練集有input(X)和label(y),測試集只有input(X),它的label是要測試集訓練好的模型去預測的。

        那麼驗證集是怎麼回事?驗證集從兩個角度來說——

(1)首先,從它做的事情的角度來說,它也是給出其input(X),然後讓訓練集訓練好的model去predict驗證集的label(我們稱y_predict)。所有從這個作用的角度而言驗證集和測試集類似,都是拿train出來的model去預測得到結果。

(2)其次,從它的“成分”來看,它是屬於訓練集的,也就是說,驗證集其實是訓練集的一個子集。所以根據前面所述,驗證集我們預測得到y_predict之後,其實它本身就有實際真實的label(y),這樣就可以讓我們去通過對y_predict和真實值y進行比較來對這個模型的預測能力(泛化能力)進行評價,避免了只在訓練集上表現出色、在測試集上表現一般的“過擬合”問題

        舉個小例子來說明一下訓練集、測試集、驗證集這哥仨:

        假設小驢一夢迴到天真爛漫的高中時代,要面臨月考了。此時月考試題就是“測試集”

。我為了能在這個“測試集”上取得好成績,所以當然要多做題,然後對答案。這些帶有答案的練習題,就是“訓練集”,是小驢用於提升自己習得某科知識能力的習題。但僅僅做題看答案是沒用的,因為你也不知道你在考試的情況下會發揮如何,所以小驢把一部分有答案的習題拿出來,先不看答案做一遍,這一部分習題就是“驗證集”。做完自我測驗的小驢拿著自己答案去和標準答案進行對照並打分,得到的分數,就可以在一定程度上反映小驢的學習水平如何,此時,我們可以把小驢看做一個經過train的“模型”

2.Cross-validation——交叉驗證:

        接著上面的說。小驢如果害怕自己所選的“驗證集”

自我測驗習題有失偏頗,比如對於物理,全都是能量守恆的題目卻沒有牛頓第二定律的內容,而自己剛好擅長能量守恆導致自己的自測分數“虛高”,那麼應該怎麼做呢?

        很簡單,大家肯定也猜到了,那就是,在我們無法左右習題是否偏頗的情況下,我們只能讓小驢在多個不同的習題集上自測,然後取自測的平均分。但在習題總量有限的情況下,小驢該怎麼做才能最客觀的反映自己的學習能力呢?

        我們再假設,小驢是一個可以穿梭時空的人(好吧小驢就是這麼神奇呵呵呵)。我們現在把所有有答案的習題(所有測試集)分成10份。第一次小驢拿前9份作為“訓練集”來訓練自己,然後用第10份作為“驗證集”來自測分數,得到score1;第二次小驢時空倒轉回到做過習題之前的那個自己(所有習題全部忘記),再拿除了第9份的9份習題做“訓練集”習題,然後用第9份作為“驗證集”自測,得到score2,並以此類推,得到10個分數。10個分數取平均,得到最終的平均分,作為小驢學習能力的最客觀體現。現在,小驢的班級裡有小馬,小豬,小狼這些同學,他們也用這種方式得到其“學習能力的客觀體現”,最終我們就可以通過這個指標,在考試前,就知道誰學習能力更強。(當然是小驢咯哈哈哈)

 

        有了小驢的例子,我們就可以自然而然的引出交叉驗證的概念:我們將訓練集分成k份,每次取(k-1)份用於訓練model,1份用於驗證(或言之:測試),再通過某種metric進行打分;然後再選擇不同的(k-1)份重新訓練model,1份用於對該model進行驗證,再通過某種metric進行打分....。最終,我們得到了k個分數,取平均,我們就可以知道這個model的分數了。

        我們使用Cross-validation,多用於對模型引數(即超引數。普通引數model會自己習得,比如線性模型中的θ每個特徵的權重)的選擇。此時,選用不同超參的模型,可看作“不同的estimator”,然後我們用交叉驗證對這個estimator打平均分,從而通過這個平均分對estimator的超引數進行選擇。

3.sklearn.model_selection中的CV:

   cross_val_scorecross_validate二者均用於交叉驗證,返回值就是scores(每次交叉驗證的得分,list形式)。你設定cv =k,就返回長度為k個scores組成的list。具體使用程式碼如下: 

cross_val_score:

>>> from sklearn import metrics
>>> from sklearn.model_selection import cross_val_score

>>> clf = svm.SVC(kernel='linear', C=1)
>>> scores = cross_val_score(
...     clf, iris.data, iris.target, cv=5, scoring='f1_macro')
>>> scores                                              
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

如上所示,我們對SVM分類器當超引數C=1時的這個model進行交叉驗證,看其得分。

clf:資料集要去fit的estimator

iris.data, iris.target:訓練集的input(X)和其label(y)

cv=5:5折交叉驗證。最終scores也是個長度為5的list

scoring='f1_macro':評價標準metrics.詳見連結:Metrics 、scoring-parameters

cross_validate:

>>> from sklearn.model_selection import cross_validate
>>> from sklearn.metrics import recall_score

>>> scoring = ['precision_macro', 'recall_macro']                         #多個評價指標
>>> clf = svm.SVC(kernel='linear', C=1, random_state=0)
>>> scores = cross_validate(clf, iris.data, iris.target, scoring=scoring,
...                         cv=5, return_train_score=False)
>>> sorted(scores.keys())
['fit_time', 'score_time', 'test_precision_macro', 'test_recall_macro']
>>> scores['test_recall_macro']                       
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

 cross_validate和cross_val_score的區別在於以下兩點

  1. 允許傳入多個metrics作為評價指標
  2. 它的返回值是個dict而非list,內容包括5類:test_score, train_score, fit_time, score_times, training scores ,(fitted) estimators,它們分別是:驗證集得分、訓練集得分、每一折cv的estimator fit訓練集的時間、每一折cv的estimator對驗證集打分的時間、每一折cv的estimator物件。其中後兩類的返回與否是可以選擇的(見下)。

return_train_score=boolean:決定是否計算並返回訓練集(而非驗證集)的得分。訓練集的得分可以讓我們在和驗證集得分的對比中進行偏差/過擬合的取捨。返回每個訓練集得分是個計算量較大,而且對你選擇泛化能力最佳的estimator無用的。

return_estimator = boolean:和上面類似,是否在return中包含“estimators”

scoring=scoring:這裡把兩種打分方式組成list傳入cross_validate函式中

值得注意的事情

對於scoring引數只傳入一個打分標準的,且scoring=string, callable or None,Return的dict的keys為:['test_score', 'fit_time', 'score_time']

對於scoring引數傳入多個打分標準的,Return的dict的keys為:['test_<scorer1_name>', 'test_<scorer2_name>', 'test_<scorer...>', 'fit_time', 'score_time'] 

4.Grid Search:給模型尋找最佳超引數

        sklearn.model_selection.GridSearchCV和交叉驗證是相輔相成的。因為GridSearchCV本身就是利用交叉驗證的方法窮舉地搜尋交叉驗證得分最佳的超引數組合。GridSearchCV之所以稱為“GridSearch”即格點搜尋,實際上是因為幾種超引數的組合就形如網格的格點一樣,這裡還是用SVC的超引數C和sigma舉例:

	    0.01	    0.1	      1.0	    10.0	    100.0
1	(0.01, 1)	(0.1, 1)	(1, 1)	  (10, 1)     (100, 1)
2	(0.01, 2)	(0.1, 2)	(1, 2)	  (10, 2)	 (100, 2)
3	(0.01, 3)	(0.1, 3)	(1, 3)    (10, 3)	 (100, 3)
4	(0.01, 4)	(0.1, 4)	(1, 4)	  (10, 4)	 (100, 4)
5	(0.01, 5)	(0.1, 5)	(1, 5) 	  (10, 5)	 (100, 5)
# 行為C的取值,列為sigma取值

        如上所示,C和sigma的取值組成了一個5*5的網格,每個格點均是一組超引數,而每組超參都能確定一個estimator。GridSearchCV對其中每組超引數所確定的estimator均進行交叉驗證,並且選擇交叉驗證得分最佳的超引數組合。

 具體程式碼如下:

import numpy as np
from sklearn import svm
from sklearn.model_selection import GridSearchCV

model = svm.SVR(kernel='rbf')
c_can = np.logspace(-2, 2, 10)
gamma_can = np.logspace(-2, 2, 10)
svr = GridSearchCV(model, param_grid={'C': c_can, 'gamma': gamma_can}, cv=5)

重要屬性及方法:

cv_results_:舊版本是“grid_scores_”,cv_results_是詳盡、升級版。內容較好理解,包含了'mean_test_score'(驗證集平均得分),'rank_test_score'(驗證集得分排名),'params'(dict形式儲存所有待選params的組合),甚至還有在每次劃分的交叉驗證中的得分('split0_test_score'、 'split1_test_score'等),就是輸出的內容稍顯臃腫。內容以dict形式輸出,我們可以轉成DataFrame形式,看起來稍微養眼一點。

best_params_ : dict:最佳引數組合

best_score_ : float:cv_results_屬性中,'mean_test_score'裡面的最高分。即你驗證集得到的最高分數

best_estimator_ : estimator or dict:得到打分最高的超參組合對應的estimator

fit()/predict():用網格搜尋得到的最佳超參所構建的estimator對資料集進行fit、predict

get_params():這個和‘best_estimator_ ’這個屬性相似,但可以得到這個模型更多的引數

 歡迎轉載,轉載請務必註明出處,多謝!