Новая модель выиграла 1%: как проверить устойчивость разницы на тех же объектах

Две модели посчитали прогнозы на одинаковом тесте. Вместо сравнения двух отдельных интервалов оценим разность ошибок на тех же объектах с помощью парного bootstrap.

Объект должен оставаться одним и тем же в обеих версиях

У старой модели MAE 12,4, у новой — 12,2. Улучшение есть в отчёте, но команда хочет понять, насколько оно устойчиво к составу тестовых объектов. Само по себе отличие на две десятых ещё не показывает, будет ли преимущество повторяться. Особенно если несколько крупных ошибок определяют весь итог.

Для каждой строки посчитайте абсолютную ошибку старой и новой версии, затем разность «новая минус старая». Отрицательное среднее означает выигрыш новой модели. Такой парный расчёт сохраняет сложность конкретного объекта: трудный заказ остаётся трудным для обеих моделей. Независимое перемешивание двух списков ошибок теряет эту информацию.

Bootstrap многократно выбирает объекты из теста с возвращением и пересчитывает среднюю разность. Процентили полученных средних дают приблизительный интервал. Он описывает неопределённость из-за выборки объектов при выбранной процедуре, а не изменения рынка, будущие релизы признаков или ошибочные метки.

Рассчитаем интервал разности потерь

В учебном примере восемь независимых объектов. Новая модель в основном уменьшает ошибку, но на двух строках немного проигрывает. Генератор имеет фиксированное зерно для воспроизводимости. Код использует стандартную библиотеку; для более сложных схем можно обратиться к scipy.stats.bootstrap, где поддерживается парная выборка.

Мы берём ближайшие порядковые статистики из 5000 повторений как границы 95-процентного percentile-интервала. Для небольшого набора такой расчёт прежде всего показывает механику. В рабочей задаче проверьте объём, зависимость наблюдений и чувствительность к отдельным объектам.

from random import Random
old_errors = [12, 8, 15, 5, 10, 9, 20, 7]
new_errors = [10, 7, 12, 6, 8, 7, 16, 8]
differences = [n-o for n, o in zip(new_errors, old_errors)]
rng = Random(42)
means = sorted(sum(rng.choices(differences, k=len(differences))) /
               len(differences) for _ in range(5000))
observed = sum(differences) / len(differences)
low, high = means[125], means[4874]
print("delta MAE:", observed)
print("percentile interval:", low, high)
assert observed == -1.5
assert low <= observed <= high < 0

Наблюдаемая разность равна −1,5. В этом наборе обе границы интервала отрицательны: преимущество сохраняется в большей части повторных выборок. Число 1,5 выражено в единицах целевой переменной. Чтобы решить вопрос о внедрении, сопоставьте его с расходами: более тяжёлая модель может требовать больше вычислений, а выигрыш не окупать задержку.

Если в тесте несколько заказов одного клиента, нельзя считать их независимыми строками. Выбирайте клиентов с возвращением и включайте все их заказы, после чего рассчитывайте нужную агрегированную метрику. При временной зависимости потребуется схема, сохраняющая временные блоки. Иначе интервал получится неоправданно узким.

Ещё одна граница — выбор самой модели. Если новая версия победила среди сотни экспериментов на этом же тесте, парный bootstrap не возвращает тесту независимость. Сначала выбирайте конфигурацию по валидации, затем сравнивайте финальные версии на отложенных данных. Историю выбора стоит сохранить рядом с результатом.

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

Для следующего шага пригодится зависимость строк одного клиента.

В платном курсе «ML Engineer / Data Scientist: табличные модели в продакшн» вы будете сравнивать модели по подходящим метрикам и вести воспроизводимую историю экспериментов. В результате останутся отчёты, на которых можно обосновать выбор версии и следующий шаг разработки. Откройте программу курса.

Продолжить на практике

  • ML Engineer / Data Scientist: табличные модели в продакшн ↗

    Практический курс для тех, кто хочет получить навыки ML Engineer / Data Scientist на реальных табличных задачах. В курсе Вы не просто обучите CatBoost/LightGBM, а соберёте полноценный production-style пайплайн: подготовка данных, feature engineering (генерация признаков), корректная валидация, защита от leakage (утечек), тюнинг через Optuna, интерпретация через SHAP, batch-инференс и REST API для предсказаний.