Поезд / тестирование / проверка набора расщепления в Sklearn

59

Как я мог случайно разбить матрицу данных и соответствующий вектор метки на X_train, X_test, X_val, y_train, y_test, y_val с помощью Sklearn? Насколько я знаю, sklearn.cross_validation.train_test_splitспособен только на две, а не на три ...

Хендрик
источник

Ответы:

81

Вы могли бы просто использовать sklearn.model_selection.train_test_splitдважды. Сначала разделить на тренировку, протестировать, а затем снова разделить поезд на валидацию и тренировку. Что-то вроде этого:

 X_train, X_test, y_train, y_test 
    = train_test_split(X, y, test_size=0.2, random_state=1)

 X_train, X_val, y_train, y_val 
    = train_test_split(X_train, y_train, test_size=0.2, random_state=1)
hh32
источник
1
Да, это работает, конечно, но я надеялся на что-то более элегантное;) Неважно, я принимаю этот ответ.
Хендрик
1
Я хотел бы добавить, что если вы хотите использовать набор проверки для поиска лучших гиперпараметров, вы можете сделать следующее после разделения: gist.github.com/albertotb/1bad123363b186267e3aeaa26610b54b
skd
12
Итак, какова окончательная пропорция поезда, теста, валидации в этом примере? Потому что на втором train_test_split вы делаете это за предыдущий сплит 80/20. Таким образом, ваш val составляет 20% от 80%. Разделенные пропорции не очень просты в этом смысле.
Моника Хеднек
1
Я согласен с @Monica Heddneck в том, что 64% ​​обучающих, 16% проверочных и 20% тестовых тестов могут быть более понятными. Это надоедливый вывод, который вы должны сделать с этим решением.
Перри
33

На SO есть отличный ответ на SO, который использует numpy и pandas.

Команда (см. Ответ для обсуждения):

train, validate, test = np.split(df.sample(frac=1), [int(.6*len(df)), int(.8*len(df))])

производит разбивку на 60%, 20%, 20% для наборов обучения, проверки и тестирования.

0_0
источник
2
Я вижу .6значение 60% ... но что это .8значит?
Том Хейл
1
@TomHale np.splitразделится на 60% длины перетасованного массива, а затем на 80% длины (что является дополнительными 20% данных), оставляя, таким образом, оставшиеся 20% данных. Это связано с определением функции. Вы можете проверить / поиграть с:, x = np.arange(10.0)а затемnp.split(x, [ int(len(x)*0.6), int(len(x)*0.8)])
0_0
3

Чаще всего вы обнаружите, что не разбиваете его один раз, но на первом этапе вы разделите свои данные в обучающем и тестовом наборе. Впоследствии вы будете выполнять поиск параметров, включающий более сложные разбиения, такие как перекрестная проверка, с алгоритмом «разбить по k-сгибу» или «оставить один» (LOO).

JLT
источник
3

Вы можете использовать train_test_splitдважды. Я думаю, что это наиболее просто.

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=1)
X_train, X_val, y_train, y_val = train_test_split(
    X_train, y_train, test_size=0.25, random_state=1)

Таким образом, train, val, testнабор будет 60%, 20%, 20% набора данных соответственно.

Дэвид Юнг
источник
2

В приведенном выше наилучшем ответе не упоминается, что разделение два раза с использованием train_test_splitнеизменяемых размеров разделов не даст изначально предполагаемый раздел:

x_train, x_remain = train_test_split(x, test_size=(val_size + test_size))

Тогда часть проверочных и тестовых наборов в x_remain изменится и может быть посчитана как

new_test_size = np.around(test_size / (val_size + test_size), 2)
# To preserve (new_test_size + new_val_size) = 1.0 
new_val_size = 1.0 - new_test_size

x_val, x_test = train_test_split(x_remain, test_size=new_test_size)

В этом случае все начальные разделы сохраняются.

A.Ametov
источник
1

Вот другой подход (предполагает равное трехстороннее разделение):

# randomly shuffle the dataframe
df = df.reindex(np.random.permutation(df.index))

# how many records is one-third of the entire dataframe
third = int(len(df) / 3)

# Training set (the top third from the entire dataframe)
train = df[:third]

# Testing set (top half of the remainder two third of the dataframe)
test = df[third:][:third]

# Validation set (bottom one third)
valid = df[-third:]

Это может быть сделано более кратким, но я держал это подробным для целей объяснения.

Вишал
источник
0

Учитывая train_frac=0.8, эта функция создает разделение 80% / 10% / 10%:

import sklearn

def data_split(examples, labels, train_frac, random_state=None):
    ''' https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html
    param data:       Data to be split
    param train_frac: Ratio of train set to whole dataset

    Randomly split dataset, based on these ratios:
        'train': train_frac
        'valid': (1-train_frac) / 2
        'test':  (1-train_frac) / 2

    Eg: passing train_frac=0.8 gives a 80% / 10% / 10% split
    '''

    assert train_frac >= 0 and train_frac <= 1, "Invalid training set fraction"

    X_train, X_tmp, Y_train, Y_tmp = sklearn.model_selection.train_test_split(
                                        examples, labels, train_size=train_frac, random_state=random_state)

    X_val, X_test, Y_val, Y_test   = sklearn.model_selection.train_test_split(
                                        X_tmp, Y_tmp, train_size=0.5, random_state=random_state)

    return X_train, X_val, X_test,  Y_train, Y_val, Y_test
Том Хейл
источник
0

Добавление к ответу @ hh32 при соблюдении любых заранее определенных пропорций, таких как (75, 15, 10):

train_ratio = 0.75
validation_ratio = 0.15
test_ratio = 0.10

# train is now 75% of the entire data set
# the _junk suffix means that we drop that variable completely
x_train, x_test, y_train, y_test = train_test_split(dataX, dataY, test_size=1 - train_ratio)

# test is now 10% of the initial data set
# validation is now 15% of the initial data set
x_val, x_test, y_val, y_test = train_test_split(x_test, y_test, test_size=test_ratio/(test_ratio + validation_ratio)) 

print(x_train, x_val, x_test)
Андрей Флоря
источник
0

Расширение ответа @ hh32 с сохранением соотношений.

# Defines ratios, w.r.t. whole dataset.
ratio_train = 0.8
ratio_val = 0.1
ratio_test = 0.1

# Produces test split.
x_remaining, x_test, y_remaining, y_test = train_test_split(
    x, y, test_size=test_ratio)

# Adjusts val ratio, w.r.t. remaining dataset.
ratio_remaining = 1 - ratio_test
ratio_val_adjusted = ratio_val / ratio_remaining

# Produces train and val splits.
x_train, x_val, y_train, y_val = train_test_split(
    x_remaining, y_remaining, test_size=ratio_val_adjusted)

Поскольку оставшийся набор данных уменьшается после первого разделения, новые соотношения по отношению к сокращенному набору данных должны быть рассчитаны путем решения уравнения:

RremainingRnew=Rold

Хорхе Барриос
источник