Чистим «засоры» на товарных полках в ритейле. Недорого

Чистим «засоры» на товарных полках в ритейле. Недорого

Всем привет! Меня зовут Егор. Я представляю команду аналитиков прекрасного коллектива Эрманн, одного из лидеров рынка России в категории современной молочной продукции (густые и питьевые йогурты, твороженные десерты, пудинги и др.) .

В данной публикации я хотел бы поделиться нашим опытом борьбы с довольно известной на FMCG-рынке проблемой «виртуальных стоков", возникающей непосредственно в ритейловых торговых точках. Сразу оговорюсь, что на момент написания публикации мы только вступаем в активный rolll-out решения в "поля», и сами с нетерпением ждем первых результатов проекта. Дальнейшую рефлексию планируем изложить в последующей части этой темы. Сейчас же мы представляем описание самой проблемы и теоретическую выкладку ее решения.

Виртуальный сток: что за зверь и чем опасен?

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

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

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

Почему на торговых полках может возникать ситуация «запаса достаточно»?

  1. Естественная причина: товар не продается => цифра запаса товара не двигается => системе автозаказа нет резона запрашивать дополнительную поставку продукта => подходит срок годности продукта => товар списывается == ритейлер несет убытки.

    Будьте уверены, через некоторое время такой продукт с низкой оборачиваемостью будет выведен из ассортиментной матрицы ритейлера.

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

    И тут мы входим в мертвый цикл: товара в торговой точке нет => продаваться нечему => система не заказывает товар => товара в торговой точке нет…

    Мне нравится аналогия с засором: оборачиваемость продукции отсутствует, так как сток, по мнению системы автозаказа, забит товаром.

Причинами возникновения виртуального стока обычно служат разного рода ошибки в учетных системах торговых точек:

  • пересортица товара — вместо одного товара продали другой;
  • некорректная приемки товара;
  • недопоставок — в программе зафиксировано большее количество товаров, чем поставлено и т. д.

Формируем задачу и предвкушаем профит

Наша цель — научиться детектировать факт виртуального стока для конкретного продукта в конкретной торговой точке и устранять его. Тем самым мы сможем предотвратить ситуации искусственного снижения оборачиваемости наших продуктов и не допустить ухудшения их рейтинга в ассортиментной матрице ритейлера, что в свою очередь позволит сохранять стабильный уровень дистрибуции наших брендов. И, конечно, вовремя пойманный и устраненный виртуальный сток позволяет сократить число потенциальных дней без продаж — прямой путь к увеличению продаж!

Далее в статье мы концентрируемся только на первом этапе задачи — как определять виртуальный сток.

Коротко об этапе устранения виртуального стока

Чтобы устранить виртуальный сток, необходимо физическое присутствие в торговой точке. Для этого мы пользуемся сервисом мерчандайзинга.
Дополнительная (в ходе визита проводится ряд мероприятий по работе с товарной полкой) задача "проверить виртуальный сток по продукту X в торговой точке по адресу Y" поступает к мерчандайзеру в мобильное приложение на телефон. Далее от мерчандайзера мы получаем обратную связь в виде закрытой задачи после посещения. Примечательно и важно, что никакой дополнительной стоимости к визиту данная задача не несет.

Что нам поможет определять виртуальный сток?

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

Старт потока рассуждений

Исходя из сущности виртуального стока (товар числится в системе с остатками в торговой точке, но на самом деле он отсутствует), мы можем предположить, что если на протяжении n дней мы не видим никаких изменений цифры остатков продукта в торговой точке, то значит сток «встрял», и мы поймали нужный нам кейс. Логично, что и продаж в эти дни мы тоже не увидим, так как в противном случае цифра остатков бы сдвинулась (продажа сокращает остаток).

Главный вопрос: как определить нужный параметр n дней?

Путь наименьшего сопротивления

Мы можем пойти простым путем и установить (экспертно) общий детерминированный порог n дней равный, допустим, 7-и дням. Как только в конкретной торговой точке по конкретному продукту нет продаж и
цифра товарного запаса остается прежней в течение 7-и дней, мы обозначаем этот кейс как виртуальный сток и транслируем его на этап устранения.

Простой и понятный подход, да и какой-то процент виртуальных стоков будет в действительности определен правильно.

Однако, сразу бросается недостаток метода — сверх обобщение. Сложно представить, что отметка "7 дней" будет серебряной пулей для каждой комбинации торговая точка/продукт, а именно на таком уровне детализации мы планируем работать. В теории для каждой торговой точки и продукта может быть свой порог, когда стоит бить тревогу о виртуальном стоке.

Конечно, можно добавить немного сложности и для каждого продукта из нашего ассортимента рассчитывать свой порог. Это придаст гибкости решению, но повлечет за собой ряд дополнительных вопросов: «как и как часто пересчитывать значение порогов?", "как учитывать региональную специфику торговых точек?", »как разные форматы торговых точек повлияют на оцениваемый порог?" и т.д.

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

Наш вероятностный путь

Мы поставили перед собой задачу оценивать вероятность виртуального стока для каждого конкретного случая в детализации торговая точка/продукт. Для этого мы вводим несколько метрик (речь о них пойдет дальше) , которые могут принимать значения в диапазоне от 0 до 1, где 1 — это сильная уверенность в наличие виртуального стока (быть уверенным в чем-то на 100% незаконно). Когда обе метрики достигают порога 0.95 (экспертная оценка) , то для нас это сигнал к объявлению виртуального стока для данного продукта в конкретной торговой точке.

Нам нет смысла просчитывать вероятности каждый день для всех продуктов во всех торговых точках. Мы рассматриваем только претендентов на виртуальный сток. Стать претендентом очень просто — продукту нужно просто единожды не продаться в день в торговой точке. Для нас это сигнал (триггер) к созданию специальной сущности -кейса. Далее в рамках этого кейса мы мониторим «поведение" продукта в торговой точке до того момента, пока не наступает естественный триггер на закрытие кейса (случилась продажа/ цифра запаса товара изменилась), либо вышеупомянутые вероятностные метрики кейса не достигают заветных 95% процентов, и он, получая лейбл "виртуальный сток», переходит на этап устранения.

Мониторинг кейса происходит в системе ежедневно путем пересчета вероятностных метрик. Одним из основных параметром в расчетах выступает продолжительность (возраст) кейса в днях. Логично, что при увеличении продолжительности кейса, увеличивается и вероятность попадания продукта в виртуальный сток. Также на скорость достижения порога в 95% в обеих метриках оказывает влияние выбранная нами кумулятивная функция с параметрами, на которых она построена. Оценка этих параметров как раз и позволяет нам говорить, что мы кастомно рассматриваем каждый кейс для комбинации торговая точка/продукт.

Внутри кейса

Все еще проще иллюстрируется на примере.

День № 1

Давайте представим, что наступает новый день (первый день) , к нам в систему передана новая порция данных за вчерашний день, и мы видим, что в магазине Y не было продаж продукта X. Это событие-триггер на создание кейса с новым case_id. Пускай case_id = 1

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

  1. Интенсивность продаж (sales intensity): считаем средние ежедневные продажи в штуках продукта X в торговой точке Y за 60 последних дней, исключая периоды промо-акций (это возможно сделать на уровне поставляемых ритейлером данных) . Период промо-акции подразумевает повышенные продажи, которые могут завысить наш показатель интенсивности. Предположим, что sales intensity = 0.73 (в день ожидаем в среднем проданными 0.73 штуки). Нет ничего страшного в том, что значение интенсивности — десятичная дробь.

  2. Частота продаж (sales frequency): считаем отношение дней с продажами продукта X в торговой точке Y к общему числу дней
    в анализируем периоде (60 дней) , исключая периоды промо-акций (это возможно сделать на уровне поставляемых ритейлером данных) . Период промо-акции подразумевает повышенную частоту продаж, которая завысит типичный показатель. Предположим, что sales frequency = 0.45 (факт продаж происходит чуть реже чем 1 раз в 2 дня).

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

    Также записываем цифру запаса остатков (stock value) продукта X в магазине Y. На протяжении жизненного цикла кейса мы каждый день будем сличать цифру остатка, так как в случае ее изменения мы ловим триггер на закрытие кейса. Предположим, что сейчас в запасах находится 16 штук товара X, т. е. stock value = 16.

День №1: фиксируем параметры первого дня без продаж
День №1: фиксируем параметры первого дня без продаж

Теперь настала очередь вероятностных метрик.

Sales absence probability (вероятность продать 0 штук продукта Х при текущей интенсивности продаж). Мы делаем допущение, что ежедневные продажи в штуках — это случайная величина распределенная по Пуассону (распределение Пуассона) с параметром λ, который равен уже ранее рассчитанному показателю интенсивности продаж (sales intensity) и переменной x = 0, так как нас интересует вероятность продать 0 штук.

Функция вероятности распределения Пуассона:

Чистим «засоры» на товарных полках в ритейле. Недорого

Можно воспользоваться онлайн-калькулятором: ссылка

<i>Вероятность продать 0 штук при интенсивности продаж 0.73 штуки в день</i>
Вероятность продать 0 штук при интенсивности продаж 0.73 штуки в день

Подставим значения в формулу:

Чистим «засоры» на товарных полках в ритейле. Недорого

Стоит отметить, что значение sales absence probability (0.48) будет закреплено за кейсом на каждый день в течение всего его жизненного цикла, а сам показатель является промежуточным, служащим для расчета следующей метрики.

Empty shelf probability («вероятность пустой полки»). Виртуальный остаток подразумевает под собой отсутствие продукта на товарной полке в реальности. С помощью метрики empty shelf probability мы оцениваем вероятность того, что при текущей интенсивности продаж (sales intensity) и вероятности нулевых продаж (sales absence probability) серия дней с нулевыми продажами затянется на n дней.

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

Чистим «засоры» на товарных полках в ритейле. Недорого

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

Формула для empty shelf probability будет выглядеть так:

где <b>n</b> - продолжительность (возраст) кейса в днях.
где n - продолжительность (возраст) кейса в днях.

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

1 — 0.48^1 = 0.52

На очереди вторая вероятностная метрика, которая должна дополнительно подкрепить нашу уверенность в детектировании виртуального стока.

N-zero-sales-days probability (вероятность НЕ увидеть подряд n-дней без продаж при текущей частоте продаж) . В данной метрике мы воспользуемся геометрическим распределением (Геометрическое распределение) для оценки вероятности наступления серии дней без продаж длинной n, при условии известного значения параметра частоты продаж (sales frequency), который был рассчитан нами ранее.

Формула геометрического распределения, которой мы воспользуемся:

где <b>n</b> - количество продолжительность (возраст) кейса в днях, а <b>p</b> - значение параметра частоты продаж (sales frequency).
где n - количество продолжительность (возраст) кейса в днях, а p - значение параметра частоты продаж (sales frequency).

Для лучше интерпретации мы также вычтем полученное по формуле значение из единицы. В итоге для n-zero-sales-days probability мы получим следующее выражение: 1 — (1 — p)^n . Подставляем требуемые значения для первого дня и вычисляем: 1 — (1 — 0.45)^1 = 0.45.

Также мы введем еще один показатель — stock variance (дисперсия цифры остатков) . Эта метрика поможет нам, в случае изменения значения стока в торговой точке Y, закрыть рассматриваемый кейс естественным путем. Пока данный показатель в течение жизненного цикла кейса равен нулю, мы продолжаем подозревать виртуальный сток. В расчете нам пригодится ранее обозначенный параметр stock value.

Считается показатель по формуле дисперсии:

Чистим «засоры» на товарных полках в ритейле. Недорого

Логично, что для первого дня мониторинга нашего кейса stock variance = 0.

<i>День №1: итоговая таблица для первого дня без продаж</i>
День №1: итоговая таблица для первого дня без продаж

День № 2

Наступает второй день мониторинга. Как же поведет себя продукт X в торговой точке Y сегодня? Возможны два варианта, которые мы и рассмотрим.

  1. Сработает триггер на естественное закрытие кейса. Причиной может послужить как ненулевая продажа (т. е. продукт X продастся) , так и пополнение запасов через закупку продукта X. Оба варианта изменят значение параметра stock value, что повлечет за собой реакцию показателя stock variance.

    Давайте взглянем на таблицу, предположив, что было продано 3 штуки продукта X
<i>День №2: после продажи 3 штук товара Х сработал триггер на закрытие кейса</i>
День №2: после продажи 3 штук товара Х сработал триггер на закрытие кейса

При данном варианте мы бы прекратили преследование кейса по подозрению в потенциальном виртуальном стоке.

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

<i>День №2: пересчитываем вероятностные метрики при наступления нового дня</i>
День №2: пересчитываем вероятностные метрики при наступления нового дня

Наблюдаем естественный рост вероятностей для empty shelf probability и n-zero-sales-days probability. Мы условились, что виртуальный сток объявляется при достижении обоими метриками порога в 0.95, поэтому пока рано бить тревогу — продолжаем наблюдать.

День № 3

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

<i>День №3: пересчитываем вероятностные метрики при наступления третьего дня</i>
День №3: пересчитываем вероятностные метрики при наступления третьего дня

Да, мы вновь не достигли заветной отметки. Давайте смоделируем все последующие дни и увидим, когда же все-таки мы повесим ярлык виртуального стока на рассматриваемый кейс.

День X

При заданных параметрах для продукта X в торговой точке Y мы детектируем виртуальный сток на 5-й день. Далее мы проводим мероприятия по его устранению.

<i>День №5: кейс объявляется виртуальным стоком; обе метрики превысили порог 0.95</i>
День №5: кейс объявляется виртуальным стоком; обе метрики превысили порог 0.95

Давайте проверять

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

В рамках внутренней проверки на адекватность мы воспользовались возможностью проводить виртуальные визиты в торговые точки. Да, звучит классно: мы проверяем наличие виртуального стока через виртуальные визиты. Благодаря сервису мерчандайзинга и технологии IR (Image Recognition), мы можем, физически не посещая торговые точки, рассматривать фотографии торговых полок и анализировать их содержимое.

На текущий момент мы провели несколько десятков тестов-верификаций на уровне торговая точка/продукт и проверили общую статистику на всем наборе доступных торговых точек.

Ряд полученных инсайтов:

  • Мы в действительности обнаруживаем виртуальный сток!
  • В момент одного дня виртуальный сток подозревался в каждой третьей торговой точке!
  • В нескольких случаях мы попадали на ложноположительное срабатывание. В подавляющем большинстве таких ситуаций мы наблюдали, что наш продукт просто «забит» куда-то в угол полочного пространства. Не удивительно, что он не продавался.
  • Ложноположительное срабатывание — тоже сигнал к действию. Мы осознали, что с помощью наших расчетов можно расширить пул решаемых задач и обнаруживать не только виртуальные стоки, но и кейсы плохой выкладки продукции на торговой полке.

Отдельно хочется продемонстрировать один из кейсов "упущенных возможностей". Если бы мы запустили функционал ранее, то смогли бы предотвратить ситуацию виртуального стока на 6-й день, и не затянули бы продажную засуху на более чем 11 дней! И этот кейс — упущенная возможность лишь по одному продукту, в одной торговой точке.

<i>Реальный кейс виртуального стока, который мог бы быть предотвращен</i>
Реальный кейс виртуального стока, который мог бы быть предотвращен

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

Есть над чем подумать…

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

Открытые вопросы:

  • Почему порог вероятностей 95%? Должен ли он быть дифференцируем в зависимости от ритейлера, формата магазина, продукта и т. д.?
  • Есть ли более эффективный способ оценки параметров интенсивности продаж и частоты продаж?
  • Каким образом снизить количество ложноположительных результатов?
  • Как лучше оценить экономический эффект влияния внедрения решения?

Заключения

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

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

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

Спасибо за внимание!

33
2 комментария

Интересно сопоставить результаты с подходом «нет изменения стока в течение 7 дней»)

Ответить

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

Ответить