У новой модели MAE меньше. Насколько результат зависит от нескольких клиентов?
Команда сравнивает две модели прогноза объёма отгрузки. Обе получили одни и те же заказы из отложенного месяца. У новой модели средняя абсолютная ошибка ниже. В отчёте видно, что большая часть выигрыша пришла от нескольких клиентов, у которых много заказов. Можно ли рассчитывать на такой же выигрыш, если состав клиентов окажется немного другим?
Сначала определяем, что измеряем
Для каждого заказа вычислим абсолютную ошибку новой и старой модели и вычтем старую из новой. Отрицательное число означает улучшение. Оба прогноза относятся к одному заказу и должны оставаться парой. Если отдельно выбирать случайные строки для каждой модели, первая может получить лёгкие заказы, а вторая сложные. Разброс такого сравнения будет отражать ещё и случайное различие задач.
Выберем целевую метрику. Если важна ошибка на случайном заказе, делим сумму разностей на число заказов. Если клиенты равноправны независимо от размера, сперва считаем среднюю разность на клиента, потом усредняем клиентов. Это разные вопросы. В примере основной результат относится к заказам. Среднее по клиентам покажем рядом, чтобы увидеть, насколько вывод зависит от веса больших групп.
Повторяем сравнение с разным составом клиентов
Заказы одного клиента могут походить друг на друга из-за договора, товарного профиля или адреса. Поэтому выбираем с возвращением целых клиентов. В каждом повторе берём столько клиентов, сколько было в контрольном наборе, вместе со всеми заказами каждого выбранного клиента. Если клиент выбран дважды, его суммы и число заказов учитываются дважды. Размер повторной выборки в строках меняется. Каждый раз нужно заново поделить на получившееся число заказов.
Ниже вклад уже свёрнут до суммы парных разностей и размера каждой группы. Для MAE этого достаточно, чтобы получить тот же результат, что при копировании строк. Если хотите повторить подход для F1, сохраняйте по группам необходимые компоненты матрицы ошибок и пересчитывайте F1 после суммирования. Среднее от готовых F1 групп дало бы другую величину.
from random import Random
from statistics import mean
# Заказы за один и тот же период: (id клиента, MAE старой,
# MAE новой, количество заказов). MAE здесь уже посчитаны по заказам.
clients = [
("A", 12, 9, 60), ("B", 8, 9, 12), ("C", 6, 7, 8),
("D", 7, 7.5, 10), ("E", 9, 8, 6), ("F", 5, 6.5, 4),
]
groups = [((new - old) * n, n) for _, old, new, n in clients]
def order_delta(sample):
return sum(total for total, _ in sample) / sum(n for _, n in sample)
rng = Random(173)
estimates = sorted(
order_delta(rng.choices(groups, k=len(groups)))
for _ in range(10000)
)
low = estimates[int(0.025 * (len(estimates) - 1))]
high = estimates[int(0.975 * (len(estimates) - 1))]
print(f"Разность на заказ: {order_delta(groups):.2f}")
print(f"Разность на клиента: {mean(total / n for total, n in groups):.2f}")
print(f"Процентильный диапазон: [{low:.2f}, {high:.2f}]")
assert order_delta(groups) < 0 < high and low < 0
Крупный клиент A тянет общую разницу в пользу новой модели. Когда в очередном повторе он не выпадает, положительные разности других клиентов становятся заметнее. В результате интервал пересекает ноль, хотя точечная оценка отрицательна. Здесь мало клиентов, и распределение повторов сильно зависит от каждого. Процентили показывают механизм и дают подсказку, какие группы смотреть в отчёте первыми.
Как связать результат с выпуском
Соберите по заказу фактический объём и оба прогноза с версиями моделей. Проверьте совпадение идентификаторов и покрытие: пропуски новой модели могут убрать самые трудные строки и улучшить MAE на пересечении. Число строк с обоими прогнозами должно быть видно рядом с метрикой. Отдельно сохраните сравнение для новых клиентов и долю выигрыша от крупнейших участников.
Группа должна отражать существенную зависимость. Если клиенты независимы лишь внутри одного календарного периода, а общие сбои поставок одновременно меняют ошибки всех, выбор клиентов не воспроизведёт разброс по неделям. Для вопроса о таких сбоях нужна проверка на новых временных блоках. Выберите минимальный полезный выигрыш до просмотра результата. Если даже нижняя ошибка на выбранном holdout слабо подтверждает нужный эффект, дополнительная выборка по клиентам и времени даст больше информации, чем тысячи новых bootstrap-повторов.
Практика на Latorn
В бесплатном тренажёре NumPy и pandas отработайте группировки через groupby. Они пригодятся для подготовки вкладов по клиентам в собственном отчёте.
На платном курсе «ML Engineer / Data Scientist» вы отработаете корректную валидацию, сравнение CatBoost и LightGBM и разбор ошибок через SHAP. Возьмите результаты двух моделей из такого эксперимента и проверьте, на каких клиентах держится выигрыш. Открыть программу курса.
Продолжить на практике
- ML Engineer / Data Scientist: табличные модели в продакшн ↗
Уже обучали модели на Python? Научитесь доводить их до работы в приложении: проверять качество без утечек, сравнивать CatBoost и LightGBM, объяснять прогнозы через SHAP и запускать модель через FastAPI. Практика на табличных данных, Docker, пакетный инференс и мониторинг.
