Как ответить
Data drift — это изменение распределения данных в продакшене относительно тех распределений, на которых модель обучалась. Если модель училась на исторических данных, а в реальности приходят другие паттерны, качество предсказаний будет падать. Строго говоря, дрифт бывает трёх видов.
Первый — ковариатный сдвиг (covariate shift): меняется распределение входных признаков. Например, модель для распознавания кошек обучали на фотографиях днём, а в продакшен приходят ночные снимки. Второй — концепт-дрифт: меняется связь между признаками и целевой переменной. Клиенты начинали покупать товары не по возрасту, а по новому триггеру — скажем, после изменения моды. Третий — приоритетный сдвиг: меняется распределение целевой переменной. Например, доля оттока клиентов выросла с 10% до 25% из-за кризиса.
Методы обнаружения делятся на три группы. Первая — статистические тесты на парных выборках. Для численных признаков используют двухвыборочный критерий Колмогорова-Смирнова или тест Манна-Уитни, для категориальных — χ²-тест. Популярна метрика PSI (Population Stability Index) — она же Population Shift Index. Значение PSI больше 0.1 считается сигналом дрифта. В моей практике я чаще сталкивался с проблемами именно при PSI около 0.15–0.2.
Вторая группа — мониторинг распределения предсказаний модели. Если средняя вероятность положительного класса в продакшене вдруг упала с 0.7 до 0.4 — это косвенный признак дрифта, даже если статистический тест ещё не сработал. Третья — мониторинг метрик качества: accuracy, precision, recall. Если на лаге метрики валидации стабильны, а в продакшене точность падает на 5% — это почти гарантированный дрифт.
На практике лучший подход — комбинированный. Я видел успешные пайплайны с Evidently AI или Alibi Detect: они считают PSI и KS-тест по каждому признаку, а дополнительно мониторят метрики модели без лага. Если хотя бы два из трёх сигналов показывают дрифт — идёт переобучение.
Код для расчёта PSI на Python часто выглядит так: разбиваем эталонные данные и новые данные на одинаковые корзины, считаем долю значений в каждой корзине, затем вычисляем сумму по формуле (p_i - q_i) * ln(p_i / q_i). В продакшене это считается раз в час по последнему батчу.
Важный нюанс: сезонные изменения не всегда дрифт. Для розницы декабрьский спрос — не дрифт, а ожидаемое событие. Нужно либо учитывать сезонность, либо калибровать модель на сезонных данных.