Явное указание наборов тестов / поездов в GridSearchCV

У меня есть вопрос о параметре cv в GridSearchCV sklearn. .

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

Вместо этого я хочу явно указать ограничения для данных обучения, проверки и тестирования в GridSearchCV. Я могу это сделать?

Чтобы лучше прояснить вопрос, вот как я бы сделал это вручную.

import numpy as np
import pandas as pd
from sklearn.linear_model import Ridge
np.random.seed(444)

index = pd.date_range('2014', periods=60, freq='M')
X, y = make_regression(n_samples=60, n_features=3, random_state=444, noise=90.)
X = pd.DataFrame(X, index=index, columns=list('abc'))
y = pd.Series(y, index=index, name='y')

# Train on the first 30 samples, validate on the next 10, test on
#     the final 10.
X_train, X_val, X_test = np.array_split(X, [35, 50])
y_train, y_val, y_test = np.array_split(y, [35, 50])

param_grid = {'alpha': np.linspace(0, 1, 11)}
model = None
best_param_ = None
best_score_ = -np.inf

# Manual implementation
for alpha in param_grid['alpha']:
    ridge = Ridge(random_state=444, alpha=alpha).fit(X_train, y_train)
    score = ridge.score(X_val, y_val)
    if score > best_score_:
        best_score_ = score
        best_param_ = alpha
        model = ridge

print('Optimal alpha parameter: {:0.2f}'.format(best_param_))
print('Best score (on validation data): {:0.2f}'.format(best_score_))
print('Test set score: {:.2f}'.format(model.score(X_test, y_test)))
# Optimal alpha parameter: 1.00
# Best score (on validation data): 0.64
# Test set score: 0.22

Процесс здесь следующий:

  • И для X, и для Y мне нужен набор для обучения, набор для проверки и набор для тестирования. Обучающая выборка - это первые 35 выборок во временном ряду. Набор для валидации - это следующие 15 образцов. Набор тестов - финальный 10.
  • Наборы для обучения и проверки используются для определения оптимального параметра alpha в рамках регрессии Риджа. Здесь я тестирую alphas из (0,0, 0,1, ..., 0,9, 1,0).
  • Набор тестов предназначен для «фактического» тестирования в виде невидимых данных.

В любом случае ... Похоже, я хочу сделать что-то подобное, но я не уверен, что передать cv здесь:

from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(Ridge(random_state=444), param_grid, cv= ???)
grid_search.fit(...?)

В документах, которые у меня возникают проблемы с интерпретацией, указывается:

cv: int, генератор перекрестной проверки или итерируемый, необязательный

Определяет стратегию разделения перекрестной проверки. Возможные исходные данные для cv:

  • Нет, чтобы использовать трехкратную перекрестную проверку по умолчанию,
  • целое число, чтобы указать количество складок в (стратифицированной) KFold,
  • Объект, который будет использоваться в качестве генератора перекрестной проверки.
  • Итерируемый доходный поезд, тестовые расщепления.

Для входных значений типа integer / None, если оценщик является классификатором, а y является двоичным или многоклассовым, используется StratifiedKFold. Во всех остальных случаях используется KFold.


person Brad Solomon    schedule 22.01.2018    source источник
comment
См. Также stackoverflow.com/q/31948879/10495893   -  person Ben Reiniger    schedule 30.05.2021


Ответы (3)


Как сказал @MaxU, лучше позволить GridSearchCV обрабатывать разделение, но если вы хотите принудительно выполнить разделение, как вы установили в вопросе, вы можете использовать _ 1_, что и делает именно это.

Поэтому вам необходимо внести следующие изменения в свой код.

# Here X_test, y_test is the untouched data
# Validation data (X_val, y_val) is currently inside X_train, which will be split using PredefinedSplit inside GridSearchCV
X_train, X_test = np.array_split(X, [50])
y_train, y_test = np.array_split(y, [50])


# The indices which have the value -1 will be kept in train.
train_indices = np.full((35,), -1, dtype=int)

# The indices which have zero or positive values, will be kept in test
test_indices = np.full((15,), 0, dtype=int)
test_fold = np.append(train_indices, test_indices)

print(test_fold)
# OUTPUT: 
array([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
       -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0])

from sklearn.model_selection import PredefinedSplit
ps = PredefinedSplit(test_fold)

# Check how many splits will be done, based on test_fold
ps.get_n_splits()
# OUTPUT: 1

for train_index, test_index in ps.split():
    print("TRAIN:", train_index, "TEST:", test_index)

# OUTPUT: 
('TRAIN:', array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
   17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
   34]), 
 'TEST:', array([35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]))


# And now, send this `ps` to cv param in GridSearchCV
from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(Ridge(random_state=444), param_grid, cv=ps)

# Here, send the X_train and y_train
grid_search.fit(X_train, y_train)

X_train, y_train, отправленные в fit(), будут разделены на train и test (val в вашем случае) с использованием определенного разделения, и, следовательно, Ridge будет обучен на исходных данных из индексов [0:35] и протестирован на [35:50 ].

Надеюсь, это очистит работу.

person Vivek Kumar    schedule 23.01.2018
comment
Просто чтобы убедиться, что я следую - по индексам, которые имеют нулевые или положительные значения, будут сохраняться в тесте - вы имеете в виду то, что также обычно называют набором проверки, правильно? Т.е. тест », на котором определяются оптимальные параметры. - person Brad Solomon; 23.01.2018
comment
@BradSolomon Да. Набор тестов, на котором поиск по сетке оценивает параметры. Фактический набор тестов из индекса 50 и выше остался нетронутым. - person Vivek Kumar; 23.01.2018
comment
@BradSolomon Вы можете посмотреть мой другой ответ. Посмотрите шаги с 4 по 8. - person Vivek Kumar; 23.01.2018
comment
Вы также можете сделать test_fold = np.repeat([-1, 0], [35, 15]) здесь, чтобы сохранить несколько строк - person Brad Solomon; 11.02.2018
comment
@VivekKumar Итак, если я правильно понимаю, если вы используете gridsearch для всего набора данных, нет необходимости вручную создавать еще один набор проверки? Обучающего набора и тестового набора должно хватить? - person Riley; 27.07.2018
comment
@Riley Я не совсем понимаю вопрос. Да, не нужно разделять данные для сохранения другого набора для проверки, если проблема позволяет это. Например, у некоторых людей данные уже разделены на обучающие и тестовые, и они могут использовать только обучающие данные для подгонки. В этом случае они могут использовать все обучающие данные в поиске по сетке, который разделит данные по складкам. Они могут заранее разделить данные, чтобы уберечь набор проверки от поиска по сетке, если они захотят. - person Vivek Kumar; 27.07.2018
comment
@VivekKumar, меня немного смущает использование трех разных наборов (поезд, проверка и тест). Я использую регрессию SVM, и я настроил свои параметры с помощью gridsearch на моем обучающем наборе (состоящем из 60% данных). Насколько я понимаю, набор проверки используется для предотвращения переобучения, но с SVM-RBF и gridsearch у вас есть параметры, эффективно предотвращающие это, что заставляет меня полагать, что в этом случае дополнительный набор проверки действительно не нужен. Извиняюсь за длинный комментарий, я начинаю верить, что мне следовало опубликовать это как новый вопрос. - person Riley; 27.07.2018
comment
@VivekKumar, а что, если я хочу иметь 3 или более наборов? Например, если у меня 3 подхода, я могу тренироваться в первом и втором подходах и тестировать в третьем. В следующей итерации тренируйтесь на 2-й и 3-й и тестируйте на 1-й и так далее ... - person Balki; 14.11.2019
comment
@Balki Независимо от того, что вы хотите включить в тестовый набор, вам нужно проиндексировать его как 0 или положительный результат. Для трех наборов, если вы хотите, чтобы каждый набор был протестирован один раз, вы можете назначить 0, 1, 2 соответственно каждому набору. Затем, когда 0 и 1 находятся в обучении, будут проверены 2 и так далее ... - person Vivek Kumar; 14.11.2019
comment
@VivekKumar Спасибо, vivek. Чтобы было ясно, если у меня 6 строк, и если я установлю [0,0,1,1,2,2], моя перекрестная проверка будет работать при первом обучении на первых 4 строках и тестировании на последних 2 строках. В следующий раз он будет тренироваться на последних 4 рядах и проверять первые 2 ряда и так далее .. правильно? - person Balki; 14.11.2019
comment
@Balki Да. Но если вам нужно только разделить строки на разные складки, как показано выше, вы можете напрямую использовать KFold - person Vivek Kumar; 14.11.2019
comment
@VivekKumar Верно, но все мои складки не одинаковой длины. Итак, я думаю, что предопределенное разделение поможет - person Balki; 14.11.2019
comment
Если я уже предоставил разделенные данные, мне нужно будет снова объединить их и добавить индексы, есть ли способ напрямую работать с разделенными данными в GridSearchCV? - person user23657; 09.05.2021
comment
@ user23657 Нет, боюсь, это невозможно сделать в GridSearchCV - person Vivek Kumar; 11.05.2021

Вы пробовали TimeSeriesSplit?

Это было сделано специально для разделения данных временных рядов.

tscv = TimeSeriesSplit(n_splits=3)
grid_search = GridSearchCV(clf, param_grid, cv=tscv.split(X))
person Bert Kellerman    schedule 23.01.2018

Для данных временных рядов Kfold - неправильный подход, так как kfold cv перемешает ваши данные, и вы потеряете шаблон внутри ряда. Вот подход

import xgboost as xgb
from sklearn.model_selection import TimeSeriesSplit, GridSearchCV
import numpy as np
X = np.array([[4, 5, 6, 1, 0, 2], [3.1, 3.5, 1.0, 2.1, 8.3, 1.1]]).T
y = np.array([1, 6, 7, 1, 2, 3])
tscv = TimeSeriesSplit(n_splits=2)

model = xgb.XGBRegressor()
param_search = {'max_depth' : [3, 5]}

my_cv = TimeSeriesSplit(n_splits=2).split(X)
gsearch = GridSearchCV(estimator=model, cv=my_cv,
                        param_grid=param_search)
gsearch.fit(X, y)

ссылка - Как использовать TimeSeriesSplit с объектом GridSearchCV для настройки модели в scikit-learn?

person rohan chikorde    schedule 27.12.2018