Необходимость разбиения набора данных на test и train при прогнозировании значений

Рейтинг: 2Ответов: 1Опубликовано: 11.08.2025

Использую статистические модели (множественная линейная регрессия, регрессионное дерево, случайный лес, ближайшего соседа) для прогноза распределения снега по долине на основе характеристик рельефа в точках измерений. Делаю это для нескольких лет наблюдений.

Имеющиеся данные включают координаты точек, высоту снега в ней, характеристики рельефа (высота, крутизна, экспозиция, кривизна поверхности и др) в этих точках. Типы переменных - int и float. Точки распределены хаотично в пределах долины. В разные годы количество точек 300-400.

Прогноз делается для точек, равномерно распределенных по долине. Если объяснять картографически, то на карту местности наложена сетка и для узлов сетки делается прогноз высоты снега. Для этих узлов с цифровых моделей рельефа получены значения тех же характеристик рельефа. Количество узлов - около 1000.

ВОПРОС: при составлении указанных моделей нужно ли делить набор данных на test и train выборки? Ведь по сути мой test - первичные данные из независимых и зависимой переменной (высота снега), на основе которых я получаю либо уравнение МЛР, либо регрессионное дерево, и т.д. Подставляя в полученную модель характеристики рельефа в узлах сетки (которая и есть train-выборка), я получаю прогноз.

Исправьте меня, если моя логика неверна или следует идти иным путем. Буду благодарен советами по наполнению кода.

Часть кода для регрессионного дерева:

`

            independent_variables = ["Z", "S", "C", "A", "Sx", "NR"]
            X = df[independent_variables]
            y = df['Snow_m']
            
            X_train = X
            y_train = y

            # Обучение
            path = DecisionTreeRegressor(random_state=5, criterion='squared_error',
            min_samples_leaf=2).cost_complexity_pruning_path(X_train, y_train)
            ccp_alphas, impurities = path.ccp_alphas, path.impurities
            ccp_alphas = np.insert(ccp_alphas, 0, 0)
            param_grid_tree = {
                'max_depth': range(5, 20),
                'ccp_alpha': ccp_alphas,
                'min_samples_split': [2, 5, 10],
            }
            kf = KFold(n_splits=10, shuffle=True, random_state=5)
            grid_search_tree = GridSearchCV(DecisionTreeRegressor(random_state=5,
            criterion='squared_error'),
                                            param_grid_tree,
                                            scoring='neg_mean_squared_error',
                                            cv=kf,
                                            n_jobs=-1,
                                            verbose=1)
            grid_search_tree.fit(X_train, y_train)
            
            # Поиск наилучшего дерева
            best_tree = grid_search_tree.best_estimator_
            best_params_tree = grid_search_tree.best_params_`

Распределение точек измерений на местности:

введите сюда описание изображения

распределение узлов, для которых делается прогноз:

введите сюда описание изображения

Ответы

▲ 3Принят

"Смешались в кучу кони, люди" (c)

Смотрите, все ваши данные, для которых у вас есть разметка (известная целевая переменная), вместе взятые - это train (или X, см. в конец ответа, но пока пусть будет так). Вы можете выделить из train часть данных и назвать их test или отложенная выборка, чтобы проверить - насколько хорошо ваша модель на самом деле работает. Обычно для этих целей используют 20% данных.

На самом деле вы уже используете в какой-то мере разделение на train и test в виде cross fold validation, когда подбираете оптимальные параметры для дерева. В функции GridSearchCV есть параметр cv=kf, где как-раз используется функция KFold, которая делит много раз ваши данные на train и test, чтобы подобрать такие параметры дерева, которые будут обеспечивать хорошее качество предсказания на test по всем фолдам (в среднем).

Тут главное понять, что у вас может обозначаться как train и как test разные наборы сущностей на разных этапах процесса машинного обучения. На каждом этапе процесса, когда вы отделяете от основных данных какую-то часть для независимой проверки качества моделей, вы можете обозначать часть для тренировки train, а часть для проверки test. Это может быть прямо такая матрёшка.

Ещё более запутывает ситуацию то, что в соревнованиях по машинному обучению и в тестовых задачах как test может обозначаться тот набор данных, для которого вам нужно сделать предсказание. Разметки для этого набора у вас нет и вы не можете проверить на нём качество работы модели. По крайней мере в тот момент, когда вы эту модель тренируете.

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

название описание
X,y все доступные вам исходные данные с разметкой
X_test данные без разметки, на которых вам нужно сделать предсказание
X_train, y_train часть данных, на которых происходит тренировка модели
X_valid, y_valid отложенная выборка для проверки качества модели

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

Таким образом, что касается вашей ситуации. Я бы рекомендовал сделать так:

X_train, X_valid, y_train, y_valid = train_test_split(
    X, y, test_size=0.2, shuffle=True, random_state=42)

Дальше всё как вы делаете. И после построения модели вы проверяете её качество на X_valid, y_valid, считая на них вашу целевую метрику, например RMSE. (Вы же выбрали целевую метрику для вашей задачи, которую вы хотите оптимизировать?)

y_pred = model.predict(X_valid)
print(root_mean_squared_error(y_valid, y_pred))

Причём, тут нужно учесть, что это разделение нужно только для контроля. Когда вы будете уже прямо внедрять вашу модель, вы можете тренироваться на всём массиве данных X и y, качество модели будет чуть выше при этом. Я вот этого не сделал на одном из соревнований на Kaggle и, думаю, потерял на этом некоторое количество очков, мог бы подняться выше в лидерборде.

А проверять в этом случае (при использовании всех данных для тренировки) насколько модель хорошо работает, вы по идее можете когда у вас позднее будут приходить данные по высоте снега в тех точках, для которых вы её предсказали. Если у вас, конечно, будут такие данные. Если их не будет, то нужно будет что-то ещё придумывать для контроля. Контролировать качество работы модели с течением времени обязательно нужно, это тоже часть процесса. Модели имеют свойство деградировать со временем и за этим тоже нужно следить.

И всегда нужно помнить, что у вам нужно соблюдать баланс между тем, чтобы иметь более лучшее качество предсказаний модели на конкретных данных и способностью модели к обобщению. Если вы показываете модели все ваши данные, то она лучше их выучит и сможет показать большее качество на любой части этих данных. Но сможет ли она показать себя хорошо на тех данных, которые она ещё не видела - вы не знаете. Методика обучения моделей на части данных с проверкой на отложенной части или кросс-валидация как вариант - это как-раз проверка на то, как модель себя ведёт, когда видит только часть ваших данных, хорошо ли она обобщается на остальные данные, которые она ещё не видела.

При этом нужно учитывать, что если у вас данные имеют временну'ю природу, то есть, например, они за несколько лет, то они ведь могут ещё меняться со временем. И тогда для проверки модели вам нужно не перемешивать данные, а проверять, насколько хорошо модель предсказывает более свежие данные, научившись на более старых данных. Для этого есть специальные методы разбиения данных на фолды и вообще тема time series - она особая и интересная, но её нужно разбирать отдельно.