Что такое distribution drift и как его обнаружить (KS-test, PSI)?
Ответ от нейросети
sobes.tech AI
Что хотят услышать интервьюеры:
Distribution drift — это сдвиг распределения данных между обучением и продакшеном или между двумя периодами времени. Важно показать, что это не всегда означает падение качества, но часто является ранним сигналом риска. Для обнаружения обычно сравнивают статистики признаков и используют тесты вроде KS-test и метрики вроде PSI.
Определение:
Distribution drift — это изменение статистического распределения признака или набора признаков во времени, по сравнению с эталонным периодом. Обычно различают сдвиг входных данных, целевой переменной и связи между ними. На практике drift может возникать из-за сезонности, изменения поведения пользователей, новых источников данных или ошибок в пайплайне.
KS-test и PSI — два популярных способа проверить, насколько сильно отличаются распределения:
- KS-test сравнивает две выборки и измеряет максимальную разницу между их эмпирическими распределениями. Это хороший выбор для числовых признаков.
- PSI (Population Stability Index) измеряет, насколько изменились доли наблюдений по бинам между baseline и текущими данными. Его часто используют в мониторинге моделей, потому что метрика проста в интерпретации.
Пример использования:
Например, модель скоринга обучалась на данных прошлого года, а в продакшене начали приходить заявки из нового канала. Сначала проверяют ключевые признаки: доход, возраст, количество транзакций. Если по доходу KS-test дает малое p-value, а PSI превышает порог, это сигнал, что распределение изменилось и модель может деградировать.
import numpy as np
from scipy.stats import ks_2samp
# baseline и current - две выборки одного числового признака
baseline = np.array([10, 12, 13, 15, 18, 20, 21, 22, 25])
current = np.array([14, 15, 16, 18, 19, 23, 24, 26, 28])
# KS-test
stat, p_value = ks_2samp(baseline, current)
print("KS statistic:", stat)
print("p-value:", p_value)
# PSI
def psi(expected, actual, bins=10):
eps = 1e-6
breaks = np.percentile(expected, np.linspace(0, 100, bins + 1))
breaks[0] = -np.inf
breaks[-1] = np.inf
exp_counts, _ = np.histogram(expected, bins=breaks)
act_counts, _ = np.histogram(actual, bins=breaks)
exp_perc = np.maximum(exp_counts / len(expected), eps)
act_perc = np.maximum(act_counts / len(actual), eps)
return np.sum((act_perc - exp_perc) * np.log(act_perc / exp_perc))
print("PSI:", psi(baseline, current))
Пояснение кода:
Код показывает два шага проверки drift для числового признака.
-
ks_2samp(baseline, current)сравнивает две выборки и возвращает статистику KS и p-value.- Если p-value маленькое, гипотеза о том, что выборки из одного распределения, отвергается.
- Это не “величина дрейфа” в бизнес-смысле, а именно статистическая проверка различий.
-
Функция
psi(...):- строит бины по распределению baseline;
- считает долю наблюдений в каждом бине для baseline и current;
- сравнивает доли через логарифмическую формулу PSI.
-
Интерпретация:
- чем выше PSI, тем сильнее изменилось распределение;
- на практике используют пороги вроде “малый/умеренный/сильный drift”, но конкретные границы зависят от домена и критичности модели.
-
Важно, что PSI зависит от выбора бинов, поэтому для стабильного мониторинга бины нужно фиксировать и не пересчитывать каждый раз по текущим данным.
Ключевые моменты:
- Drift — это не только “данные стали другими”, но и потенциальный риск для качества модели.
- KS-test хорошо подходит для сравнения числовых распределений и дает статистическую значимость различий.
- PSI удобен для мониторинга в продакшене, потому что его легко считать и объяснять бизнесу.
- Для категориальных признаков чаще анализируют изменение долей по категориям, а не KS-test.
- Drift по признакам не всегда означает падение метрик модели, но это повод проверить качество, калибровку и стабильность пайплайна.
- Надежный мониторинг обычно сочетает несколько сигналов: drift по фичам, изменение таргета, качество модели и данные по сегментам.