天天看點

如何把資料集劃分成訓練集和測試集

from如何把資料集劃分成訓練集和測試集 - Liupeng_Wang - 部落格園  https://www.cnblogs.com/liupeng-Wang/p/8823371.html

(版權歸原作者,自己留着學習,侵删)本文主要内容來自周志華《機器學習》

本文中代碼

之前對訓練集資料集概念沒厘清,本文章是在有些訓練模型可能需要用的到分出來一個測試集。

問題: 對于一個隻包含mm個樣例的資料集D={(x1,y1),(x2,y2),⋯,(xm,ym)D={(x1,y1),(x2,y2),⋯,(xm,ym),如何适當處理,從DD中産生訓練集SS和測試集TT?

下面介紹三種常見的做法:

  • 留出法
  • 交叉驗證法
  • 自助法

留出法(hold-out)

留出法直接将資料集DD劃分為兩個互斥的集合,其中一個集合作為訓練集SS,留下的集合作為測試集TT,即D=S∪T,S∩T=∅D=S∪T,S∩T=∅。在SS上訓練出模型後,用TT來評估其測試誤差,作為對泛化誤差的估計。以二分類任務為例,假設DD包含1000個樣本,我們采取7/3分樣,将其劃分為SS包含700個樣本,TT包含300個樣本。

S/TS/T的劃分要盡可能的保持資料分布的一緻性(S/TS/T中的資料分布跟DD是一樣的),才能避免因資料劃分過程引入額外的偏差而對最終結果産生影響。例如,在分類任務中,至少要保持樣本的類别比例相似。保留類别比例的采樣方式,即分層采樣(stratified sampling)。例如,DD中含有500個正例,500個反例,當采用分層采樣擷取70%的樣本的訓練集SS和30%的赝本的測試集TT時,則SS包含有350個正例和350個反例,TT有150個正例和150個反例。

給定樣本比例,有多種劃分方式對DD進行分割。如在上面的例子中,我們可以把DD的樣本排序,然後把前350個正例放到SS中,也可以把後350個正例放入SS... 這種不同的劃分将導緻不同的訓練/測試集,相應的模型評估也是有差别的。是以,使用留出法時,一般要采用若幹次随機劃分、重複進行實驗評估後取平均值作為留出法的評估結果。例如進行100次随機劃分,每次産生一個S/TS/T進行實驗評估,得到100個結果,而留出法傳回的則是這100個結果的平均。

常見做法将大約2/3~4/5的樣本作為SS,剩下的作為TT。

通過調用

sklearn.model_selection.train_test_split

按比例劃分訓練集和測試集:

import numpy as np
from sklearn.model_selection import train_test_split

X, Y = np.arange(10).reshape((5, 2)), range(5)
print("X=", X)
print("Y=", Y)
X_train, X_test, Y_train, Y_test = train_test_split(
    X, Y, test_size=0.30, random_state=42)
print("X_train=", X_train)
print("X_test=", X_test)
print("Y_train=", Y_train)
print("Y_test=", Y_test)
           

其中

test_size=0.30

表示TT占30%, 那麼SS占70%。運作結果:

X= [[ ]
 [2 3]
 [4 5]
 [6 7]
 [8 9]]
Y= range(, )
X_train= [[ ]
 [0 1]
 [6 7]]
X_test= [[ ]
 [8 9]]
Y_train= [, , ]
Y_test= [, ]
           

交叉驗證法(cross validation)

交叉驗證法将DD劃分為kk個大小相似的互斥子集,即D=D1∪D2∪⋯∪Dk,Di∩Dj=∅(i≠j)D=D1∪D2∪⋯∪Dk,Di∩Dj=∅(i≠j)。每個子集DiDi都盡可能保持資料分布的一緻性,即從DD中通過分層采樣得到。然後,每次用k−1k−1個子集的并集作為SS,剩下的那個子集作為TT,這樣可獲得kk組S/TS/T,進而可進行kk次訓練和測試,最終傳回這kk個測試結果的平均。

交叉驗證法評估結果的穩定性和保真性在很大程度上取決于kk的取值、為強調這一點,通常把交叉驗證法稱為“kk折交叉驗證”(kk-fold cross validation)。kk最常用的取值是10,有時也取5和20等。

通過調用

sklearn.model_selection.KFold

按kk折交叉劃分訓練集和測試集:

import numpy as np
from sklearn.model_selection import KFold

X= np.arange().reshape((, ))
print("X=", X)
kf = KFold(n_splits=)
for train_index, test_index in kf.split(X):
    print('X_train:%s ' % X[train_index])
    print('X_test: %s ' % X[test_index])
           

其中

n_splits=2

表示k=2k=2。運作結果:

X= [[0 1]
 [2 3]
 [4 5]
 [6 7]
 [8 9]]
X_train:[[6 7]
 [8 9]] 
X_test: [[0 1]
 [2 3]
 [4 5]] 
X_train:[[0 1]
 [2 3]
 [4 5]] 
X_test: [[6 7]
 [8 9]]  
           

當DD包含mm個樣本,令k=mk=m,則得到交叉驗證法的一個特例——留一法(Leave-One-Out,簡稱LOO)。留一法使用的SS隻比DD少一個樣本,是以在絕大多數情況下,實際評估結果與用DD訓練的模型相似。是以,留一法被認為比較準确。但留一法對于大資料集,計算開銷太大;另外也不見得永遠比其他方法準确。

通過調用

sklearn.model_selection.LeaveOneOut

按留一法劃分訓練集和測試集:

import numpy as np
from sklearn.model_selection import LeaveOneOut

X= np.arange().reshape((, ))
print("X=", X)
loo = LeaveOneOut()
for train_index, test_index in loo.split(X):
    print('X_train:%s ' % X[train_index])
    print('X_test: %s ' % X[test_index])
           

運作結果:

X= [[0 1]
 [2 3]
 [4 5]
 [6 7]
 [8 9]]
X_train:[[2 3]
 [4 5]
 [6 7]
 [8 9]] 
X_test: [[0 1]] 
X_train:[[0 1]
 [4 5]
 [6 7]
 [8 9]] 
X_test: [[2 3]] 
X_train:[[0 1]
 [2 3]
 [6 7]
 [8 9]] 
X_test: [[4 5]] 
X_train:[[0 1]
 [2 3]
 [4 5]
 [8 9]] 
X_test: [[6 7]] 
X_train:[[0 1]
 [2 3]
 [4 5]
 [6 7]] 
X_test: [[8 9]] 
           

自助法(bootstrapping)

在前兩種方法中都保留部分樣本作為TT用于測試,是以實際評估模型使用的訓練集TT總是比期望評估模型使用的訓練集DD小,這樣會引入一些因訓練樣本規模不同而導緻的估計偏差。

自助法,以自助采樣(bootstrap sampling)為基礎。對DD進行采樣産生D′D′:每次随機從DD中挑選一個樣本,将其拷貝一份放入D′D′中,保持DD不變,重複以上過程mm次。顯然,DD中有部分樣本會多次出現在D′D′中,而另一部分不會出現。樣本在mm次采樣中的始終不被采到的機率為(1−1m)m(1−1m)m,當m→∞m→∞時,(1−1m)m→1e≈0.368(1−1m)m→1e≈0.368。

通過自助法,DD中有36.8%不會出現D′D′中。于是我們把D′D′當作訓練集SS,把D∖D′D∖D′當作測試集TT,這樣實際評估模型與期望評估模型都為mm個樣本,而仍有資料總量1/3的、沒有出現在訓練集中的樣本用于測試。這樣的測試結果為包外估計(out-of-bag estimate)。

自助法在資料集較小、難以劃分S/TS/T時很有用。此外,自助法能從DD中産生不同的SS,對內建學習等方法有好吃。自助法産生的SS改變了DD的分布,會引入估計偏差。當資料量足夠時,留出法和交叉驗證法更常用、

繼續閱讀