Честная проверка модели

Утечка цели и неправильное разделение

Содержание курса

Случайное перемешивание недопустимо: время и повторные наблюдения

Удаление признака-нарушителя решает проблему утечки через содержимое столбца. Но бывают ситуации, где проблема возникает не из-за признака, а из-за самого способа разделения строк.

Временные данные. Представьте таблицу с ежедневными продажами за два года: каждая строка — один день, признаки — день недели, признак праздника, цель — объём продаж. При случайном перемешивании строка с данными за декабрь 2024 года может оказаться в train, а строка за январь 2024 — в test. Тогда модель обучается на данных, которые хронологически позже тестовых, и оценка качества перестаёт отражать реальную задачу — прогноз на ещё не наступившие дни.

Здесь уместно вспомнить диагностический вопрос из предыдущих секций: «Будет ли это значение известно до момента прогноза?» Он касается не только столбцов, но и самих строк. Когда мы случайно помещаем в train строку из будущего, мы дарим модели знание, которого у неё не было бы в реальной ситуации. Признаки вроде погоды тоже стоит рассматривать критически: фактическая погода будущего дня в момент прогноза неизвестна — её можно использовать только в виде прогноза, доступного заранее.

Корректная стратегия для временных данных — хронологический разрез без перемешивания: все ранние записи идут в train, все поздние — в test. Граница проходит по дате.

# sales_df — датафрейм с колонкой 'date'
sales_df_sorted = sales_df.sort_values('date')
split_idx = int(len(sales_df_sorted) * 0.8)
train_df = sales_df_sorted.iloc[:split_idx]
test_df  = sales_df_sorted.iloc[split_idx:]

Никакого shuffle=True, никакого random_state для выбора строк — только позиция во времени определяет принадлежность.

Повторные наблюдения одного объекта. Другая ситуация: таблица медицинских измерений, где каждому пациенту соответствует несколько строк (визиты). Если задача — оценить, как модель будет работать с ранее не встречавшимися пациентами, то случайное разделение строк этого не обеспечивает: часть визитов пациента №7 попадает в train, часть — в test. Модель обучалась на строках этого пациента — его профиль, хронические заболевания — и применяет это знание к тестовым строкам того же человека. Ошибка может оказаться низкой не потому, что модель научилась обобщать на новых людей, а потому что она уже видела данного пациента.

Для такой постановки правильная стратегия — разделять по объектам целиком: все строки пациента либо в train, либо в test. Тогда тестовые объекты гарантированно незнакомы модели и оценка отражает реальную цель.

Обе ситуации объединяет одна идея: случайный split молчаливо предполагает, что строки независимы и одинаково распределены, а цель оценки — качество на похожих строках из того же распределения. Как только постановка меняется — нужен прогноз на будущие периоды или перенос на новых объектов — это предположение нарушается, и случайное перемешивание делает оценку нерелевантной, даже если все признаки в X безупречны.