Làm thế nào để tách / phân vùng một tập dữ liệu thành các tập dữ liệu huấn luyện và kiểm tra, ví dụ: xác thực chéo?


99

Cách tốt để tách một mảng NumPy ngẫu nhiên thành tập dữ liệu đào tạo và kiểm tra / xác nhận là gì? Một cái gì đó tương tự như cvpartitionhoặc các crossvalindchức năng trong Matlab.

Câu trả lời:


125

Nếu bạn muốn chia tập dữ liệu một lần thành hai nửa, bạn có thể sử dụng numpy.random.shufflehoặc numpy.random.permutationnếu bạn cần theo dõi các chỉ số:

import numpy
# x is your dataset
x = numpy.random.rand(100, 5)
numpy.random.shuffle(x)
training, test = x[:80,:], x[80:,:]

hoặc là

import numpy
# x is your dataset
x = numpy.random.rand(100, 5)
indices = numpy.random.permutation(x.shape[0])
training_idx, test_idx = indices[:80], indices[80:]
training, test = x[training_idx,:], x[test_idx,:]

Có nhiều cách để phân vùng lặp lại cùng một tập dữ liệu để xác thực chéo . Một chiến lược là lấy lại mẫu từ tập dữ liệu, với sự lặp lại:

import numpy
# x is your dataset
x = numpy.random.rand(100, 5)
training_idx = numpy.random.randint(x.shape[0], size=80)
test_idx = numpy.random.randint(x.shape[0], size=20)
training, test = x[training_idx,:], x[test_idx,:]

Cuối cùng, sklearn chứa một số phương thức xác nhận chéo (k-fold , left -n-out, ...). Nó cũng bao gồm các phương pháp "lấy mẫu phân tầng" nâng cao hơn nhằm tạo ra một phân vùng dữ liệu cân bằng đối với một số tính năng, chẳng hạn như để đảm bảo rằng có cùng tỷ lệ các ví dụ tích cực và tiêu cực trong tập huấn luyện và thử nghiệm.


13
cảm ơn vì những giải pháp này. Nhưng, không phải phương pháp cuối cùng, sử dụng randint, có cơ hội tốt để đưa ra các chỉ số giống nhau cho cả tập thử nghiệm và huấn luyện?
ggauravr

3
Giải pháp thứ hai là một câu trả lời hợp lệ trong khi giải pháp thứ nhất và thứ ba thì không. Đối với giải pháp thứ nhất, xáo trộn tập dữ liệu không phải lúc nào cũng là một lựa chọn, có nhiều trường hợp bạn phải giữ thứ tự đầu vào dữ liệu. Và cái thứ 3 rất có thể tạo ra các chỉ số giống nhau để kiểm tra và đào tạo (như được chỉ ra bởi @ggauravr).
pedram bashiri 17/09/19

Bạn không nên lấy mẫu lại cho tập hợp xác thực chéo của mình. Toàn bộ ý tưởng là bộ CV mà bạn chưa từng thấy trước đây. Các bộ đào tạo và bài kiểm tra được sử dụng để phù hợp với dữ liệu, vì vậy tất nhiên bạn sẽ nhận được kết quả tốt nếu đưa chúng vào bộ CV của mình. Tôi muốn tán thành câu trả lời này vì giải pháp thứ 2 là giải pháp tôi cần, nhưng câu trả lời này có vấn đề.
RubberDuck

55

Có một lựa chọn khác chỉ cần sử dụng scikit-learning. Như wiki của scikit mô tả , bạn chỉ có thể sử dụng các hướng dẫn sau:

from sklearn.model_selection import train_test_split

data, labels = np.arange(10).reshape((5, 2)), range(5)

data_train, data_test, labels_train, labels_test = train_test_split(data, labels, test_size=0.20, random_state=42)

Bằng cách này, bạn có thể tiếp tục đồng bộ hóa các nhãn cho dữ liệu mà bạn đang cố gắng chia thành đào tạo và kiểm tra.


1
Đây là một câu trả lời rất thực tế, do cách xử lý thực tế của cả bộ tàu và nhãn.
chinnychinchin

38

Chỉ là một ghi chú. Trong trường hợp bạn muốn tập hợp đào tạo, kiểm tra và xác thực AND, bạn có thể thực hiện việc này:

from sklearn.cross_validation import train_test_split

X = get_my_X()
y = get_my_y()
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
x_test, x_val, y_test, y_val = train_test_split(x_test, y_test, test_size=0.5)

Các tham số này sẽ cung cấp 70% cho quá trình đào tạo và 15% cho mỗi bộ kiểm tra và val. Hi vọng điêu nay co ich.


5
có thể nên thêm điều này vào mã của bạn: from sklearn.cross_validation import train_test_split để làm cho nó rõ ràng những gì bạn đang sử dụng mô-đun
Radix

Điều này có phải là ngẫu nhiên?
liang

Tức là có thể tách theo thứ tự đã cho của X và y được không?
liang

1
@liang không, nó không phải là ngẫu nhiên. bạn có thể chỉ cần nói kích thước tập hợp đào tạo, kiểm tra và xác thực sẽ là a, b và c phần trăm kích thước của tổng số tập dữ liệu. giả sử a=0.7, b=0.15, c=0.15, và d = dataset, N=len(dataset)sau đó x_train = dataset[0:int(a*N)], x_test = dataset[int(a*N):int((a+b)*N)]x_val = dataset[int((a+b)*N):].
offwhitelotus

1
Không được chấp nhận: stackoverflow.com/a/34844352/4237080 , sử dụngfrom sklearn.model_selection import train_test_split
briennakh

14

sklearn.cross_validationmô-đun không được dùng nữa, bạn có thể sử dụng:

import numpy as np
from sklearn.model_selection import train_test_split
X, y = np.arange(10).reshape((5, 2)), range(5)

X_trn, X_tst, y_trn, y_tst = train_test_split(X, y, test_size=0.2, random_state=42)

5

Bạn cũng có thể xem xét việc phân chia phân tầng thành tập huấn luyện và thử nghiệm. Phân chia Startified cũng tạo ra tập hợp đào tạo và kiểm tra một cách ngẫu nhiên nhưng theo cách sao cho tỷ lệ lớp ban đầu được bảo toàn. Điều này làm cho các tập huấn luyện và thử nghiệm phản ánh tốt hơn các thuộc tính của tập dữ liệu gốc.

import numpy as np  

def get_train_test_inds(y,train_proportion=0.7):
    '''Generates indices, making random stratified split into training set and testing sets
    with proportions train_proportion and (1-train_proportion) of initial sample.
    y is any iterable indicating classes of each observation in the sample.
    Initial proportions of classes inside training and 
    testing sets are preserved (stratified sampling).
    '''

    y=np.array(y)
    train_inds = np.zeros(len(y),dtype=bool)
    test_inds = np.zeros(len(y),dtype=bool)
    values = np.unique(y)
    for value in values:
        value_inds = np.nonzero(y==value)[0]
        np.random.shuffle(value_inds)
        n = int(train_proportion*len(value_inds))

        train_inds[value_inds[:n]]=True
        test_inds[value_inds[n:]]=True

    return train_inds,test_inds

y = np.array([1,1,2,2,3,3])
train_inds,test_inds = get_train_test_inds(y,train_proportion=0.5)
print y[train_inds]
print y[test_inds]

Mã này xuất ra:

[1 2 3]
[1 2 3]

Cảm ơn bạn! Việc đặt tên hơi gây hiểu lầm, value_indsthực sự là các chỉ số, nhưng đầu ra không phải là chỉ số, chỉ có mặt nạ.
greenoldman

1

Tôi đã viết một hàm cho dự án của riêng mình để thực hiện điều này (mặc dù nó không sử dụng numpy):

def partition(seq, chunks):
    """Splits the sequence into equal sized chunks and them as a list"""
    result = []
    for i in range(chunks):
        chunk = []
        for element in seq[i:len(seq):chunks]:
            chunk.append(element)
        result.append(chunk)
    return result

Nếu bạn muốn các phần được ngẫu nhiên, chỉ cần xáo trộn danh sách trước khi chuyển nó vào.


0

Đây là một đoạn mã để chia dữ liệu thành n = 5 lần theo cách phân tầng

% X = data array
% y = Class_label
from sklearn.cross_validation import StratifiedKFold
skf = StratifiedKFold(y, n_folds=5)
for train_index, test_index in skf:
    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]

0

Cảm ơn pberkes cho câu trả lời của bạn. Tôi vừa sửa đổi nó để tránh (1) thay thế trong khi lấy mẫu (2) các trường hợp trùng lặp xảy ra trong cả đào tạo và kiểm tra:

training_idx = np.random.choice(X.shape[0], int(np.round(X.shape[0] * 0.8)),replace=False)
training_idx = np.random.permutation(np.arange(X.shape[0]))[:np.round(X.shape[0] * 0.8)]
    test_idx = np.setdiff1d( np.arange(0,X.shape[0]), training_idx)

0

Sau khi thực hiện một số đọc và tính đến (nhiều ..) các cách khác nhau để tách dữ liệu để đào tạo và kiểm tra, tôi quyết định bấm giờ!

Tôi đã sử dụng 4 phương pháp khác nhau (không phải trong số chúng đang sử dụng thư viện sklearn, mà tôi chắc chắn sẽ cho kết quả tốt nhất, vì nó là mã được thiết kế và thử nghiệm tốt):

  1. xáo trộn toàn bộ ma trận và sau đó chia nhỏ dữ liệu để huấn luyện và kiểm tra
  2. xáo trộn các chỉ số rồi gán x và y để chia nhỏ dữ liệu
  3. giống như phương pháp 2, nhưng theo cách hiệu quả hơn để làm điều đó
  4. sử dụng khung dữ liệu gấu trúc để phân chia

Phương pháp 3 đã thắng cách biệt với thời gian ngắn nhất, sau phương pháp 1, và phương pháp 2 và 4 được phát hiện là thực sự kém hiệu quả.

Mã cho 4 phương pháp khác nhau mà tôi đã hẹn giờ:

import numpy as np
arr = np.random.rand(100, 3)
X = arr[:,:2]
Y = arr[:,2]
spl = 0.7
N = len(arr)
sample = int(spl*N)

#%% Method 1:  shuffle the whole matrix arr and then split
np.random.shuffle(arr)
x_train, x_test, y_train, y_test = X[:sample,:], X[sample:, :], Y[:sample, ], Y[sample:,]

#%% Method 2: shuffle the indecies and then shuffle and apply to X and Y
train_idx = np.random.choice(N, sample)
Xtrain = X[train_idx]
Ytrain = Y[train_idx]

test_idx = [idx for idx in range(N) if idx not in train_idx]
Xtest = X[test_idx]
Ytest = Y[test_idx]

#%% Method 3: shuffle indicies without a for loop
idx = np.random.permutation(arr.shape[0])  # can also use random.shuffle
train_idx, test_idx = idx[:sample], idx[sample:]
x_train, x_test, y_train, y_test = X[train_idx,:], X[test_idx,:], Y[train_idx,], Y[test_idx,]

#%% Method 4: using pandas dataframe to split
import pandas as pd
df = pd.read_csv(file_path, header=None) # Some csv file (I used some file with 3 columns)

train = df.sample(frac=0.7, random_state=200)
test = df.drop(train.index)

Và đối với thời gian, thời gian tối thiểu để thực hiện trong 3 lần lặp lại 1000 vòng là:

  • Phương pháp 1: 0,35883826200006297 giây
  • Phương pháp 2: 1.7157016959999964 giây
  • Phương pháp 3: 1.7876616719995582 giây
  • Phương pháp 4: 0,07562861499991413 giây

Tôi hy vọng điều đó hữu ích!


0

Có khả năng bạn sẽ không chỉ cần chia thành đào tạo và kiểm tra mà còn xác thực chéo để đảm bảo mô hình của bạn tổng quát hóa. Ở đây tôi giả định 70% dữ liệu đào tạo, 20% xác thực và 10% dữ liệu kiểm tra / giữ lại.

Kiểm tra np.split :

Nếu indices_or_section là mảng 1-D gồm các số nguyên được sắp xếp, các mục nhập cho biết vị trí mà mảng được chia dọc theo trục. Ví dụ: [2, 3], đối với trục = 0, kết quả là

ary [: 2] ary [2: 3] ary [3:]

t, v, h = np.split(df.sample(frac=1, random_state=1), [int(0.7*len(df)), int(0.9*len(df))]) 

0

Chia thành thử nghiệm tàu ​​và hợp lệ

x =np.expand_dims(np.arange(100), -1)


print(x)

indices = np.random.permutation(x.shape[0])

training_idx, test_idx, val_idx = indices[:int(x.shape[0]*.9)], indices[int(x.shape[0]*.9):int(x.shape[0]*.95)],  indices[int(x.shape[0]*.9):int(x.shape[0]*.95)]


training, test, val = x[training_idx,:], x[test_idx,:], x[val_idx,:]

print(training, test, val)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.