詳解機器學習中的7種交叉驗證方法

來源:機器學習社區(qū)、數(shù)據(jù)派THU
本文約3400字,建議閱讀10分鐘
本文與你分享7種最常用的交叉驗證技術(shù)及其優(yōu)缺點,提供了每種技術(shù)的代碼片段。在任何有監(jiān)督機器學習項目的模型構(gòu)建階段,我們訓練模型的目的是從標記的示例中學習所有權(quán)重和偏差的最佳值。
如果我們使用相同的標記示例來測試我們的模型,那么這將是一個方法論錯誤,因為一個只會重復剛剛看到的樣本標簽的模型將獲得完美的分數(shù),但無法預測任何有用的東西 - 未來的數(shù)據(jù),這種情況稱為過擬合。
為了克服過度擬合的問題,我們使用交叉驗證。所以你必須知道什么是交叉驗證?以及如何解決過擬合的問題?

什么是交叉驗證?
它是如何解決過擬合問題的?
在本文中,我將分享 7 種最常用的交叉驗證技術(shù)及其優(yōu)缺點,我還提供了每種技術(shù)的代碼片段,歡迎收藏學習,喜歡點贊支持。
下面列出了這些技術(shù)方法:
- HoldOut 交叉驗證
- K-Fold 交叉驗證
- 分層 K-Fold交叉驗證
- Leave P Out 交叉驗證
- 留一交叉驗證
- 蒙特卡洛 (Shuffle-Split)
- 時間序列(滾動交叉驗證)
1、HoldOut 交叉驗證

優(yōu)點:
1.快速執(zhí)行:因為我們必須將數(shù)據(jù)集拆分為訓練集和驗證集一次,并且模型將在訓練集上僅構(gòu)建一次,因此可以快速執(zhí)行。
缺點:
1. 不適合不平衡數(shù)據(jù)集:假設(shè)我們有一個不平衡數(shù)據(jù)集,它具有“0”類和“1”類。假設(shè) 80% 的數(shù)據(jù)屬于“0”類,其余 20% 的數(shù)據(jù)屬于“1”類。在訓練集大小為 80%,測試數(shù)據(jù)大小為數(shù)據(jù)集的 20% 的情況下進行訓練-測試分割??赡軙l(fā)生“0”類的所有 80% 數(shù)據(jù)都在訓練集中,而“1”類的所有數(shù)據(jù)都在測試集中。所以我們的模型不能很好地概括我們的測試數(shù)據(jù),因為它之前沒有看到過“1”類的數(shù)據(jù);
2. 大量數(shù)據(jù)無法訓練模型。
在小數(shù)據(jù)集的情況下,將保留一部分用于測試模型,其中可能具有我們的模型可能會錯過的重要特征,因為它沒有對該數(shù)據(jù)進行訓練。
代碼片段:
from sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import accuracy_scoreiris=load_iris()X=iris.dataY=iris.targetprint("Size of Dataset {}".format(len(X)))logreg=LogisticRegression()x_train,x_test,y_train,y_test=train_test_split(X,Y,test_size=0.3,random_state=42)logreg.fit(x_train,y_train)predict=logreg.predict(x_test)print("Accuracy score on training set is {}".format(accuracy_score(logreg.predict(x_train),y_train)))print("Accuracy score on test set is {}".format(accuracy_score(predict,y_test)))

2、K 折交叉驗證
該技術(shù)重復 K 次,直到每個折疊用作驗證集,其余折疊用作訓練集。
模型的最終精度是通過取 k-models 驗證數(shù)據(jù)的平均精度來計算的。

1. 整個數(shù)據(jù)集既用作訓練集又用作驗證集。
缺點:
1. 不用于不平衡的數(shù)據(jù)集:正如在 HoldOut 交叉驗證的情況下所討論的,在 K-Fold 驗證的情況下也可能發(fā)生訓練集的所有樣本都沒有樣本形式類“1”,并且只有 類“0”。驗證集將有一個類“1”的樣本;2. 不適合時間序列數(shù)據(jù):對于時間序列數(shù)據(jù),樣本的順序很重要。但是在 K 折交叉驗證中,樣本是按隨機順序選擇的。
代碼片段:
from sklearn.datasets import load_irisfrom sklearn.model_selection import cross_val_score,KFoldfrom sklearn.linear_model import LogisticRegressioniris=load_iris()X=iris.dataY=iris.targetlogreg=LogisticRegression()kf=KFold(n_splits=5)score=cross_val_score(logreg,X,Y,cv=kf)print("Cross Validation Scores are {}".format(score))print("Average Cross Validation score :{}".format(score.mean()))

3、分層 K 折交叉驗證
但是在這種技術(shù)中,每個折疊將具有與整個數(shù)據(jù)集中相同的目標變量實例比率。

1. 對于不平衡數(shù)據(jù)非常有效:分層交叉驗證中的每個折疊都會以與整個數(shù)據(jù)集中相同的比率表示所有類別的數(shù)據(jù)。
缺點:
1. 不適合時間序列數(shù)據(jù):對于時間序列數(shù)據(jù),樣本的順序很重要。但在分層交叉驗證中,樣本是按隨機順序選擇的。
代碼片段:
from sklearn.datasets import load_irisfrom sklearn.model_selection import cross_val_score,StratifiedKFoldfrom sklearn.linear_model import LogisticRegressioniris=load_iris()X=iris.dataY=iris.targetlogreg=LogisticRegression()stratifiedkf=StratifiedKFold(n_splits=5)score=cross_val_score(logreg,X,Y,cv=stratifiedkf)print("Cross Validation Scores are {}".format(score))print("Average?Cross?Validation?score?:{}".format(score.mean()))

4、Leave P Out ?交叉驗證
假設(shè)我們在數(shù)據(jù)集中有 100 個樣本。如果我們使用 p=10,那么在每次迭代中,10 個值將用作驗證集,其余 90 個樣本將用作訓練集。
重復這個過程,直到整個數(shù)據(jù)集在 p 樣本和 n-p 訓練樣本的驗證集上被劃分。
優(yōu)點:
1. 所有數(shù)據(jù)樣本都用作訓練和驗證樣本。
缺點:
1. 計算時間長:由于上述技術(shù)會不斷重復,直到所有樣本都用作驗證集,因此計算時間會更長;2. 不適合不平衡數(shù)據(jù)集:與 K 折交叉驗證相同,如果在訓練集中我們只有 1 個類的樣本,那么我們的模型將無法推廣到驗證集。
代碼片段:
from sklearn.model_selection import LeavePOut,cross_val_scorefrom sklearn.datasets import load_irisfrom sklearn.ensemble import RandomForestClassifieriris=load_iris()X=iris.dataY=iris.targetlpo=LeavePOut(p=2)lpo.get_n_splits(X)tree=RandomForestClassifier(n_estimators=10,max_depth=5,n_jobs=-1)score=cross_val_score(tree,X,Y,cv=lpo)print("Cross Validation Scores are {}".format(score))print("Average?Cross?Validation?score?:{}".format(score.mean()))

5、留一交叉驗證
假設(shè)我們在數(shù)據(jù)集中有 100 個樣本。然后在每次迭代中,1 個值將用作驗證集,其余 99 個樣本作為訓練集。因此,重復該過程,直到數(shù)據(jù)集的每個樣本都用作驗證點。
它與使用 p=1 的 LeavePOut 交叉驗證相同。

代碼片段:
from sklearn.datasets import load_irisfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import LeaveOneOut,cross_val_scoreiris=load_iris()X=iris.dataY=iris.targetloo=LeaveOneOut()tree=RandomForestClassifier(n_estimators=10,max_depth=5,n_jobs=-1)score=cross_val_score(tree,X,Y,cv=loo)print("Cross Validation Scores are {}".format(score))print("Average?Cross?Validation?score?:{}".format(score.mean()))
6、蒙特卡羅交叉驗證(Shuffle Split)
我們已經(jīng)決定了要用作訓練集的數(shù)據(jù)集的百分比和用作驗證集的百分比。如果訓練集和驗證集大小的增加百分比總和不是 100,則剩余的數(shù)據(jù)集不會用于訓練集或驗證集。
假設(shè)我們有 100 個樣本,其中 60% 的樣本用作訓練集,20% 的樣本用作驗證集,那么剩下的 20%( 100-(60+20)) 將不被使用。
這種拆分將重復我們必須指定的“n”次。

優(yōu)點:
1.我們可以自由使用訓練和驗證集的大小;2.我們可以選擇重復的次數(shù),而不依賴于重復的折疊次數(shù)。
缺點:
1. 可能不會為訓練集或驗證集選擇很少的樣本;2. 不適合不平衡的數(shù)據(jù)集:在我們定義了訓練集和驗證集的大小后,所有的樣本都是隨機選擇的,所以訓練集可能沒有測試中的數(shù)據(jù)類別 設(shè)置,并且該模型將無法概括為看不見的數(shù)據(jù)。
代碼片段:
from sklearn.model_selection import ShuffleSplit,cross_val_scorefrom sklearn.datasets import load_irisfrom sklearn.linear_model import LogisticRegressionlogreg=LogisticRegression()shuffle_split=ShuffleSplit(test_size=0.3,train_size=0.5,n_splits=10)scores=cross_val_score(logreg,iris.data,iris.target,cv=shuffle_split)print("cross Validation scores:n {}".format(scores))print("Average?Cross?Validation?score?:{}".format(scores.mean()))

7、時間序列交叉驗證
時間序列數(shù)據(jù)是在不同時間點收集的數(shù)據(jù)。由于數(shù)據(jù)點是在相鄰時間段收集的,因此觀測值之間可能存在相關(guān)性。這是區(qū)分時間序列數(shù)據(jù)與橫截面數(shù)據(jù)的特征之一。
在時間序列數(shù)據(jù)的情況下如何進行交叉驗證?
在時間序列數(shù)據(jù)的情況下,我們不能選擇隨機樣本并將它們分配給訓練集或驗證集,因為使用未來數(shù)據(jù)中的值來預測過去數(shù)據(jù)的值是沒有意義的。
由于數(shù)據(jù)的順序?qū)τ跁r間序列相關(guān)問題非常重要,所以我們根據(jù)時間將數(shù)據(jù)拆分為訓練集和驗證集,也稱為“前向鏈”方法或滾動交叉驗證。
我們從一小部分數(shù)據(jù)作為訓練集開始?;谠摷希覀冾A測稍后的數(shù)據(jù)點,然后檢查準確性。
然后將預測樣本作為下一個訓練數(shù)據(jù)集的一部分包括在內(nèi),并對后續(xù)樣本進行預測。

優(yōu)點:
1. 最好的技術(shù)之一。
缺點:
1. 不適用于其他數(shù)據(jù)類型的驗證:與其他技術(shù)一樣,我們選擇隨機樣本作為訓練或驗證集,但在該技術(shù)中數(shù)據(jù)的順序非常重要。
代碼片段:
import numpy as npfrom sklearn.model_selection import TimeSeriesSplitX = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [1, 2], [3, 4]])y = np.array([1, 2, 3, 4, 5, 6])time_series = TimeSeriesSplit()print(time_series)for train_index, test_index in time_series.split(X):print("TRAIN:", train_index, "TEST:", test_index)X_train, X_test = X[train_index], X[test_index]y_train, y_test = y[train_index], y[test_index]

結(jié)論
編輯:黃繼彥
校對:龔力
評論
圖片
表情
