1. 程式人生 > >使用sklearn進行交叉驗證

使用sklearn進行交叉驗證

種子 叠代 輸入 mode int repeated core split 分組

交叉驗證之前的知識:我們如何評估一個模型

當我們想要測試我們的模型效果怎麽樣的時候,最好的方法是在實際的樣本當中進行測試,這樣可以測試出模型的泛化誤差,但是實際的樣本是沒有標簽的,所以這是一個悖論,我們無法知道樣本的泛化誤差。

假如我們在我們訓練模型的數據上面直接進行測試的話,結果會很好,會出現過擬合的方式,所以這樣來進行模型評估也是不行的。

所以,測試我們模型的方法就需要把我們已有的數據分為兩部分,一部分用進行模型的訓練,我們把它叫做訓練集,另外一部分專門用來訓練,我們把它叫做測試集。

在python當中,使用train_test_split可以將數據分為訓練集和測試集,下面使用鳶尾花數據集看一看

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import datasets
from sklearn import svm

iris = datasets.load_iris()
print(iris.data.shape, iris.target.shape)

X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.4, random_state=0)

print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)

clf = svm.SVC(kernel=‘linear‘, C=1).fit(X_train, y_train)
print( clf.score(X_test, y_test) )

輸出結果如下,test_size可以接受一個浮點數來表示測試集的比例:

(150, 4) (150,)
(90, 4) (90,)
(60, 4) (60,)
0.966666666667

上面這種方法有一個名稱,它叫做留出法(hold-out)。但是,出現了這麽一個問題,對於有一些模型(當然並不是所有的),需要我們手動輸入一些參數,比如上面svm當中的參數C,我們需要確定哪些參數是比較好的,假如還是使用訓練集和測試集這樣的劃分,當我們調整參數的時候,測試集的結果也會發生變化,依然會出現過擬合的現象,我們的測試集不能夠反應出來模型的泛化效果。

所以,我們再假如一個驗證集,來驗證哪一些參數是比較好的。最後數據集的劃分劃分變成了這樣:訓練集,驗證集還有測試集。 訓練集是為了進行模型的訓練,驗證集是為了進行參數的調整,測試集是為了看這個模型的好壞。

但是,上面的劃分依然有問題,劃分出來驗證集還有測試集,那麽我們的訓練集會變小。並且還有一個問題,那就是我們的模型會隨著我們選擇的訓練集和驗證集不同而不同。所以這個時候,我們引入了交叉驗證(cross-validation 簡稱cv)

交叉驗證

交叉驗證的基本思想是這樣的:將數據集分為k等份,對於每一份數據集,其中k-1份用作訓練集,單獨的那一份用作測試集。

sklearn當中對於模型評估所使用的一些方法

cross_value_score

這個方法能夠使用交叉驗證來計算模型的評分情況,使用方法如下所示:

from sklearn import datasets
from sklearn import svm
from sklearn.model_selection import cross_val_score

iris = datasets.load_iris()

clf = svm.SVC(kernel=‘linear‘, C=1)
scores = cross_val_score(clf, iris.data, iris.target, cv=5)

print(scores)

輸出結果如下: [ 0.96666667 1. 0.96666667 0.96666667 1. ]

clf是我們使用的算法,

cv是我們使用的交叉驗證的生成器或者叠代器,它決定了交叉驗證的數據是如何劃分的,當cv的取值為整數的時候,使用(Stratified)KFold方法。

你也可也使用自己的cv,如下所示:

from sklearn.model_selection import ShuffleSplit
my_cv = ShuffleSplit(n_splits=3, test_size=0.3, random_state=0)
scores = cross_val_score(clf, iris.data, iris.target, cv=my_cv)

還有一個參數是 scoring,決定了其中的分數計算方法。

如我們使用 scores = cross_val_score(clf, iris.data, iris.target, cv=5, scoring=‘f1_macro‘)

那麽得到的結果將是這樣的: [ 0.96658312 1. 0.96658312 0.96658312 1. ]

cross_validate

cross_validate方法和cross_validate有個兩個不同點:它允許傳入多個評估方法,可以使用兩種方法來傳入,一種是列表的方法,另外一種是字典的方法。最後返回的scores為一個字典,字典的key為[‘test_<scorer1_name>‘, ‘test_<scorer2_name>‘, ‘test_<scorer...>‘, ‘fit_time‘, ‘score_time‘]

下面是它的演示代碼,當scoring傳入列表的時候如下:

技術分享圖片View Code

當scoring傳入字典的時候如下:

技術分享圖片View Code

cross_val_predict

cross_val_predict 和 cross_val_score的使用方法是一樣的,但是它返回的是一個使用交叉驗證以後的輸出值,而不是評分標準。它的運行過程是這樣的,使用交叉驗證的方法來計算出每次劃分為測試集部分數據的值,知道所有的數據都有了預測值。假如數據劃分為[1,2,3,4,5]份,它先用[1,2,3,4]訓練模型,計算出來第5份的目標值,然後用[1,2,3,5]計算出第4份的目標值,直到都結束為止。

技術分享圖片View Code

sklearn中運用交叉驗證進行數據集劃分的方法

下面的函數是一些劃分的策略,方便我們自己劃分數據,並且我們假設數據是獨立同分布的(iid)

KFold方法 k折交叉驗證

k折交叉驗證上面已經介紹過了,它的思想不是很復雜,python代碼如下:

from sklearn.model_selection import KFold
import numpy as np

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([1, 2, 3, 4])

kf = KFold(n_splits=2)
for train_index, test_index in kf.split(X):
    print(‘train_index‘, train_index, ‘test_index‘, test_index)
    train_X, train_y = X[train_index], y[train_index]
    test_X, test_y = X[test_index], y[test_index]

輸出如下:

train_index [2 3] test_index [0 1]
train_index [0 1] test_index [2 3]

通過KFold函數,我們可以很方便的得到我們所需要的訓練集,還有測試集。

RepeatedKFold p次k折交叉驗證

在實際當中,我們只進行一次k折交叉驗證還是不夠的,我們需要進行多次,最典型的是:10次10折交叉驗證,RepeatedKFold方法可以控制交叉驗證的次數。

from sklearn.model_selection import RepeatedKFold
import numpy as np

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([1, 2, 3, 4])

kf = RepeatedKFold(n_splits=2, n_repeats=2, random_state=0)
for train_index, test_index in kf.split(X):
    print(‘train_index‘, train_index, ‘test_index‘, test_index)

輸出結果如下:

train_index [0 1] test_index [2 3]
train_index [2 3] test_index [0 1]
train_index [1 3] test_index [0 2]
train_index [0 2] test_index [1 3]

LeaveOneOut 留一法

留一法是k折交叉驗證當中,k=n(n為數據集個數)的情形

from sklearn.model_selection import LeaveOneOut

X = [1, 2, 3, 4]

loo = LeaveOneOut()
for train_index, test_index in loo.split(X):
    print(‘train_index‘, train_index, ‘test_index‘, test_index)

輸出結果如下:

train_index [1 2 3] test_index [0]
train_index [0 2 3] test_index [1]
train_index [0 1 3] test_index [2]
train_index [0 1 2] test_index [3]

留一法的缺點是:當n很大的時候,計算量會很大,因為需要進行n次模型的訓練,而且訓練集的大小為n-1。建議k折交叉驗證的時候k的值為5或者10。

LeavePOut 留P法

基本原理和留一法一樣,它會產生 技術分享圖片個訓練集和測試集

from sklearn.model_selection import LeavePOut

X = [1, 2, 3, 4]

lpo = LeavePOut(p=2)
for train_index, test_index in lpo.split(X):
    print(‘train_index‘, train_index, ‘test_index‘, test_index)

輸出結果如下:

train_index [2 3] test_index [0 1]
train_index [1 3] test_index [0 2]
train_index [1 2] test_index [0 3]
train_index [0 3] test_index [1 2]
train_index [0 2] test_index [1 3]
train_index [0 1] test_index [2 3]

ShuffleSplit 隨機分配

使用ShuffleSplit方法,可以隨機的把數據打亂,然後分為訓練集和測試集。它還有一個好處是可以通過random_state這個種子來重現我們的分配方式,如果沒有指定,那麽每次都是隨機的。

from sklearn.model_selection import ShuffleSplit
import numpy as np

X = np.arange(5)

ss = ShuffleSplit(n_splits=4, random_state=0, test_size=0.25)

for train_index, test_index in ss.split(X):
    print(‘train_index‘, train_index, ‘test_index‘, test_index)

輸出結果如下(因為指定了random_state的值,所以,當你運行這段代碼的時候,你的結果和我的是一樣的):

train_index [1 3 4] test_index [2 0]
train_index [1 4 3] test_index [0 2]
train_index [4 0 2] test_index [1 3]
train_index [2 4 0] test_index [3 1]

其它特殊情況的數據劃分方法

1:對於分類數據來說,它們的target可能分配是不均勻的,比如在醫療數據當中得癌癥的人比不得癌癥的人少很多,這個時候,使用的數據劃分方法有 StratifiedKFold ,StratifiedShuffleSplit

2:對於分組數據來說,它的劃分方法是不一樣的,主要的方法有 GroupKFold,LeaveOneGroupOut,LeavePGroupOut,GroupShuffleSplit

3:對於時間關聯的數據,方法有TimeSeriesSplit

再說模型評估,另一種方法 自助法

我們剛開始介紹的留出法(hold-out)還有我們介紹的交叉驗證法(cross validation),這兩種方法都可以進行模型評估。當然,還有一種方法,那就是自助法(bootstrapping),它的基本思想是這樣的,對於含有m個樣本的數據集D,我們對它進行有放回的采樣m次,最終得到一個含有m個樣本的數據集D,這個數據集D會有重復的數據,我們把它用作訓練數據。按照概率論的思想,在m個樣本中,有1/e的樣本從來沒有采到,將這些樣本即D\D當做測試集。具體的推到見周誌華的機器學習2.2.3。自助法在數據集很小的時候可以使用,在集成學習的時候也有應用。

參考:

Cross-validation: evaluating estimator performance

機器學習中訓練集、驗證集和測試集的作用

機器學習 周誌華

使用sklearn進行交叉驗證