Як розділити / розділити набір даних на навчальні та тестові набори даних для, наприклад, перехресної перевірки?


99

Який хороший спосіб розділити масив NumPy випадковим чином на набір даних для навчання та тестування / перевірки? Щось подібне до функцій cvpartitionабо crossvalindв Matlab.

Відповіді:


125

Якщо ви хочете розділити набір даних один раз на дві половини, ви можете використовувати numpy.random.shuffleабо, numpy.random.permutationякщо вам потрібно відслідковувати показники:

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

або

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,:]

Є багато способів багаторазово розділити один і той же набір даних для перехресної перевірки . Однією із стратегій є повторна вибірка з набору даних з повторенням:

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,:]

Нарешті, sklearn містить кілька методів перехресної перевірки (k-fold , left -n-out, ...). Він також включає більш досконалі методи "стратифікованої вибірки", які створюють розділ даних, збалансований щодо деяких особливостей, наприклад, щоб переконатися, що однакова частка позитивних і негативних прикладів у навчальному та тестовому наборах.


13
дякую за ці рішення. Але, чи не має останній метод, що використовує randint, великі шанси дати однакові показники як для тестових, так і для навчальних наборів?
ggauravr

3
Друге рішення є правильною відповіддю, тоді як 1-я та 3-я відповіді - ні. Для першого рішення перетасування набору даних не завжди є варіантом. Є багато випадків, коли вам доведеться дотримуватися порядку введення даних. А третя цілком могла б дати ті самі показники для тестування та навчання (на що вказував @ggauravr).
Педрам Баширі,

Ви не повинні повторно проводити вибір для перехресного набору перевірок. Вся ідея полягає в тому, що набір резюме ще ніколи не бачив ваш альго. Набори тренувань та тестів використовуються для підбору даних, тому, звичайно, ви отримаєте хороші результати, якщо включите їх до свого набору резюме. Я хочу підтримати цю відповідь, оскільки мені потрібно було 2-е рішення, але ця відповідь має проблеми.
RubberDuck

55

Є ще один варіант, який просто тягне за собою використання scikit-learn. Як описано у wiki wiki , ви можете просто скористатись такими інструкціями:

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)

Таким чином ви можете синхронізувати мітки для даних, які ви намагаєтесь розділити на тренування та тестування.


1
Це дуже практична відповідь, завдяки реалістичному поводженню як з комплектом поїздів, так і з етикетками.
chinnychinchin

38

Просто записка. Якщо ви хочете набори поїздів, тестів та валідацій, ви можете зробити це:

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)

Ці параметри дадуть 70% навчанню, а 15% - тестуванню та встановленню наборів. Сподіваюся, це допомагає.


5
Мабуть, слід додати це до свого коду: from sklearn.cross_validation import train_test_splitщоб було зрозуміло, який модуль ви використовуєте
Radix

Це має бути випадковим?
liang

Тобто, чи можна розділити відповідно до заданого порядку X та y?
liang

1
@liang ні, це не повинно бути випадковим. можна просто сказати, що розміри поїзда, випробування та перевірки становитимуть відсотків a, b та c від загального набору даних. скажімо a=0.7, b=0.15, c=0.15, і d = dataset, N=len(dataset), а потім 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
Заборонені: stackoverflow.com/a/34844352/4237080 , використанняfrom sklearn.model_selection import train_test_split
briennakh

14

Як sklearn.cross_validationзастарілий модуль ви можете використовувати:

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

Ви також можете розглянути стратифікований поділ на навчальний і випробувальний набір. Посвідчений підрозділ також генерує випадкові набори та тестування, але таким чином, що зберігаються оригінальні пропорції класу. Це робить навчальні та тестувальні набори краще відображають властивості вихідного набору даних.

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]

Цей код виводить:

[1 2 3]
[1 2 3]

Дякую! Іменування дещо вводить в оману, value_indsце справді індекси, але результат не є індексами, а лише масками.
greenoldman 02

1

Я написав функцію для власного проекту, яка робить це (хоча в ньому не використовується 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

Якщо ви хочете, щоб фрагменти були рандомізовані, просто перемішайте список, перш ніж передавати його.


0

Ось код для розділення даних на n = 5 складок стратифікованим способом

% 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

Дякую pberkes за вашу відповідь. Я просто модифікував його, щоб уникнути (1) заміни, коли вибірки (2) повторюваних випадків відбувалися як під час навчання, так і під час тестування:

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

Почитавши та взявши до уваги (багато ..) різні способи розподілу даних для тренування та тестування, я вирішив зробити це!

Я використав 4 різні методи (жоден з них не використовує бібліотеку sklearn, що, я впевнений, дасть найкращі результати, даючи добре розроблений і перевірений код):

  1. перетасувати всю матрицю arr, а потім розділити дані для навчання та тестування
  2. перемішуйте індекси, а потім присвоюйте їм x та y, щоб розділити дані
  3. так само, як метод 2, але більш ефективним способом це зробити
  4. використання фрейму даних pandas для розділення

метод 3 переміг далеко за найкоротший час, після цього метод 1, а методи 2 і 4 виявились насправді неефективними.

Код для 4-х різних методів, які я приуротив:

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)

І час, мінімальний час для виконання 3-х повторів з 1000 циклів:

  • Спосіб 1: 0,35883826200006297 секунд
  • Спосіб 2: 1.7157016959999964 секунд
  • Спосіб 3: 1.7876616719995582 секунди
  • Спосіб 4: 0,07562861499991413 секунд

Я сподіваюся, що це корисно!


0

Ймовірно, вам не потрібно буде тільки розділити на поїзд та тестування, але й перехрестити перевірку, щоб переконатися, що модель узагальнена. Тут я припускаю 70% даних тренувань, 20% перевірки та 10% даних про проведення випробувань.

Перевірте np.split :

Якщо index_or_sections - це одновимірний масив відсортованих цілих чисел, записи вказують, де вздовж осі масив розділений. Наприклад, [2, 3] для осі = 0 призведе до

арі [: 2] арі [2: 3] арі [3:]

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

0

Розділити на тест на поїзд і дійсний

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.