1. 程式人生 > >【機器學習】交叉驗證(cross-validation)

【機器學習】交叉驗證(cross-validation)

1、什麼是交叉驗證 
交叉驗證(Cross validation),交叉驗證用於防止模型過於複雜而引起的過擬合。有時亦稱迴圈估計, 是一種統計學上將資料樣本切割成較小子集的實用方法。於是可以先在一個子集上做分析, 而其它子集則用來做後續對此分析的確認及驗證。 一開始的子集被稱為訓練集。而其它的子集則被稱為驗證集或測試集。交叉驗證是一種評估統計分析、機器學習演算法對獨立於訓練資料的資料集的泛化能力(generalize)。

交叉驗證一般要儘量滿足: 
1)訓練集的比例要足夠多,一般大於一半 
2)訓練集和測試集要均勻抽樣

2、交叉驗證的幾大方法

a、留出法 (holdout cross validation)

在機器學習任務中,拿到資料後,我們首先會將原始資料集分為三部分:訓練集、驗證集和測試集。 
訓練集用於訓練模型,驗證集用於模型的引數選擇配置,測試集對於模型來說是未知資料,用於評估模型的泛化能力。對於留出法,這個方法操作簡單,只需隨機把原始資料分為三組即可;一般如果只做一次分割,它對訓練集、驗證集和測試集的樣本數比例,還有分割後資料的分佈是否和原始資料集的分佈相同等因素比較敏感,不同的劃分會得到不同的最優模型,而且分成三個集合後,用於訓練的資料更少了。一般留出法的驗證集和測試集等同,以下例項說明:

#匯入函式包
import numpy as np
#匯入留出法的函式:train_test_split
from sklearn.model_selection import train_test_split
from sklearn import datasets
from sklearn import svmwa
#匯入資料集 
iris = datasets.load_iris()
iris.data.shape, iris.target.shape
#根據留出法將資料集分為訓練(60%)、測試集(40%)
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target,test_size=0.4, random_state=0) #test_size=0.4就是測試集的比例
1
2
3
4
5
6
7
8
9
10
11
b、k 折交叉驗證(k-fold cross validation)

k個子集,每個子集均做一次測試集,其餘的作為訓練集。交叉驗證重複k次,每次選擇一個子集作為測試集,並將k次的平均交叉驗證識別正確率作為結果。 
優點:所有的樣本都被作為了訓練集和測試集,每個樣本都被驗證一次。10-folder通常被使用。k 折交叉驗證通過對 k 個不同分組訓練的結果進行平均來減少方差,因此模型的效能對資料的劃分就不那麼敏感。

PS:之所以選擇將資料集分為10份,是因為通過利用大量資料集、使用不同學習技術進行的大量試驗,表明10折是獲得最好誤差估計的恰當選擇,而且也有一些理論根據可以證明這一點。但這並非最終診斷,爭議仍然存在。而且似乎5折或者20折與10折所得出的結果也相差無幾。

具體步驟如下: 
第一步,不重複抽樣將原始資料隨機分為 k 份。 
第二步,每一次挑選其中 1 份作為測試集,剩餘 k-1 份作為訓練集用於模型訓練。 
第三步,重複第二步 k 次,這樣每個子集都有一次機會作為測試集,其餘機會作為訓練集。 
在每個訓練集上訓練後得到一個模型,用這個模型在相應的測試集上測試,計算並儲存模型的評估指標; 
第四步,計算 k 組測試結果的平均值作為模型精度的估計,並作為當前 k 折交叉驗證下模型的效能指標。

k 一般取 10, 資料量小的時候,k 可以設大一點,這樣訓練集佔整體比例就比較大,不過同時訓練的模型個數也增多。 資料量大的時候,k 可以設小一點。

#最簡單的方法是直接呼叫 cross_val_score
#匯入函式包
import numpy as np
#匯入留出法的函式:train_test_split
from sklearn.model_selection import train_test_split
from sklearn import datasets
from sklearn import svm
from sklearn.model_selection import cross_val_score
clf = svm.SVC(kernel='linear', C=1)
iris = datasets.load_iris()
#用 5 折交叉驗證,設定引數 cv = 5,另外cross_val_score(分類器,X,y,交叉驗證次數)
scores = cross_val_score(clf, iris.data, iris.target, cv=5)
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
1
2
3
4
5
6
7
8
9
10
11
12
13
亦可以通過KFold來劃分資料

import numpy as np
#匯入KFold
from sklearn.model_selection import KFold
X = ["a", "b", "c", "d"]
#生成KFold資料劃分器
kf = KFold(n_splits=2)
for train, test in kf.split(X):
    #獲取訓練和測試資料
    print("%s %s" % (train, test))
1
2
3
4
5
6
7
8
9
但是上述KFold方法得到分開的資料後,還需要進一步通過分類器進行測試評估分數才行,因此沒有直接呼叫cross_val_score直接。

c、留一法(Leave one out cross validation)

每次的測試集都只有一個樣本,要進行 m 次訓練和預測。這個方法用於訓練的資料只比整體資料集少了一個樣本,因此最接近原始樣本的分佈。 但是訓練複雜度增加了,因為模型的數量與原始資料樣本數量相同。 
一般在資料缺乏時使用。

同樣的資料 X,我們看 LeaveOneOut 後是什麼樣子, 那就是把它分成 4 折, 結果中最後一個集合是測試集,只有一個元素,前面的是訓練集, 每一行為 1 折:

from sklearn.model_selection import LeaveOneOut
X = [1, 2, 3, 4]
loo = LeaveOneOut()
for train, test in loo.split(X):
    print("%s %s" % (train, test))
--------------------- 

https://blog.csdn.net/brucewong0516/article/details/78731076