Прогноз продаж с помощью ИИ полезен ровно настолько, насколько честно он проверен на данных, которые модель не видела. Прогноз продаж в Excel и нейросетевой подсказке имеет смысл только при такой проверке. Ниже — воспроизводимая процедура: разбить историю на обучающую и отложенную части, зафиксировать методы и прогнозы до раскрытия факта, посчитать построчные ошибки и MAE. Всё построено на синтетических данных и простой базовой линии. Это не обучение нейросети и не клиентский кейс, а учебный стенд, на котором видно, что сложнее не значит лучше.
Ответ и результат сначала
На учебном отложенном периоде из двух недель наивная базовая линия дала MAE 11 шт./неделю, а простой drift-кандидат — 12. Разница в одну единицу на двух точках ничего не доказывает: это не вывод о превосходстве ИИ и не вывод о том, что базовый метод лучше всегда. Здесь проверена только арифметика на заранее зафиксированных прогнозах. Реального прогона языковой модели не было: оба промпта приведены как спецификация вычисления, а не как отчёт о выполненном запуске.
Почему такой порядок важен, хорошо видно по методике оценки прогнозных моделей: оценка — это построение прогнозов на тестовом множестве, отложенном от обучающих данных, и расчёт по ним метрик, которые направляют решения о внедрении модели (Inference and evaluation of forecasting models). Там же описан backtest — прогон обученного прогнозчика вперёд по тестовому множеству с усреднением ошибки по нескольким окнам. И отдельно сказано: в идеале тестовый период должен быть длинным относительно горизонта прогноза, иначе оценки ошибки могут быть статистически шумными и менее надёжными (Inference and evaluation of forecasting models). Наш двухточечный тест — пример такого короткого окна, и относиться к нему надо соответственно.
Полная история и split
Учебный пример — один SKU и восемь недельных точек. Шесть уходят в обучение, две — в отложенный период. Все восемь значений синтетические, пропусков нет, ноль означает подтверждённый ноль продаж, а не неизвестное значение.
| Дата | Продажи, шт. | Часть |
|---|---|---|
| 2026-01-05 | 10 | train |
| 2026-01-12 | 12 | train |
| 2026-01-19 | 14 | train |
| 2026-01-26 | 16 | train |
| 2026-02-02 | 18 | train |
| 2026-02-09 | 20 | train |
| 2026-02-16 | 22 | test |
| 2026-02-23 | 0 | test |
Границы split фиксируются до любого прогноза. Обучающая часть — строки с 2026-01-05 по 2026-02-09 включительно. Отложенная — 2026-02-16 и 2026-02-23. Горизонт — две недели. Origin — последняя дата обучения, 2026-02-09: более поздние фактические значения в построение прогноза не попадают. Так исключается утечка — ситуация, когда в расчёт прогноза подмешиваются данные из будущего.
Отдельно про ноль в последней строке. Это подтверждённое значение продаж, и его нельзя выбрасывать как «выброс» или «ошибку данных»: выкидывание нулевой строки завышает видимую точность. При этом фактический спрос по продажам не восстановить: остатки, акции, цены и потерянный спрос по этому SKU неизвестны, поэтому причина нуля не объясняется.
Промпт 1 и формулы
Методы выбираются до раскрытия теста. Их два, и оба простые.
Базовая линия — наивный прогноз: оба будущих значения равны последнему обучающему, то есть 20. Прогноз не обновляется фактом первой тестовой недели: origin один и фиксированный.
Кандидат — drift: последнее значение плюс шаг, умноженный на номер горизонта, где шаг равен разности последнего и первого обучающего значения, делённой на число интервалов между ними. Параметры берутся только из шести обучающих точек. Это заданный простой кандидат, а не обученная нейросеть. Шаг: (20 − 10) / 5 = 2. Прогноз на первую неделю: 20 + 2 × 1 = 22. На вторую: 20 + 2 × 2 = 24.
Замороженный прогноз до раскрытия теста:
| Дата | Базовая линия | Drift |
|---|---|---|
| 2026-02-16 | 20 | 22 |
| 2026-02-23 | 20 | 24 |
Полный промпт первой фазы, только по обучающим данным, без доступа к тесту:
Подготовь вычисление учебного прогноза двумя заранее заданными методами. Не обращайся к внешним данным, не подбирай метод по невидимому test. Верни для 2026-02-16 и 2026-02-23 при fixed origin 2026-02-09 прогноз baseline и drift, формулу/подстановку и ограничения. Если код не запускался, не сообщай, что выполнил его.
Методы и условия:
{"chosen_before_test": true, "horizon_weeks": 2, "baseline": "Наивный: оба будущих значения = последнему train 20. Не обновлять фактом первой test-недели: один fixed origin.", "candidate": "Drift: last + h*(last-first)/(n-1), h = 1/2; параметры получить только из 6 train-точек. Это заданный простой кандидат, не обученная нейросеть.", "metric": "MAE = сумма абсолютных ошибок / 2, единицы шт./неделю. MAPE в целом неопределён при хотя бы одном actual = 0; не выкидывать нулевую строку.", "history": "Синтетические известные продажи одного SKU; нет пропусков, 0 означает подтверждённый ноль, не unknown. Остатки/акции/цены/потерянный спрос неизвестны.", "governance": "Зафиксировать методы/origin до test. Изменение формул после вскрытия test — нечестная оценка этого же test; для нового выбора потребуется новый неиспользованный период."}
Полный train (date, units):
[["2026-01-05", 10], ["2026-01-12", 12], ["2026-01-19", 14], ["2026-01-26", 16], ["2026-02-02", 18], ["2026-02-09", 20]]
Те же расчёты в Excel. В A2:A7 — даты обучения, в B2:B7 — продажи, B7 = 20 — последнее обучающее значение. Прогноз базовой линии для обеих будущих дат:
=$B$7
Прогноз drift для первой будущей недели и для второй:
=$B$7+1*($B$7-$B$2)/(ROWS($B$2:$B$7)-1)
=$B$7+2*($B$7-$B$2)/(ROWS($B$2:$B$7)-1)
После ввода формулы локаль (разделитель аргументов и десятичный знак) объявляется до использования, иначе ROWS и дробная часть шага могут считаться по-разному на разных машинах. Абсолютные ссылки $B$7 и $B$2 держат origin и первое обучающее значение на месте при протягивании формулы вниз. Проверить формулы просто: результат должен совпасть с 20/20 и 22/24 из таблицы выше.
Выход первой фазы фиксируется до раскрытия теста — например, сохранением файла или сообщения с замороженным прогнозом и временем. Иначе появляется соблазн поправить метод после того, как стали известны факты, и оценка перестаёт быть честной.
Промпт 2 и весь эталон
Вторая фаза оценивает уже зафиксированные прогнозы по раскрытому факту и не меняет ни прогноз, ни методы. Раскрытые фактические продажи: 22 за 2026-02-16 и 0 за 2026-02-23.
Построчные ошибки — модуль разности факта и прогноза:
| Дата | Факт | Базовая линия | Drift | Ошибка базовой | Ошибка drift |
|---|---|---|---|---|---|
| 2026-02-16 | 22 | 20 | 22 | 2 | 0 |
| 2026-02-23 | 0 | 20 | 24 | 20 | 24 |
MAE базовой линии: (2 + 20) / 2 = 11 шт./неделю. MAE drift: (0 + 24) / 2 = 12 шт./неделю. В Excel ошибка строки — =ABS(факт - прогноз), MAE по двум строкам — =AVERAGE(две_ошибки).
MAPE здесь не считается: при фактическом нуле деление на ноль делает процентную ошибку неопределённой, поэтому метрика помечается как null. Нулевую строку из расчёта не удаляют — иначе изменится сам тест и пропадёт самый показательный случай.
Полный промпт второй фазы, самодостаточный, с замороженным прогнозом и раскрытым тестом:
Оцени уже зафиксированные прогнозы по последующему раскрытому факту. Не изменяй ни прогноз, ни методы. Выведи все 2 строки actual/forecasts/absolute errors, MAE для каждого метода и MAPE: null, если actual 0 есть. Сравни ошибки только данного test; не выводи причины или универсальный выигрыш ИИ.
Правила:
{"chosen_before_test": true, "horizon_weeks": 2, "baseline": "Наивный: оба будущих значения = последнему train 20. Не обновлять фактом первой test-недели: один fixed origin.", "candidate": "Drift: last + h*(last-first)/(n-1), h = 1/2; параметры получить только из 6 train-точек. Это заданный простой кандидат, не обученная нейросеть.", "metric": "MAE = сумма абсолютных ошибок / 2, единицы шт./неделю. MAPE в целом неопределён при хотя бы одном actual = 0; не выкидывать нулевую строку.", "history": "Синтетические известные продажи одного SKU; нет пропусков, 0 означает подтверждённый ноль, не unknown. Остатки/акции/цены/потерянный спрос неизвестны.", "governance": "Зафиксировать методы/origin до test. Изменение формул после вскрытия test — нечестная оценка этого же test; для нового выбора потребуется новый неиспользованный период."}
Полный frozen forecast:
[{"date": "2026-02-16", "baseline": 20, "drift": 22}, {"date": "2026-02-23", "baseline": 20, "drift": 24}]
Полный test (date, units):
[["2026-02-16", 22], ["2026-02-23", 0]]
Ограничения и следующий период
Что этот стенд позволяет утверждать: на двух зафиксированных точках базовая линия ошиблась меньше, чем drift, на 1 шт./неделю по MAE. Что он не позволяет: утверждать, что ИИ хуже или лучше, что drift не работает, что ноль продаж вызван падением спроса или что модель будет точной в будущем.
Причинная история отсутствует. Продажи без данных об остатках не восстанавливают фактический спрос, поэтому нулевую неделю нельзя трактовать как обвал или как дефект данных. Две тестовые точки слишком малы для обобщения — в идеале тестовый период должен быть длинным относительно горизонта прогноза, иначе оценки ошибки могут быть статистически шумными и менее надёжными (Inference and evaluation of forecasting models). Промпты языковой модели не запускались, обучения нейросети и подбора модели не было.
Правило после теста: менять метод по результатам уже раскрытого периода нельзя — это подгонка под тот же test. Для нового выбора нужен новый неиспользованный holdout, зафиксированный до раскрытия. Для будущего исследования имеет смысл задать более длинные rolling-окна: несколько перекрывающихся окон с фиксированным контекстом, горизонтом и шагом, с усреднением ошибки по окнам. Так оценка перестаёт зависеть от одной пары точек.
Порядок повторения на своих данных: разбить историю по дате, зафиксировать origin и методы, получить и сохранить прогноз, только потом раскрыть факт, посчитать построчные ошибки и MAE, не выбрасывать нулевые строки. Смежные задачи — анализ маркетинговых данных с нейросетью и когортный анализ.

