Прогноз категории точный, закупка ошиблась: проверяем спрос на уровне SKU
На отчёте по категории прогноз продаж сошёлся с фактом. Через неделю склад обнаружил избыток одного товара и отсутствие другого. Это возможно даже при нулевой ошибке общего объёма: модель угадала сумму, но перепутала структуру спроса. Для закупки такая ошибка существенно важнее красивого графика категории.
Метрика должна отвечать на вопрос того, кто действует
Финансовый отдел планирует общий оборот, логистика — объём отгрузки, закупщик — конкретные артикулы. У этих решений разные единицы. Прогноз в штуках по группе товаров нельзя автоматически переводить в деньги или объём палет: для каждого товара потребуется цена или коэффициент упаковки. В примере все товары измеряются в одинаковых штуках, поэтому их суммы содержательно сопоставимы.
Сначала закрепите зерно исходной таблицы: один SKU за одну прогнозируемую неделю. У каждой строки должны быть фактический спрос, прогноз, категория и дата создания прогноза. Два запуска одной модели на одну неделю нельзя принимать за два независимых наблюдения. Для сравнения выбирайте одинаковый горизонт, например прогноз, сделанный за семь дней до начала недели.
После этого считайте качество на двух уровнях. Внизу видна ошибка ассортимента: абсолютные отклонения отдельных SKU. Наверху — ошибка объёма категории: сначала суммируются факты и прогнозы, затем берётся абсолютная разница. Если поменять порядок этих действий, получится другая метрика. Обе нужны, но подписи должны объяснять, какое решение они поддерживают.
Две модели, один общий объём
В следующем коде четыре товара двух категорий. Модель A переносит по тридцать единиц спроса между товарами одной категории. Модель B ошибается на пять единиц по каждому товару в одну сторону. Посмотрим, какой вариант выиграет при двух способах приёмки. Для запуска достаточно стандартного Python.
from collections import defaultdict
rows = [
("tea_black", "tea", 100, 130, 105),
("tea_green", "tea", 100, 70, 105),
("coffee_ground", "coffee", 50, 80, 55),
("coffee_beans", "coffee", 50, 20, 55),
]
for model, column in (("A", 3), ("B", 4)):
sku_abs = sum(abs(r[column] - r[2]) for r in rows)
totals = defaultdict(lambda: [0, 0])
for r in rows:
totals[r[1]][0] += r[2]
totals[r[1]][1] += r[column]
category_abs = sum(abs(pred - actual) for actual, pred in totals.values())
demand = sum(r[2] for r in rows)
short = sum(max(r[2] - r[column], 0) for r in rows)
excess = sum(max(r[column] - r[2], 0) for r in rows)
print(model, "SKU_abs", sku_abs, "category_abs", category_abs,
"SKU_WAPE", round(sku_abs / demand, 4),
"short", short, "excess", excess)
assert category_abs <= sku_abs
assert short + excess == sku_abs
Модель A получает нулевую абсолютную ошибку категорий, но сумму абсолютных ошибок SKU 120 и WAPE 0,4. Модель B имеет ошибку категорий 20 и такую же сумму ошибок SKU 20; её WAPE около 0,0667. Если закупка выполняется по артикулу, второй вариант в этом примере заметно полезнее. У A одновременно 60 недостающих и 60 избыточных единиц относительно фактического спроса.
Поля short и excess здесь описывают расхождение заказа, равного прогнозу, со спросом. Они не являются готовым расчётом потерянных продаж и складских остатков. Реальная закупка учитывает начальный запас, открытые поставки, сроки и ограничения партии. Чтобы оценить денежный эффект, передайте прогноз в одно и то же правило пополнения для обеих моделей и сравнивайте уже результат этого правила.
Как собрать отчёт, по которому выберут модель
Сохраните рядом качество по SKU и по категориям, а также вклад каждого товара в ошибку. Большой итоговый WAPE может быть вызван несколькими ходовыми позициями. Среднее процентных ошибок, наоборот, часто придаёт слишком большой вес малым продажам и требует отдельного решения для нулевого спроса. В нашем расчёте WAPE — сумма абсолютных ошибок SKU, делённая на суммарный спрос выбранного набора.
Повторите оценку на нескольких будущих периодах и выделите новые, сезонные и редкие товары. При смене категории используйте согласованный справочник на момент оценки, иначе изменения классификации будут выглядеть как движение спроса. Проверяйте полноту таблицы: исчезнувший SKU может улучшить метрику просто потому, что его сложный прогноз перестал участвовать в знаменателе.
Если прогнозы категории и SKU строятся разными моделями, проверьте, сходятся ли их суммы. Расхождение нужно явно разрешить до выдачи пользователям. Простой вариант — получать верхний прогноз суммированием нижних, как в примере. Более сложные методы согласования прогнозов стоит сравнивать на истории: арифметическая согласованность сама по себе ещё не обеспечивает высокое качество.
Перед финальной оценкой спроса отделите продажи от доступного покупателям объёма. При отсутствии товара наблюдаемые продажи могут быть ниже потребности, и модель, предсказавшая мало, получит искусственное преимущество. Сохраните признак доступности или используйте согласованную оценку неудовлетворённого спроса. Если такой оценки нет, покажите качество отдельно на периодах без дефицита и явно определите, что именно служит целевой величиной в текущем отчёте.
Уровни отчёта лучше согласовать с владельцами решений заранее. Категорийному менеджеру нужны общий объём и структура внутри категории, закупщику — недостающие конкретные позиции, планировщику склада — поступления в соответствующих упаковках. Тогда выбор модели не сводится к соревнованию двух процентов. Можно сформулировать правило приёмки: улучшение по SKU при допустимом отклонении общего плана, а спорные товары отправлять на отдельный разбор до выпуска заказа.
В платном курсе «Data Scientist: от данных до деплоя моделей» вы проходите постановку задачи, выбор метрик, обучение и анализ ошибок. Эти шаги помогают связать прогноз с действием закупщика и проверить новую модель до внедрения. Откройте программу курса и посмотрите, как оценка включается в полный цикл ML-проекта.
Продолжить на практике
- Data Scientist: от данных до деплоя моделей ↗
Практический курс по Data Science: от постановки ML-задачи и работы с данными до inference API, CI/CD и мониторинга моделей в продакшне. Вы пройдёте EDA, feature engineering, обучение и оценку моделей, experiment tracking, error analysis и deployment — чтобы собирать полноценный рабочий контур вокруг ML-решения.
