交叉驗證


本文結構:

  • 什么是交叉驗證法?
  • 為什么用交叉驗證法?
  • 主要有哪些方法?優缺點?
  • 各方法應用舉例?

什么是交叉驗證法?

它的基本思想就是將原始數據(dataset)進行分組,一部分做為訓練集來訓練模型,另一部分做為測試集來評價模型。


為什么用交叉驗證法?

  1. 交叉驗證用於評估模型的預測性能,尤其是訓練好的模型在新數據上的表現,可以在一定程度上減小過擬合。
  2. 還可以從有限的數據中獲取盡可能多的有效信息。

主要有哪些方法?

1. 留出法 (holdout cross validation)

在機器學習任務中,拿到數據后,我們首先會將原始數據集分為三部分:訓練集、驗證集和測試集。
訓練集用於訓練模型,驗證集用於模型的參數選擇配置,測試集對於模型來說是未知數據,用於評估模型的泛化能力。

 

這個方法操作簡單,只需隨機把原始數據分為三組即可。
不過如果只做一次分割,它對訓練集、驗證集和測試集的樣本數比例,還有分割后數據的分布是否和原始數據集的分布相同等因素比較敏感,不同的划分會得到不同的最優模型,而且分成三個集合后,用於訓練的數據更少了。

於是有了 2. k 折交叉驗證(k-fold cross validation)加以改進:

 

k 折交叉驗證通過對 k 個不同分組訓練的結果進行平均來減少方差,因此模型的性能對數據的划分就不那么敏感。

  • 第一步,不重復抽樣將原始數據隨機分為 k 份。
  • 第二步,每一次挑選其中 1 份作為測試集,剩余 k-1 份作為訓練集用於模型訓練。
  • 第三步,重復第二步 k 次,這樣每個子集都有一次機會作為測試集,其余機會作為訓練集。
  • 在每個訓練集上訓練后得到一個模型,
  • 用這個模型在相應的測試集上測試,計算並保存模型的評估指標,
  • 第四步,計算 k 組測試結果的平均值作為模型精度的估計,並作為當前 k 折交叉驗證下模型的性能指標。

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

當 k=m 即樣本總數時,叫做 3. 留一法(Leave one out cross validation),每次的測試集都只有一個樣本,要進行 m 次訓練和預測。
這個方法用於訓練的數據只比整體數據集少了一個樣本,因此最接近原始樣本的分布。
但是訓練復雜度增加了,因為模型的數量與原始數據樣本數量相同。
一般在數據缺乏時使用。

此外:

  1. 多次 k 折交叉驗證再求均值,例如:10 次 10 折交叉驗證,以求更精確一點。
  2. 划分時有多種方法,例如對非平衡數據可以用分層采樣,就是在每一份子集中都保持和原始數據集相同的類別比例。
  3. 模型訓練過程的所有步驟,包括模型選擇,特征選擇等都是在單個折疊 fold 中獨立執行的。

還有一種比較特殊的交叉驗證方式,Bootstrapping: 通過自助采樣法,即在含有 m 個樣本的數據集中,每次隨機挑選一個樣本,再放回到數據集中,再隨機挑選一個樣本,這樣有放回地進行抽樣 m 次,組成了新的數據集作為訓練集。

這里會有重復多次的樣本,也會有一次都沒有出現的樣本,原數據集中大概有 36.8% 的樣本不會出現在新組數據集中。

優點是訓練集的樣本總數和原數據集一樣都是 m,並且仍有約 1/3 的數據不被訓練而可以作為測試集。
缺點是這樣產生的訓練集的數據分布和原數據集的不一樣了,會引入估計偏差。
此種方法不是很常用,除非數據量真的很少。


各方法應用舉例?

1. 留出法 (holdout cross validation)

下面例子,一共有 150 條數據:

>>> import numpy as np >>> from sklearn.model_selection import train_test_split >>> from sklearn import datasets >>> from sklearn import svm >>> iris = datasets.load_iris() >>> iris.data.shape, iris.target.shape ((150, 4), (150,)) 

用 train_test_split 來隨機划分數據集,其中 40% 用於測試集,有 60 條數據,60% 為訓練集,有 90 條數據:

>>> X_train, X_test, y_train, y_test = train_test_split( ... iris.data, iris.target, test_size=0.4, random_state=0) >>> X_train.shape, y_train.shape ((90, 4), (90,)) >>> X_test.shape, y_test.shape ((60, 4), (60,)) 

用 train 來訓練,用 test 來評價模型的分數。

>>> clf = svm.SVC(kernel='linear', C=1).fit(X_train, y_train) >>> clf.score(X_test, y_test) 0.96... 

2. k 折交叉驗證(k-fold cross validation)

最簡單的方法是直接調用 cross_val_score,這里用了 5 折交叉驗證:

>>> 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) >>> scores array([ 0.96..., 1. ..., 0.96..., 0.96..., 1. ]) 

得到最后平均分為 0.98,以及它的 95% 置信區間:

>>> print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2)) Accuracy: 0.98 (+/- 0.03) 

我們可以直接看一下 K-fold 是怎樣划分數據的:
X 有四個數據,把它分成 2 折,
結果中最后一個集合是測試集,前面的是訓練集,
每一行為 1 折:

>>> import numpy as np >>> from sklearn.model_selection import KFold >>> X = ["a", "b", "c", "d"] >>> kf = KFold(n_splits=2) >>> for train, test in kf.split(X): ... print("%s %s" % (train, test)) [2 3] [0 1] [0 1] [2 3] 

同樣的數據 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)) [1 2 3] [0] [0 2 3] [1] [0 1 3] [2] [0 1 2] [3] 

資料:
機器學習
http://scikit-learn.org/stable/modules/cross_validation.html
https://ljalphabeta.gitbooks.io/python-/content/kfold.html
http://www.csuldw.com/2015/07/28/2015-07-28%20crossvalidation/


推薦閱讀 歷史技術博文鏈接匯總
http://www.jianshu.com/p/28f02bb59fe5
也許可以找到你想要的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM