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

Причин может быть множество, но сегодня я расскажу про одну из самых распространенных причин падения качества модели - Distribution shift.

Distribution shift или же смещение распределения - это ситуация, когда статистические свойства данных, на которых модель обучалась, не соответствует свойствам данных, на которых она применяется.

Рассмотрим простой пример, который хорошо иллюстрирует проблему смещения распределения.

Интересная задача на понимание Distribution shift

Задача на смещение входных данных
Задача на смещение входных данных

Есть одна фича Х, таргет У.

На графике есть синие точки - обучающая выборка, оранжевые точки - тестовая выборка. Как будет выглядеть предикт моделей Linear Regression, KNN, Random Forest на тестовых данных?

Линейная регрессия

Она учит глобальную зависимость 

y = a*x+b

В отличие от RF и KNN, линейная регрессия — параметрическая модель.

Поэтому она просто продлит прямую дальше вправо.

Random Forest

Классические деревья не умеют экстраполировать… 

Если этих данных не было в обучающей выборке, то дерево будет предсказывать константу.

Если Х тестовой точки больше любого Х из трейна, то он попадет в самый правый лист, где лежат самые правые тренировочные точки.

Модель предскажет среднее из самых правых точек.

KNN

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

Вывод:

LR - параметрический, знает глобальную зависимость.

RF, KNN - непараметрические, знают только то, что видели.

Решение задачи
Решение задачи

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

Разберёмся, какие именно бывают типы таких изменений.

Виды смещений данных

Есть несколько видов смещений:

  • Смещение ковариат

Как раз то, что происходит на графике в задаче.

Изменилось распределение входных признаков.

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

Пример: если обновляется любой бизнес-классификатор или справочник категорий, добавляются новые значения. Модель, обученная на предыдущей версии справочника, не сталкивалась с этими категориями и начинает ошибаться.

  • Смещение меток

Изменилось распределение таргета. 

Если модель диагностики ковида обучали во время его вспышки, то сейчас эта же модель будет поголовно «короновать» пациентов, потому что думает, что болезнь встречается гораздо чаще, чем на самом деле она встречается сейчас.

  • Смещение концепта

Тут уже меняется взаимосвязь между данными и ответом. Правила игры поменялись.

Например, модель предсказывает предпочтения пользователей в соцсетях. Раньше видео с бомбардиро крокодило были популярны, и модель научилась тому, что таким видео обычно ставят «лайк». Но вот уже мода на брэйн-рот животных прошла, и пользователи стали дизлайкать такие видео. Модель об этом не в курсе.

На практике эти типы смещений часто встречаются одновременно, что усложняет их диагностику.

Мы разобрали, как именно может меняться распределение данных. Теперь посмотрим, почему это происходит в реальных системах.

Возможные причины смещения данных.

  • Дрейф данных во времени

Самый частый случай. Поведение пользователей, экономические показатели и погода постоянно меняются. Модель, построенная на прошлых данных, устаревает.

  • Изменение способа сбора данных

Заменили датчик на заводе (новый шум в данных), или изменили формат логов на сайте.

  • Неполное или смещенное представление выборки

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

  • Проблемы кросс-доменности

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

Все эти причины объединяет одно — модель начинает работать в условиях, отличных от тех, на которых она обучалась.

Поэтому ключевая задача в продакшене — вовремя заметить такие изменения.

Мониторинг смещения данных

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

Количество рассчитываемых метрик зависит от вашего доступного ресурса.

Если таргет доступен онлайн, можно считать метрику, которую вы использовали при обучении, например ROC-AUC. Если она значимо упала – это уже звоночек.

Если таргет приходит с лагом, сначала мониторят прокси-метрики и распределения.

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

Текущие данные сравнивают с baseline-периодом (reference window), например, обучающей выборкой или стабильным историческим окном.

Однако метрики — это уже следствие. Часто полезнее отслеживать изменения в самих данных.

Хорошим вариантом ещё будет посчитать PSI (Population Stability Index) – это метрика для измерения того, насколько сильно распределение одной переменной (например, предсказаний модели или признака) изменилось за период времени (или между двумя выборками).

Данные разбиваются на бины (обычно 10–20).

Для каждого бина считается доля наблюдений в базовом периоде (Expected) и в текущем периоде (Actual).

PSI рассчитывается как:

PSI = sum((A_i - E_i) * ln((A_i + ε) / (E_i + ε)))

где:

  • E_i — доля наблюдений в i-м бине в baseline (Expected)

  • A_i — доля наблюдений в текущем периоде (Actual)

  • ε — маленькая константа (например, 1e-6), чтобы избежать деления на ноль

Можно сравнивать распределение скоров и признаков, и если значение PSI превысило порог – выставить алерт.

На практике алерты часто настраивают на уровне отдельных признаков (feature-level monitoring), чтобы быстрее локализовать источник дрейфа.

Правила интерпретации (общепринятые):

  • PSI < 0.1 — незначительные изменения (No shift). Модель стабильна.

  • 0.1 ≤ PSI < 0.25 — умеренные изменения (Slight shift). Стоит начать мониторить причину.

  • PSI ≥ 0.25 — сильные изменения (Major shift). Модель «поехала», требуется вмешательство.

На входе также можно проверять сырые признаки, которые поступают в модель.

PSI — не единственный способ отслеживать изменения распределений. Существуют и классические статистические методы.

Статистические тесты распределений

Для числовых признаков:

  • Критерий Колмогорова-Смирнова (K-S test) — сравнивает две функции распределения. Минус — чувствителен к большим выборкам (может находить микроскопические, но практически незначимые различия).

  • Расстояние Вассерштейна (Earth Mover's Distance) — более информативный, чем K-S. Показывает, сколько «работы» нужно проделать, чтобы превратить одно распределение в другое.

Для категориальных признаков:

  • Хи-квадрат тест (Chi-squared test) — проверяет, связаны ли два множества категорий.

Также можно строить графики распределения, box-plot — иногда расхождение видно невооружённым глазом.

Для сложных моделей, таких как нейросети, можно пойти дальше и анализировать не только признаки, но и внутренние представления модели.

Если у вас нейросеть, можно взять представления последнего слоя (эмбеддинги перед функцией активации) и спроецировать их в 2D (например, через PCA, UMAP или t-SNE).

Затем раскрасить точки по времени (синие — train, красные — сегодняшние данные).

Мы сразу увидим, перемешаны ли они (шифта нет) или образуют отдельные кластеры (шифт есть).

Если визуального анализа недостаточно, можно формализовать задачу обнаружения сдвига.

Например, доменный классификатор.

Суть метода:

Берём старые (train) данные и метим их классом 0

Берём новые (продакшен) данные и метим их классом 1

Обучаем любой классификатор (например, логистическую регрессию или градиентный бустинг) отличать старые данные от новых

Анализ результатов:

  • Если ROC-AUC ≈ 0.5 — классификатор не может отличить старые данные от новых. Значит, распределения практически одинаковые — шифта нет.

  • Если ROC-AUC > 0.6–0.7 — модель начинает различать распределения. Значит, шифт есть.

Анализ важности признаков (Feature Importance) — самое ценное в этом методе.

Мы можем посмотреть, на какие именно признаки опирается классификатор, чтобы отличать старые данные от новых.

Если самый важный признак – например, время суток, возможно, просто изменился паттерн использования сервиса.

Если это ключевой бизнес-признак, то изменения серьёзные.

Окей, мы научились находить сдвиг. Теперь главный вопрос — что с этим делать?

Способы решения проблемы смещения данных

Переобучение

Один из самых простых и надежных способов — полное переобучение модели.

Важно регулярно переобучать модель, потому что данные могут меняться по дням и по часам.

Данные (особенно после 2020 года): мы изменились и больше никогда не будем прежними…

Но как часто нужно это делать? Существует несколько подходов.

Триггерный (trigger-based retraining)

Логично, что если данные сильно съехали здесь и сейчас, то надо срочно бежать переобучать модель. Либо сразу запускать автопереобучение, если оно вам доступно.

Плановый (Scheduled retraining)

Раз в какой-то период времени запускается процесс переобучения (ручной или автоматический).

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

Важное уточнение: новая обучающая выборка должна учитывать изменившееся распределение данных (это можно проверить статистическими критериями из прошлого поста).

Однако полное переобучение не всегда оптимально — иногда можно адаптировать существующую модель.

Трансферное обучение и дообучение

Мы не выбрасываем старую модель, а используем её как стартовую точку, подстраивая под новые данные.

Старая модель уже умеет извлекать полезные признаки, надо просто научить её обрабатывать новые. Нужно меньше данных, чем для полноценного обучения, к тому же это гораздо быстрее.

Модель помнит «как было», но учится работать с новой информацией.

Техники fine-tuning для нейросетей:

Полное дообучение

Размораживаем все веса и обучаем всю модель на новых данных.

Риск: если новых данных мало и они шумные, модель может переобучиться.

Дообучение последних слоев (Head tuning)

«Замораживаем» веса слоев извлечения признаков и обучаем только последний классификатор (голову).

Общие признаки остаются теми же, меняется только правило принятия решения на их основе.

Это более устойчиво к малому количеству данных.

Бустинги

Для бустингов подход немного отличается.

У бустингов классического дообучения, как в нейросетях, нет, но можно достроить ансамбль.

Мы берем старую модель и продолжаем обучение, добавляя новые деревья на новых данных (например, используя параметр init_model в XGBoost или LightGBM).

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

Если новых данных мало, модель может начать подстраиваться под их шум и специфику (переобучиться под новый домен), забывая общие закономерности.

Также можно использовать очень небольшое количество новых деревьев для корректировки модели.

Мы берем старую модель и дообучаем её на новых данных, но с жесткими ограничениями.

Например:

• параметр num_boost_round — добавляем не 100 новых деревьев, а 5–10.

Мы как бы говорим модели:

«Не переписывай старые знания, просто немного подправь финальный ответ».

Стэкинг старой и новой модели

Если мы хотим зафиксировать изначальную модель, можно собрать стекинг из новой и старой модели.

Шаг 1. Обучаем модель M_old на старых данных. Она выступает как «экстрактор признаков высокого уровня», выдавая свои прогнозы.

Шаг 2. Обучаем модель M_new только на новых данных. Она учится понимать сдвинувшееся распределение.

Шаг 3. Обучаем простую мета-модель (например, логистическую регрессию) на небольшом валидационном наборе новых данных.

Входом для неё будут предсказания M_old и M_new, а выходом — финальный ответ.

Мета-модель учится балансировать между:

  • «старым знанием» (M_old)

  • «новым знанием» (M_new)

Бонусный вариант для гигачадов

Иногда простые модели оказываются более устойчивыми к дрейфу.

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

И никакой дрифт не страшен!

В реальных системах обычно используется комбинация этих подходов:
мониторинг → детекция → адаптация модели.

Чем раньше вы замечаете сдвиг, тем дешевле его исправить.

Если интересны темы продакшн-ML, мониторинга моделей и похожие практические разборы, иногда пишу об этом в Telegram: t.me/data_suetistka

Комментарии (2)