Наш обзор повторяющихся проблем, возникающих в проекте прогнозирования продаж, и того, как мы справлялись с ними в конкурсе M5.

TL;DR

В этой статье мы суммируем наши выводы из конкурса прогнозирования продаж M5, который заключался в прогнозировании будущих продаж в нескольких магазинах Walmart. Мы познакомим вас с нашим решением и обсудим следующие темы:

  • Какая модель машинного обучения лучше всего подходит для этой задачи?
  • Какие функции обладали наибольшей прогностической силой?
  • Как справиться с набором данных с прерывистыми продажами?
  • Как справиться с расширенным горизонтом прогнозирования?
  • Как обеспечить надежность модели с помощью соответствующей перекрестной проверки?

Использование машинного обучения для решения бизнес-задач ритейлеров

Точное прогнозирование продаж имеет решающее значение для розничных компаний, чтобы производить необходимое количество в нужное время. Но даже если одной из их главных забот является предотвращение потерь и дефицита, у розничных продавцов есть еще много возможностей для совершенствования. По крайней мере, так думают люди, работающие в Walmart, когда в марте 2020 года они запустили задачу по науке об открытых данных - соревнование M5 - чтобы увидеть, как они могут улучшить свои модели прогнозирования.

Конкурс был направлен на прогнозирование будущих продаж на уровне продукта на основе исторических данных. Более 5000 команд любителей данных и экспертов по прогнозированию в течение нескольких месяцев обсуждали методы, функции и модели, которые лучше всего подходят для решения этой хорошо известной проблемы машинного обучения. Эти дискуссии выявили некоторые повторяющиеся проблемы, встречающиеся почти во всех проектах прогнозирования. И что еще более важно, они предложили широкий спектр подходов к их решению.

В этой статье делается попытка обобщить некоторые ключевые выводы, полученные в результате выполнения этой задачи. В Artefact мы верим в обучение на собственном опыте, поэтому мы решили сделать снимок и написать собственное решение, чтобы проиллюстрировать его. Теперь давайте рассмотрим весь процесс прогнозирования и остановимся, чтобы понять, что сработало, а что нет.

Описание проблемы

Иерархическое прогнозирование временных рядов

Набор данных содержит 5-летние исторические продажи различных продуктов и магазинов с 2011 по 2016 год. Предоставляется некоторая дополнительная информация, например цены продажи и календарные события. Данные организованы иерархически: магазины разделены на 3 состояния, а продукты сгруппированы по категориям и подкатегориям.

Наша задача - спрогнозировать продажи для всех товаров в каждом магазине в дни сразу после доступного набора данных. Это означает, что необходимо сделать 30 490 прогнозов на каждый день в горизонте прогнозирования.

Эта иерархия будет определять наш выбор моделирования, поскольку взаимодействия внутри категорий продуктов или магазинов содержат очень полезную информацию для целей прогнозирования. Действительно, товары в одних и тех же магазинах и категориях могут иметь схожую эволюцию продаж или, наоборот, каннибализировать друг друга. Поэтому мы собираемся описать каждую выборку с помощью функций, которые фиксируют эти взаимодействия, и отдать приоритет подходам на основе машинного обучения по сравнению с традиционными методами прогнозирования, чтобы учитывать эту информацию при обучении модели.

Две основные проблемы: прерывистые значения и расширенный горизонт прогнозирования

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

Во-первых, временные ряды, с которыми мы работаем, имеют множество периодических значений, то есть длительные периоды последовательных дней без продаж, как показано на графике ниже. Это может быть связано с дефицитом или ограниченным количеством полок в магазинах. В любом случае это усложняет задачу, поскольку погрешность будет стремительно расти, если продажи прогнозируются на регулярном уровне, пока товар отсутствует на полках.

Второй - от самой задачи, а точнее от размера горизонта прогноза. От конкурентов требуется составлять прогнозы не только на следующую неделю, но и на 4-недельный период. Вы бы предпочли полагаться на прогноз погоды на следующий день или на 1 месяц сейчас? То же самое и с прогнозированием продаж: расширенный горизонт прогнозирования усложняет задачу, поскольку со временем увеличивается неопределенность.

Разработка функций - моделирование движущих факторов продаж

Теперь, когда мы поняли стоящую перед нами задачу, мы можем приступить к вычислению характеристик, моделирующих все явления, которые могут повлиять на динамику продаж. Задача состоит в том, чтобы описать каждый тройной день x продукт x магазин набором показателей, которые отражают влияние таких факторов, как сезонность, тенденции или цены.

Сезонность

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

Календарные события, такие как праздники или финалы НБА, также имеют сильное сезонное влияние. Для каждого события была создана одна функция со следующими значениями:

  • Отрицательные значения за 15 дней до события (от -15 до -1)
  • 0 в день Д
  • Положительные значения в течение 15 дней после события (от 1 до 15)
  • Нет стоимости в периоды более 15 дней до события

Идея состоит в том, чтобы смоделировать сезонное воздействие не только на день «Д», но также до и после него. Например, продукт, который будет много предлагать в качестве рождественского подарка, испытает пик продаж в предыдущие дни и упадет сразу после этого.

Тенденции

Последние тенденции также предоставляют полезную информацию о будущих продажах и моделируются с помощью функций задержки. Запаздывание - это значение целевой переменной, сдвинутое на определенный период. Для любого конкретного товара в данном магазине значение задержки в 1 неделю будет соответствовать продажам, сделанным неделю назад для этого конкретного товара и магазина. Можно рассматривать различные значения сдвига, а также вычислять среднее значение нескольких задержек, чтобы получить более надежные предикторы. Лаги также могут быть рассчитаны для агрегированных продаж, чтобы уловить более глобальные тенденции, например, на уровне магазина или на уровне категории продукта.

Стоимость

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

  • Относительная разница между текущей ценой товара и его исторической средней ценой, чтобы подчеркнуть влияние рекламных предложений.
  • Относительная разница в цене с тем же товаром, продаваемым в других магазинах, чтобы понять, есть ли у этого магазина привлекательная цена.
  • Относительная разница в цене с другими товарами, продаваемыми в том же магазине и той же категории товаров, чтобы учесть некоторые эффекты каннибализации.

Кодировка категориальных переменных

Категориальные переменные, такие как состояние, магазин, название продукта или его категория, также обладают значительной прогностической силой. Эта информация должна быть закодирована в функции, чтобы модель могла использовать иерархию наборов данных. Одноразовое кодирование здесь не вариант, потому что некоторые из этих категориальных переменных имеют очень высокую мощность (3049 различных продуктов). Вместо этого мы использовали упорядоченную целевую кодировку, что означает, что каждое наблюдение кодируется средними продажами прошлых наблюдений с одинаковым категориальным значением. Набор данных упорядочен по времени для этой задачи, чтобы избежать утечки данных.

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

Одна модель LightGBM на магазин

Теперь, когда у нас есть возможности, перейдем к моделированию. LightGBM - один из великих победителей конкурса M5, поскольку он использовался в большинстве лучших решений. Мы выбрали эту модель из-за ее высокой скорости и низкого использования памяти.

Поскольку это древовидный метод, он должен иметь возможность изучать разные шаблоны для каждого магазина в зависимости от их специфики. Однако мы заметили, что обучение модели с выборками только из одного хранилища привело к небольшому увеличению точности прогнозов. Поэтому мы решили обучить 10 различных моделей LightGBM, по одной для каждого магазина, что также позволило сократить общее время обучения.

Tweedie loss для работы с непостоянными значениями

Для решения проблемы прерывистых значений могут использоваться различные возможные стратегии. Некоторые участники решили создать 2 отдельные модели: одну для прогнозирования того, будет ли продукт доступен в определенный день, а вторую - для прогнозирования продаж. Как и многие другие, мы выбрали другой вариант, основанный на целевой функции, адаптированной к проблеме: потеря твида.

Не вдаваясь в математические подробности, давайте попробуем понять, почему эта функция потерь подходит для нашей задачи, сравнив распределение продаж в данных обучения и распределение твиди:

Они выглядят очень похоже, и оба имеют значения, сконцентрированные вокруг 0. Установка потери твида в качестве целевой функции в основном вынуждает модель максимизировать вероятность этого распределения и, таким образом, предсказывать правильное количество нулей. Кроме того, эта функция потерь имеет параметр, значения которого находятся в диапазоне от 1 до 2, который можно настроить в соответствии с распределением рассматриваемой проблемы:

Основываясь на нашем распределении набора данных, мы можем ожидать, что оптимальное значение будет между 1 и 1,5, но, чтобы быть более точным, мы настроим этот параметр позже с помощью перекрестной проверки. Эта целевая функция также доступна для других моделей повышения градиента, таких как XGBoost или CatBoost, поэтому ее определенно стоит попробовать, если вы имеете дело с прерывистыми значениями.

Как сделать прогноз на 28 дней вперед?

Максимальное использование функций задержки

Как объяснялось выше, характеристики лага - это продажи, сдвинутые на определенный период времени. Таким образом, их значения зависят от того, где вы находитесь в горизонте прогнозирования. Продажи, сделанные в конкретный день D, можно рассматривать как задержку в 1 день, если вы прогнозируете на один день вперед, или как задержку в 28 дней, если вы прогнозируете 28 дней вперед. Следующая диаграмма иллюстрирует этот момент:

Эта концепция важна для понимания того, какие функции будут доступны во время прогноза. Здесь у нас день D, и мы хотели бы спрогнозировать продажи на следующие 28 дней. Если мы хотим использовать одну и ту же модель - и, следовательно, одни и те же функции - для прогнозирования всего горизонта прогнозирования, мы можем использовать только те задержки, которые доступны для прогнозирования всех дней между D + 1 и D + 28. Это означает, что если мы используем функцию задержки в 1 день для обучения модели, эту переменную также необходимо будет заполнить для прогнозов на D + 2, D + 3,… и D + 28, тогда как она относится к датам в будущем. .

Тем не менее, задержки, вероятно, являются функциями с самой большой прогностической силой, поэтому важно найти способ максимально эффективно использовать эту информацию. Мы рассмотрели 3 варианта решения этой проблемы, давайте посмотрим, как они работают.

Вариант 1. Одна модель на все недели

Первый вариант наиболее очевиден. Он заключается в использовании одной и той же модели для прогнозирования всех недель в горизонте прогнозирования. Как мы только что объяснили, это связано с огромным ограничением: можно использовать только функции, доступные для прогнозирования на D + 28. Следовательно, мы должны избавиться от всей информации, предоставленной 27 последними задержками. Обидно, что самые свежие лаги также являются наиболее информативными, поэтому мы рассмотрели другой вариант.

Вариант 2. Еженедельные модели

Эта альтернатива заключается в обучении разной модели LightGBM каждую неделю. На диаграмме выше каждая модель учится на самых последних возможных задержках по отношению к ограничению, налагаемому ее горизонтом прогнозирования. Следуя той же логике, что и предыдущий вариант, это означает, что каждая модель может использовать все задержки, кроме тех, которые новее, чем самый дальний день для прогнозирования. Точнее:

  • Модель 1 делает прогнозы на 1–7 дни, основываясь на всех лагах, кроме 6 самых последних.
  • Модель 2 делает прогнозы на 8–14 дни, основываясь на всех лагах, кроме 13 самых последних.
  • Модель 3 делает прогнозы на 15–21 день, основываясь на всех лагах, кроме 20 самых последних.
  • Модель 4 делает прогнозы на 22–28 дни, основываясь на всех лагах, кроме самых последних 27, как и в варианте 1.

Этот метод позволяет нам лучше использовать информацию о задержках в течение первых 3 недель и, таким образом, повысить точность прогнозов нашего решения. Это того стоило, потому что это был конкурс Kaggle, но для промышленного проекта также следует учитывать вопросы сложности, обслуживания и интерпретируемости. Действительно, этот вариант может быть дорогостоящим с точки зрения вычислений, и если мы нацелены на развертывание в масштабе всей страны, это потребует поддержки сотен моделей в реальном времени. В этом случае необходимо оценить, достаточно ли приращение производительности, чтобы оправдать эту более сложную реализацию.

Вариант 3. Рекурсивное моделирование

В последнем варианте также используются недельные модели, но на этот раз рекурсивным образом. Рекурсивное моделирование означает, что прогнозы, созданные для данной недели, будут использоваться в качестве функций задержки на следующие недели. Это происходит последовательно: сначала мы делаем прогнозы на первую неделю, используя все задержки, кроме 6 самых последних. Затем мы прогнозируем 2-ю неделю, используя наши предыдущие прогнозы в качестве 1-недельных лагов, вместо того, чтобы исключать больше лагов, как в варианте 2. Повторяя тот же процесс, мы всегда получаем последние доступные задержки, даже для недель 3 и 4, что позволяет нам использовать эту информацию для обучения моделей.

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

Обеспечение устойчивости модели с помощью соответствующей перекрестной проверки

Почему перекрестная проверка важна для временных рядов

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

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

Адаптация процесса проверки к актуальной проблеме

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

Сгибы 1, 2 и 3 направлены на определение параметров, которые могли бы обеспечить максимальную эффективность за последние периоды, в основном за последние 3 месяца. Проблема в том, что эти 3 месяца могут иметь другие особенности, чем предстоящий период, который мы готовы спрогнозировать. Например, представим, что магазины запустили огромный рекламный сезон за последние несколько месяцев, а сегодня он прекратился. Эти продвижения, вероятно, повлияют на поведение модели, но было бы рискованно полагаться только на эти недавние периоды, чтобы настроить ее, потому что это не репрезентативно для того, что будет дальше.

Чтобы уменьшить этот риск, мы также включили складки 4 и 5, которые соответствуют периоду прогноза, сдвинутому соответственно на 1 и 2 года. Эти периоды, вероятно, будут похожи, поскольку проблема имеет сильную годовую сезонность, что часто бывает в розничной торговле. Если бы у нас была другая периодичность, мы могли бы выбрать любую стратегию перекрестной проверки, которая имеет больше бизнес-смысла. В конце концов, мы выбрали комбинацию гиперпараметров с наименьшей ошибкой из 5 крат для обучения окончательной модели.

Результаты

Различные методы, упомянутые выше, позволили нам достичь 0,59 взвешенного RMSSE - показателя, используемого в Kaggle, - что эквивалентно точности взвешенного прогноза 82,8%. На приведенной ниже диаграмме суммирована дополнительная производительность на каждом этапе:

Эти цифры являются ориентировочными: возрастающая точность также зависит от порядка, в котором выполняется каждый шаг.

Основные выводы

Мы многому научились из этой задачи благодаря обмену мнениями участников, и мы надеемся, что это также дало вам пищу для размышлений. Вот наши основные выводы:

  • Работайте с небольшим, но репрезентативным подмножеством данных для быстрой итерации.
  • Будьте предельно осторожны с утечкой данных в процессе разработки функций: убедитесь, что все функции, которые вы вычисляете, будут доступны во время прогнозирования.
  • Выберите архитектуру модели, которая позволяет максимально эффективно использовать задержки, но при этом не забывайте о сложности, если вы хотите перейти к производству.
  • Настройте стратегию перекрестной проверки, адаптированную к вашей бизнес-проблеме, чтобы правильно оценивать эффективность ваших экспериментов.

Большое спасибо за то, что дочитали до этого момента, и не стесняйтесь обращаться, если у вас есть какие-либо комментарии по теме! Вы можете посетить наш блог здесь, чтобы узнать больше о наших проектах машинного обучения.