【机器学习】图解机器学习中的 12 种交叉验证技术
今天我給大家盤點下機器學(xué)習(xí)中所使用的交叉驗證器都有哪些,用最直觀的圖解方式來幫助大家理解他們是如何工作的。
數(shù)據(jù)集說明
數(shù)據(jù)集來源于kaggle M5 Forecasting - Accuracy[1]
該任務(wù)是盡可能精確地預(yù)測沃爾瑪在美國銷售的各種產(chǎn)品的單位銷售額(demand)。本文將使用其中的一部分?jǐn)?shù)據(jù)。
該數(shù)據(jù)樣例如下。
數(shù)據(jù)集的劃分需要根據(jù)交叉驗證基本原理來操作。首先需要將所有數(shù)據(jù)集劃分為訓(xùn)練集和測試集,再再訓(xùn)練集中利用交叉驗證劃分訓(xùn)練集和驗證集,如下圖所示。
首先按照日期date劃分測試集和訓(xùn)練集,如下圖所示。
為本次演示需求,創(chuàng)造了一些新的特征,最終篩選并使用了如下幾個變量。
Training?columns:? ['sell_price',?'year',?'month',?'dayofweek',?'lag_7',? 'rmean_7_7',?'demand_month_mean',?'demand_month_max', 'demandmonth_max_to_min_diff',?'demand_dayofweek_mean',? 'demand_dayofweek_median',?'demand_dayofweek_max']設(shè)置如下兩個全局變量,以及用來存儲每種交叉驗證得分結(jié)果的DataFrame
SEED?=?888?#?為了再現(xiàn) NFOLDS?=?5?#?設(shè)置K折驗證的折數(shù) stats?=?pd.DataFrame(columns=['K-Fold?Variation','CV-RMSE','TEST-RMSE'])交叉驗證
交叉驗證(Cross Validation) 是在機器學(xué)習(xí)建立模型和驗證模型參數(shù)時常用的方法。顧名思義,就是重復(fù)的使用數(shù)據(jù),把得到的樣本數(shù)據(jù)進行切分,組合為不同的訓(xùn)練集和測試集。用訓(xùn)練集來訓(xùn)練模型,測試集來評估模型的好壞。
交叉驗證的目的
從有限的學(xué)習(xí)數(shù)據(jù)中獲取盡可能多的有效信息。
交叉驗證從多個方向開始學(xué)習(xí)樣本的,可以有效地避免陷入局部最小值。
可以在一定程度上避免過擬合問題。
交叉驗證的種類
根據(jù)切分的方法不同,交叉驗證分為下面三種:
第一種是簡單交叉驗證
首先,隨機的將樣本數(shù)據(jù)分為兩部分(比如:70%的訓(xùn)練集,30%的測試集),然后用訓(xùn)練集來訓(xùn)練模型,在測試集上驗證模型及參數(shù)。接著再把樣本打亂,重新選擇訓(xùn)練集和測試集,繼續(xù)訓(xùn)練數(shù)據(jù)和檢驗?zāi)P汀W詈筮x擇損失函數(shù)評估最優(yōu)的模型和參數(shù)。
第二種是K折交叉驗證(K-Fold Cross Validation)
和第一種方法不同, 折交叉驗證會把樣本數(shù)據(jù)隨機的分成 份,每次隨機的選擇 份作為訓(xùn)練集,剩下的1份做測試集。當(dāng)這一輪完成后,重新隨機選擇 份來訓(xùn)練數(shù)據(jù)。若干輪(小于 )之后,選擇損失函數(shù)評估最優(yōu)的模型和參數(shù)。
第三種是留一交叉驗證(Leave-one-out Cross Validation)
它是第二種情況的特例,此時 等于樣本數(shù) ,這樣對于 個樣本,每次選擇 個樣本來訓(xùn)練數(shù)據(jù),留一個樣本來驗證模型預(yù)測的好壞。此方法主要用于樣本量非常少的情況,比如對于普通適中問題, 小于50時,一般采用留一交叉驗證。
下面將用圖解方法詳細(xì)介紹12種交叉驗證方法,主要參考scikit-learn官網(wǎng)[2]介紹。
交叉驗證器
01 K折交叉驗證--沒有打亂
折交叉驗證器 KFold,提供訓(xùn)練/驗證索引以拆分訓(xùn)練/驗證集中的數(shù)據(jù)。將數(shù)據(jù)集拆分為 ?個連續(xù)的折疊(默認(rèn)情況下不改組)。然后將每個折疊用作一次驗證,而剩余的 個折疊形成訓(xùn)練集。
from?sklearn.model_selection?import?KFold KFold(n_splits=?NFOLDS,?shuffle=False,?random_state=None)? CV mean score: 23.64240, std: 1.8744. Out of sample (test) score: 20.455980不建議使用這種類型的交叉驗證來處理時間序列數(shù)據(jù),因為它忽略了數(shù)據(jù)的連貫性。實際的測試數(shù)據(jù)是將來的一個時期。
如下圖所示,黑色部分為被用作的驗證的一個折疊,而黃色部分為被用作訓(xùn)練的 個折疊。
另外數(shù)據(jù)分布圖是5折交叉驗證中每個驗證數(shù)據(jù)集(黑色部分),及實際用作驗證模型的數(shù)據(jù)集的組合分布圖。
02 K折交叉驗證--打亂的
K折交叉驗證器KFold設(shè)置參數(shù)shuffle=True
from?sklearn.model_selection?import?KFold KFold(n_splits=?NFOLDS,?random_state=SEED,?shuffle=True) CV mean score: 22.65849, std: 1.4224. Out of sample (test) score: 20.508801在每次迭代中,五分之一的數(shù)據(jù)仍然是驗證集,但這一次它是隨機分布在整個數(shù)據(jù)中。與前面一樣,在一個迭代中用作驗證的每個示例永遠(yuǎn)不會在另一個迭代中用作驗證。
如下圖所示,黑色部分為被用作驗證的數(shù)據(jù)集,很明顯,驗證集數(shù)據(jù)是被打亂了的。
03 隨機排列交叉驗證
隨機排列交叉驗證器ShuffleSplit,生成索引以將數(shù)據(jù)拆分為訓(xùn)練集和驗證集。
注意:與其他交叉驗證策略相反,隨機拆分并不能保證所有折疊都會不同,盡管對于大型數(shù)據(jù)集來說z這是很有可能。
from?sklearn.model_selection?import?ShuffleSplit ShuffleSplit(n_splits=?NFOLDS,?random_state=SEED,?train_size=0.7,?test_size=0.2) #?還有0.1的數(shù)據(jù)是沒有被取到的 CV mean score: 22.93248, std: 1.0090. Out of sample (test) score: 20.539504ShuffleSplit將在每次迭代過程中隨機抽取整個數(shù)據(jù)集,生成一個訓(xùn)練集和一個驗證集。test_size和train_size參數(shù)控制每次迭代的驗證和訓(xùn)練集的大小。因為我們在每次迭代中都是從整個數(shù)據(jù)集采樣,所以在一次迭代中選擇的值,可以在另一次迭代中再次選擇。
由于部分?jǐn)?shù)據(jù)未包含在訓(xùn)練中,該方法比普通的k倍交叉驗證更快。
如下圖所示,黑色部分為被用作驗證的數(shù)據(jù)集,橙色是被用作訓(xùn)練的數(shù)據(jù)集,而白色部分為未被包含在訓(xùn)練和驗證集中的數(shù)據(jù)集。
04 分層K折交叉驗證--沒有打亂
分層 ?折交叉驗證器StratifiedKFold。
提供訓(xùn)練/驗證索引以拆分訓(xùn)練/驗證集中的數(shù)據(jù)。這個交叉驗證對象是 KFold 的一種變體,它返回分層折疊。通過保留每個類別的樣本百分比來進行折疊。
from?sklearn.model_selection?import?StratifiedKFold StratifiedKFold(n_splits=?NFOLDS,?shuffle=False) CV mean score: 22.73248, std: 0.4955. Out of sample (test) score: 20.599119就跟普通的 折交叉驗證類似,但是每折包含每個目標(biāo)樣本的大約相同的百分比。更好地使用分類而不是回歸。
其中有幾點需要注意:
生成驗證集中,使每次切分的訓(xùn)練/驗證集中的包含類別分布相同或盡可能接近。
當(dāng) shuffle=False時,將保留數(shù)據(jù)集排序中的順序依賴關(guān)系。也就是說,某些驗證集中來自類 k 的所有樣本在 y 中是連續(xù)的。
生成驗證集大小一致,即最小和最大驗證集數(shù)據(jù)數(shù)量,最多也就相差一個樣本。
如下圖所示,在沒有打亂的情況下,驗證集(圖中黑色部分)分布是有一定的規(guī)律的。
且從下面的數(shù)據(jù)分布圖可見,5折交叉驗證數(shù)據(jù)密度分布曲線基本重合,說明雖然劃分的樣本不同,但其分布基本一致。
05 分層K折交叉驗證--打亂的
對于每個目標(biāo),折疊包大約相同百分比的樣本,但首先數(shù)據(jù)被打亂。這里需要注意的是,該交叉驗證的拆分?jǐn)?shù)據(jù)方法是一致的,僅僅是在拆分前,先打亂數(shù)據(jù)的排列,再進行分層 折交叉驗證。
from?sklearn.model_selection?import?StratifiedKFold? StratifiedKFold(n_splits=?NFOLDS,?random_state=SEED,?shuffle=True) CV mean score: 22.47692, std: 0.9594. Out of sample (test) score: 20.618389如下圖所示,打亂的分層K折交叉驗證的驗證集是沒有規(guī)律、隨機分布的。
該交叉驗證的數(shù)據(jù)分布與未被打亂的分層K折交叉驗證基本一致。
06 分組K折交叉驗證
具有非重疊組的 折迭代器變體GroupKFold。
同一組不會出現(xiàn)在兩個不同的折疊中(不同組的數(shù)量必須至少等于折疊的數(shù)量)。這些折疊是近似平衡的,因為每個折疊中不同組的數(shù)量是近似相同的。
可以從數(shù)據(jù)集的另一特定列(年)來定義組。確保同一組中不同時處于訓(xùn)練集和驗證集中。
該交叉驗證器分組是在方法split中參數(shù)groups來體現(xiàn)出來的。
from?sklearn.model_selection?import?GroupKFold groups?=?train['year'].tolist() groupfolds?=?GroupKFold(n_splits=NFOLDS) groupfolds.split(X_train,Y_train,?groups=groups) CV mean score: 23.21066, std: 2.7148. Out of sample (test) score: 20.550477如下圖所示,由于數(shù)據(jù)集原因(不是包含5個整年(組)),因此5折交叉驗證中,并不能保證沒次都包含相同數(shù)據(jù)數(shù)量的驗證集。
在上一個示例中,我們使用年作為組,在下一個示例中使用月作為組。大家可以通過下面圖可以很明顯地看看有什么區(qū)別。
from?sklearn.model_selection?import?GroupKFold groups?=?train['month'].tolist() groupfolds?=?GroupKFold(n_splits=NFOLDS) groupfolds.split(X_train,Y_train,?groups=groups) CV mean score: 22.32342, std: 3.9974. Out of sample (test) score: 20.481986如下圖所示,每次迭代均是以月為組來取驗證集。
07 分組K折交叉驗證--留一組
留一組交叉驗證器LeaveOneGroupOut。
根據(jù)第三方提供的整數(shù)組數(shù)組保留樣本。此組信息可用于編碼任意特定于域的預(yù)定義交叉驗證折疊。
因此,每個訓(xùn)練集由除與特定組相關(guān)的樣本之外的所有樣本構(gòu)成。
例如,組可以是樣本收集的年份、月份等,因此允許針對基于時間的拆分進行交叉驗證。
from?sklearn.model_selection?import?LeaveOneGroupOut groups?=?train['month'].tolist() n_folds?=?train['month'].nunique() logroupfolds?=?LeaveOneGroupOut() logroupfolds.split(X_train,Y_train,?groups=groups) CV mean score: 22.48503, std: 5.6201. Out of sample (test) score: 20.468222在每次迭代中,模型都使用留一組之外的所有組的樣本進行訓(xùn)練。如果以月份為組,則執(zhí)行12次迭代。
由下圖可以看到該分組K折交叉驗證的拆分?jǐn)?shù)據(jù)方法。
08 分組K折交叉驗證--留N組
LeavePGroupsOut將 P 組留在交叉驗證器之外,例如,組可以是樣本收集的年份,因此允許針對基于時間的拆分進行交叉驗證。
LeavePGroupsOut 和 LeaveOneGroupOut 的區(qū)別在于,前者使用所有樣本分配到P不同的組值來構(gòu)建測試集,而后者使用所有分配到相同組的樣本。
通過參數(shù)n_groups設(shè)置要在測試拆分中排除的組數(shù)。
from?sklearn.model_selection?import?LeavePGroupsOut groups?=?train['year'].tolist() lpgroupfolds?=?LeavePGroupsOut(n_groups=2) lpgroupfolds.split(X_train,Y_train,?groups=groups) CV mean score: 23.92578, std: 1.2573. Out of sample (test) score: 90.222850由下圖可知,因K=5,n_groups=2,所以共分為10種情況,每種劃分的驗證集均不相同。
09 隨機排列的分組K折交叉驗證
Shuffle-Group(s)-Out 交叉驗證迭代器GroupShuffleSplit
GroupShuffleSplit迭代器為ShuffleSplit和LeavePGroupsOut的兩種方法的結(jié)合,并生成一個隨機分區(qū)序列,其中每個分區(qū)都會保留組的一個子集。
例如,組可以是樣本收集的年份,因此允許針對基于時間的拆分進行交叉驗證。
LeavePGroupsOut 和 GroupShuffleSplit 之間的區(qū)別在于,前者使用大小P唯一組的所有子集生成拆分,而 GroupShuffleSplit 生成用戶確定數(shù)量的隨機驗證拆分,每個拆分都有用戶確定的唯一組比例。
例如,與LeavePGroupsOut(p=10)相比,一個計算強度較小的替代方案是 GroupShuffleSplit(test_size=10, n_splits=100)。
注意:參數(shù)test_size和train_size指的是組,而不是樣本,像在 ShuffleSplit 中一樣
定義組,并在每次迭代中隨機抽樣整個數(shù)據(jù)集,以生成一個訓(xùn)練集和一個驗證集。
from?sklearn.model_selection?import?GroupShuffleSplit groups?=?train['month'].tolist() rpgroupfolds?=?GroupShuffleSplit(n_splits=NFOLDS,?train_size=0.7,?test_size=0.2,?random_state=SEED) rpgroupfolds.split(X_train,Y_train,?groups=groups) CV mean score: 21.62334, std: 2.5657. Out of sample (test) score: 20.354134從圖中可見,斷開(白色)部分為未取到的數(shù)據(jù)集,每一行中每段(以白色空白為界)中驗證集(黑色)比例及位置都是一致的。而不同行之間驗證集的位置是不同的。
10 時間序列交叉驗證
時間序列數(shù)據(jù)的特征在于時間上接近的觀測值之間的相關(guān)性(自相關(guān))。然而,經(jīng)典的交叉驗證技術(shù),例如 KFold 和 ShuffleSplit假設(shè)樣本是獨立的和同分布的,并且會導(dǎo)致時間序列數(shù)據(jù)的訓(xùn)練和測試實例之間不合理的相關(guān)性(產(chǎn)生對泛化誤差的不良估計)。
因此,在“未來”觀察中評估我們的模型的時間序列數(shù)據(jù)非常重要,這與用于訓(xùn)練模型的觀察最不相似。為了實現(xiàn)這一點,提供了一種解決方案TimeSeriesSplit。
TimeSeriesSplit是KFold的變體,它首先返回 折疊成訓(xùn)練集和 第 折疊作為驗證集。請注意,與標(biāo)準(zhǔn)交叉驗證方法不同,連續(xù)訓(xùn)練集是它們之前的超集。此外,它將所有剩余數(shù)據(jù)添加到第一個訓(xùn)練分區(qū),該分區(qū)始終用于訓(xùn)練模型。
from?sklearn.model_selection?import?TimeSeriesSplit timeSeriesSplit?=?TimeSeriesSplit(n_splits=?NFOLDS) CV mean score: 24.32591, std: 2.0312. Out of sample (test) score: 20.999613這種方法建議用于時間序列數(shù)據(jù)。在時間序列分割中,訓(xùn)練集通常分為兩部分。第一部分始終是訓(xùn)練集,而后一部分是驗證集。
由下圖可知,驗證集的長度保持不變,而訓(xùn)練集隨著每次迭代的不斷增大。
11 封閉時間序列交叉驗證
這是自定義的一種交叉驗證方法。該方法函數(shù)見文末函數(shù)附錄。
btscv?=?BlockingTimeSeriesSplit(n_splits=NFOLDS) CV mean score: 22.57081, std: 6.0085. Out of sample (test) score: 19.896889由下圖可見,訓(xùn)練和驗證集在每次迭代中都是唯一的。沒有值被使用兩次。列車集總是在驗證之前。由于在較少的樣本中訓(xùn)練,它也比其他交叉驗證方法更快。
12 清除K折交叉驗證
這是基于_BaseKFold的一種交叉驗證方法。在每次迭代中,在訓(xùn)練集之前和之后,我們會刪除一些樣本。
cont?=?pd.Series(train.index) purgedfolds=PurgedKFold(n_splits=NFOLDS,t1=cont,?pctEmbargo=0.0) CV mean score: 23.64854, std: 1.9370. Out of sample (test) score: 20.589597由下圖可看出,訓(xùn)練集前后刪除了一些樣本。且其劃分訓(xùn)練集和驗證集的方法與基礎(chǔ)不打亂的KFold一致。
將embargo設(shè)置為大于0的值,將在驗證集之后刪除額外的樣本。
cont?=?pd.Series(train.index) purgedfolds=PurgedKFold(n_splits=NFOLDS,t1=cont,pctEmbargo=0.1) CV mean score: 23.87267, std: 1.7693. Out of sample (test) score: 20.414387由下圖可看出,不僅在訓(xùn)練集前后刪除了部分樣本,在驗證集后面也刪除了一些樣本,這些樣本的大小將取決于參數(shù)embargo的大小。
各交叉驗證結(jié)果比較
cm?=?sns.light_palette("green",?as_cmap=True,?reverse=True) stats.style.background_gradient(cmap=cm)附錄
封閉時間序列交叉驗證函數(shù)
class?BlockingTimeSeriesSplit():def?__init__(self,?n_splits):self.n_splits?=?n_splitsdef?get_n_splits(self,?X,?y,?groups):return?self.n_splitsdef?split(self,?X,?y=None,?groups=None):n_samples?=?len(X)k_fold_size?=?n_samples?//?self.n_splitsindices?=?np.arange(n_samples)margin?=?0for?i?in?range(self.n_splits):start?=?i?*?k_fold_sizestop?=?start?+?k_fold_sizemid?=?int(0.9?*?(stop?-?start))?+?startyield?indices[start:?mid],?indices[mid?+?margin:?stop]清除K折交叉驗證函數(shù)
from?sklearn.model_selection._split?import?_BaseKFold class?PurgedKFold(_BaseKFold):'''擴展KFold類以處理跨越間隔的標(biāo)簽在訓(xùn)練集中剔除了重疊的測試標(biāo)記間隔假設(shè)測試集是連續(xù)的(shuffle=False),中間有w/o訓(xùn)練樣本'''def?__init__(self,?n_splits=3,?t1=None,?pctEmbargo=0.1):if?not?isinstance(t1,?pd.Series):raise?ValueError('Label?Through?Dates?must?be?a?pd.Series')super(PurgedKFold,self).__init__(n_splits,?shuffle=False,?random_state=None)self.t1?=?t1self.pctEmbargo?=?pctEmbargodef?split(self,X,y=None,groups=None):X?=?pd.DataFrame(X)if?(X.index==self.t1.index).sum()!=len(self.t1):raise?ValueError('X?and?ThruDateValues?must?have?the?same?index')indices?=?np.arange(X.shape[0])mbrg?=?int(X.shape[0]?*?self.pctEmbargo)test_starts=[(i[0],i[-1]+1)?for?i?in?np.array_split(np.arange(X.shape[0]),?self.n_splits)]for?i,j?in?test_starts:t0?=?self.t1.index[i]?#?測試集的開始test_indices?=?indices[i:j]maxT1Idx?=?self.t1.index.searchsorted(self.t1[test_indices].max())train_indices?=?self.t1.index.searchsorted(self.t1[self.t1<=t0].index)if?maxT1Idx?<?X.shape[0]:?#?右邊的訓(xùn)練集帶有?embargo)train_indices?=?np.concatenate((train_indices,?indices[maxT1Idx+mbrg:]))yield?train_indices,test_indices參考資料
[1]
數(shù)據(jù)集: https://www.kaggle.com/c/m5-forecasting-accuracy
[2]交叉驗證: https://scikit-learn.org/stable/modules/classes.html
往期精彩回顧適合初學(xué)者入門人工智能的路線及資料下載機器學(xué)習(xí)及深度學(xué)習(xí)筆記等資料打印機器學(xué)習(xí)在線手冊深度學(xué)習(xí)筆記專輯《統(tǒng)計學(xué)習(xí)方法》的代碼復(fù)現(xiàn)專輯 AI基礎(chǔ)下載機器學(xué)習(xí)的數(shù)學(xué)基礎(chǔ)專輯黃海廣老師《機器學(xué)習(xí)課程》視頻課 本站qq群851320808,加入微信群請掃碼: 與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的【机器学习】图解机器学习中的 12 种交叉验证技术的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: maven jar包冲突
- 下一篇: 【效率】推荐一款特别厉害的在线工具,程序