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


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

8 68

8 ответов:

если вы хотите разделить набор данных один раз на две половины, вы можете использовать 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 содержит несколько методов перекрестной проверки (к-Кратье, оставьте-Н-аут, ...). Он также включает в себя дополнительные "стратифицированная выборка" методы, которые создают раздел данных, сбалансированный по некоторым признакам, например, чтобы убедиться, что существует одинаковое соотношение положительных и отрицательных примеров в наборе обучения и тестирования.

есть еще один вариант, который просто влечет за собой использование scikit-learn. Как Вики 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)

таким образом, вы можете синхронизировать метки для данных, которые вы пытаетесь разделить на обучение и тестирование.

просто к сведению. Если вы хотите обучать, тестировать и проверять наборы, вы можете сделать это:

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% каждое для того чтобы испытать и наборы вал. Надеюсь, это поможет.

Как 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)

вы также можете рассмотреть стратифицированное разделение на набор для обучения и тестирования. 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]

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

спасибо 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)