Как разбить / разделить набор данных на обучающие и тестовые наборы данных, например, для перекрестной проверки?


99

Каков хороший способ случайным образом разбить массив NumPy на набор данных для обучения и тестирования / проверки? Что-то похожее на функции cvpartitionor 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, leave-n-out, ...). Он также включает более продвинутые методы «стратифицированной выборки», которые создают раздел данных, сбалансированный по некоторым характеристикам, например, чтобы убедиться, что в обучающем и тестовом наборе есть одинаковая пропорция положительных и отрицательных примеров.


13
спасибо за эти решения. Но разве последний метод, использующий randint, имеет хорошие шансы дать одинаковые индексы как для тестового, так и для тренировочного набора?
ggauravr 05

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

Вы не должны выполнять повторную выборку для вашего набора перекрестной проверки. Вся идея заключается в том, что ваш алгоритм никогда раньше не видел набор резюме. Наборы для обучения и тестирования используются для соответствия данным, поэтому, конечно, вы получите хорошие результаты, если включите их в свой набор резюме. Я хочу проголосовать за этот ответ, потому что второе решение - это то, что мне нужно, но с этим ответом есть проблемы.
RubberDuck

55

Есть еще один вариант, который подразумевает использование scikit-learn. Как описано в wiki scikit , вы можете просто использовать следующие инструкции:

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

Это должно быть случайным образом?
лян

То есть возможно ли разделение в соответствии с заданным порядком X и Y?
лян

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

Вы также можете рассмотреть возможность стратифицированного разделения на набор для обучения и тестирования. Startified Division также генерирует набор для обучения и тестирования случайным образом, но таким образом, чтобы сохранялись исходные пропорции класса. Благодаря этому наборы для обучения и тестирования лучше отражают свойства исходного набора данных.

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 dataframe для разделения

метод 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.