Завтра будет так же, как вчера?
Разбиение на обучающую и тестовую выборку без учета времени — распространенная ошибка, про которую все уже знают. Правильное разбиение может привести к неочевидным проблемам, которые мы обнаружим и решим.
Рассмотрим небольшой пример. Нам нужно спрогнозировать выручку по магазинам на следующий месяц, признаки — агрегаты выручки в прошлом, доступны данные за год. Модель специально выберем стандартную, градиентный бустинг над решающими деревьями. Для наглядности оценивать качество будем по средней относительной ошибке MAPE.
Разобьем данные на обучающую (train) и тестовую (test) выборки случайно, обучим модель и оценим результат. Кросс-валидацию и валидационную выборку упускаем для простоты.
Подход со случайным разбиением дает ошибку на test в 12%. Возможно этого хватит, но в продакшене модель обученная на прошлом будет прогнозировать будущую выручку. В случайном разбиении это не учтено.
Сравнение разбиений для одного магазина
Сделаем разбиение по времени, теперь в test последние 3 месяца. Всегда стоит разобраться, как будет использоваться модель и выбрать стратегию валидации, повторяющую продакшн.
Обучаем новую модель, MAPE выросла с 12% до 24%! Более того, ошибка растет с каждым месяцем.
Чем дальше в будущее, тем сильнее ошибается модель
В отчетах или на демо 12% выглядят лучше, чем 24%, но в проде модель будет работать с ошибкой в 24%. Оценивая модель некорректно, вы можете неприятно удивиться результатам АБ-теста или приемки.
Что произошло?
Мы столкнулись со смещением данных или dataset shift. Мир со временем меняется, и эти изменения отражаются в данных. Обученная на прошлом модель ничего о них не знает. Пытаясь обучиться на train, модель начинает все сильнее ошибаться test.
Скрытый текст
Смещение можно принять за переобучение. В нашем примере ошибка на test 24%, а на train 6%. Предотвращение переобучения повысит метрики, но не решит проблему.
Что это значит для нас:
Большая ошибка прогноза. 24% Может быть достаточно, но можно меньше.
Быстрая деградация модели. Без регулярного переобучения 19% в первый месяц быстро превратятся в 30%.
Сложно обучить модель. Изменение гиперпараметров и работа с данными слабо влияют на метрики качества.
Обнаружим смещение
Есть 3 причины смещения и все они могут возникнуть одновременно:
Covariate shift: Разное распределение признаков в train и test.
Prior probability shift или label shift: Разное распределение целевой переменной.
Concept drift: Изменилась зависимость между признаками и целевой переменной.
Несколько методов обнаружения смещения, пойдем от простого к сложному:
Проверить изменение целевой переменной и признаков во времени глазами. Иногда можно заметить очевидные аномалии и тренды.
Сравнить распределения признаков и целевой переменной в train и test, лучше с помощью стат. тестов. Этот метод обнаруживает смещение в отдельных признаках, но не учитывает их взаимодействие.
Построить классификатор отличающий train и test. Объединяем train и test выборки, признаки из исходного датасета, а целевая переменная — принадлежность к train или test. Чем выше качество классификатора, тем сильнее смещение. Взаимодействие признаков уже учитывается, по feature importance можно определить смещенные признаки.
Теперь разберемся что происходит у нас. Не обязательно сразу бросаться в подготовленные датасеты, общую картину можно быстро понять по уже готовым отчетам и дэшбордам, особенно это выручает когда ваши данные еще не готовы. Откроем отчет с показателями по нашей компании и посмотрим на выручку.
Средняя выручка по магазинам из отчета по компании
Благодаря общим усилиям, выручка в магазинах растет и продолжает расти, есть тренд. Посмотрим на целевую переменную в наших данных.
Train и test различаются по значениям целевой переменной
То же самое. Логично, это тот же показатель, что и на предыдущем графике. Более того, наши признаки подсчитаны из выручки за прошлые месяцы, тренд есть и в них. Причина смещения — тренд, который модель не может учесть. Разберемся, как он влияет на модель:
Меняется распределение признаков, посчитанных из истории выручки. Выученные сплиты решающих деревьев начинают работать хуже.
Меняется распределение целевой переменной. Решающее дерево не умеет экстраполировать, модель никогда не видела таких больших значений выручки и не может их спрогнозировать.
В прошлом тренда не было или он был другим. У нас мало данных с нужными зависимостями.
В реальных задачах все будет сложнее: появляются новые категории объектов, различные акции и промо или меняется методология сбора данных и расчета метрик.
Скрытый текст
Несколько примеров из жизни.
Работая над проектом из нефтяной промышленности, заметили, что с определенного момента данных становится значительно больше и падает качество. Выяснилось, что у месторождения сменился владелец. Бурить начали активнее и по-другому собирать показатели.
Другой случай возник при работе над системой динамического ценообразования. Прямо перед запуском в метриках продукта появился тренд, как в нашем примере. Построенные модели с ним не справлялись, помогло удаление тренда и другие методы.
Устраним смещение
Если коротко, то нам нужно сделать train и test похожими. Несколько простых методов:
Удаление наиболее различающихся признаков. Может помочь, но как правило смещение не содержится только в каких-то конкретных признаках, к тому же теряем ценную информацию.
Oversampling или undersampling. Насэмплим данные в train, чтобы распределения в train и test были похожими. Помогает в случае label shift.
Преобразование признаков и целевой переменной: переход к относительными значениям, масштабирование данных, объединение или разделение категорий, удаление тренда и т.д.
Удаление данных. Например, если в test или train есть аномалии и вы уверены, что модель не должна их обрабатывать, можно их удалить.
Также можно воспользоваться техниками из transfer learning или собрать больше данных.
А теперь удалим тренд. Из каждого значения выручки вычтем предыдущее значение, пересчитаем признаки. Модель будет прогнозировать не выручку, а изменение выручки относительно предыдущего месяца.
Для оценки качества обязательно выполним обратное преобразование: прибавим к прогнозу модели выручку за предыдущий месяц. Теперь ошибка 7% и не растет во времени! Мы не только уменьшили MAPE c 24% до 7%, но и сделали нашу модель надежнее. Если тренд продолжится, модель будет работать корректно.
После удаления тренда ошибка не только стала меньше, но и не растет со временем
На практике полностью удалять смещение не нужно. Как только качество устраивает, заканчиваем. Если есть сомнения, проверьте, что разница в ошибках стат. значимая.
Итог
Разбивая датасет по времени, можно столкнуться со смещением. Обнаружить и устранить смещение непросто, но в результате вы получите надежную и точную модель. Вложенные усилия обязательно окупятся в продакшене.
Что мы узнали:
Важно правильно выбрать стратегию валидации. Качество может отличаться в разы, а узнаете вы об этом только в проде.
Всегда стоит проверить, как данные изменяются во времени. Хотя бы по основным показателям и целевой переменной.
Удаление смещения повышает качество модели и делает ее надежнее.
Расскажите в комментариях о своих случаях смещения, некорректных или необычных способах валидации. Буду рад любым дополнениям и уточнениям.
Полезные ссылки: