Современным подходом к ценообразованию в ритейле является динамическое ценообразование. Оно напрямую связано с моделированием спроса для выявления оптимальных цен на будущий период. Такое моделирование в первую очередь связано с машинным обучением, когда имея исторические данные по продажам, мы можем построить модель, которая отражает взаимосвязь цен и спроса. После этого модель используется для оптимизации цен. Есть огромное множество моделей машинного обучения, которые могут использоваться в данной задаче, однако, их можно разделить на два “лагеря”: Байесовские модели Идейные наследники формулы Байеса, в своей сути предполагающие, что зависимости между переменными носят вероятностный характер и не могут быть определены в точности. Например, истинный коэффициент эластичности может находиться где-то в промежутке между -0.45 и -0.55. Это открывает нам возможность вычислять вероятности различных исходов. Следовательно, оптимальная цена в данном случае может быть не одна. Основными плюсами такого подхода являются:
Популярной моделью в задаче оптимизации цен с использованием комбинации Reinforcement learning и Байесовского подхода является Сэмплирование Томпсона (далее — ST). Именно проблемы практического применения этой модели и будут рассматриваться в данной статье. Подробно про то, как работает модель сэмплирования, можно прочитать тут. Разница с задачей выбора оптимальной цены заключается в том, что вместо выбора картинки котика, которую нужно показывать пользователям, мы выбираем цену, которую нужно установить на товары. Точечные модели В отличие от байесовского подхода, предполагают, что есть конкретная зависимость, которую можно восстановить из данных. Например, что коэффициент эластичности = -0.5. Цена, при которой будет наибольшая ожидаемая прибыль в данном подходе, может быть вычислена однозначно. Минусами такого подхода являются:
В случае использования линейных моделей многие минусы обходятся (модель является полностью интерпретируемой, есть статистические методы определения значимости коэффициентов факторов на основе p-value). Однако, давайте подумаем о том, а является ли зависимость, которую мы пытаемся восстановить с помощью модели, линейной? Например, размер промо чаще всего нелинейно влияет на спрос (после определенного % скидки может начаться взрывной рост спроса). Именно нелинейными зависимостями обусловлено использование сложных ML моделей, потому что они могут использоваться для обучения таким зависимостям. Например, посмотрите, как ошибается линейная модель в предсказании спроса на электричество в крайних частях диапазона цен: ![]() График 1: спрос на электричество. Отрицательные цены — это не ошибка Сэмплирование Томпсона для ценообразования на практикеВ общем виде модель выглядит не такой уж и сложной для понимания. Модель является итеративной, а, значит, ее применение является поэтапным. Чтобы разобраться, какие существуют нюансы применения этой модели, разберем каждый этап применения модели. Самый первый выбор для классического ML в ценообразовании является линейный характер зависимости спроса от цены. Именно такую зависимость между ценой и спросом можно встретить в значительном количестве микроэкономических моделей. ![]() График 2: линейная модель спроса Нюанс 1: дискретная модель спроса Однако, для ST такой характер зависимости не является выбором по умолчанию, потому что в самой сути модели заложена дискретность выбора какого-то одного оптимального варианта из нескольких доступных. В случае ценообразования — модель ST ищет оптимальную цену среди нескольких возможных. Это выливается в то, что в варианте по умолчанию алгоритма ST используется дискретная модель спроса, которая предполагает, что для каждой цены у нас свой спрос, и величина спроса между ценами никак не коррелирует между собой. ![]() График 3: дискретная модель спроса Для нас, как пользователей этой модели, это означает, что если мы собрали исторические данные о спросе по цене P1, то модель никак не сможет их применить для прогнозирования того, а какой спрос будет по цене Р2, пока эта цена не будет установлена на практике и не будет измерен спрос (что мы можем сделать сами и без моделей). Дискретный характер зависимости может быть довольно оправданным решением в рекомендательных системах для контента, потому что лайки одной картинки с котиком никак не коррелирует с лайками другой картинки с котиком, однако, для вопроса ценообразования этого становится несколько .. недостаточно. В первую очередь потому, что дискретная модель спроса — это самый базовый вариант, который вообще никак не учитывает такие факторы спроса, как сезонность, промо, каннибализм между товарами и так далее. Если не учитывать все эти факторы, то распределение возможного спроса для каждой цены останется достаточно широким, сколько бы итераций уточнения на основе реальных данных ни произошло. Также, из предпосылки дискретной функции спроса следует множество технических ограничений модели, с которыми мы столкнемся далее. Нюанс 2: а сколько разных цен мы можем установить? С точки зрения математики — бесконечное количество: от (-) бесконечности до (+) бесконечности. Однако, давайте придерживаться практичности и предположим, что возможный диапазон новых цен будет +/- 10% от некоторой текущей цены. Сколько можно установить различных цен сейчас? Давайте предположим, что шаг цены может быть равен 1 копейка. Тогда, если базовая цена составляет 100 рублей, то установить мы можем цены в диапазоне 90-110, а это, как нетрудно посчитать, 2 000 возможных вариантов цен. Теперь вспоминаем про дискретную модель спроса (нюанс 1), которая предполагает, что для каждой цены у нас спрос полностью независим, и получаем 2 000 никак не связанных между собой моделей. Теперь представим, что мы захотим по одному разу поставить каждую цену хотя бы на один день и получаем 5,5 лет мучений выбора оптимальной цены для этого товара. Не очень хорошо! Что делается, чтобы избежать такой ситуации на практике: серьезно сокращается количество цен, которые можно выставить. Тут идут в ход всеми любимые округления до х.99, х.45 и так далее, что значительно снижает коллекцию из 2 000 цен до нескольких десятков. Тем не менее, если мы разобрались для товара с ценой 100 рублей, то для товара с ценой 1 000 разобраться становится сложнее: с шагом в 1 копейку, в диапазоне +/- 10% уже не 2 000 возможных цен, а 20 000! Решать такое возможно только либо скрупулезной проработкой возможных цен для установки, либо алгоритмами, которые автоматически выбирают цены с некоторым % шагом, соблюдая правила округления. Ценой за такой подход является широта пробелов между возможными ценами: вместо того чтобы пробовать 1 010, 1 019, 1 029 … 1 099, на практике становится возможным опробовать перечень гораздо уже, например 1 000, 1 049, 1 099. Это все сказывается на точности выявления оптимальной цены. Например, если истинно оптимальная цена будет 1 079, то мы этого уже не узнаем, а сможем установить только самую ближайшую к ней — 1 099, даже, если это приведет к уменьшению ожидаемой выручки/прибыли. Давайте для простоты установим следующий возможный перечень цен: [1.99, 2.49, 2.99, 3.49, 3.99, 4.49, 5.99]. Решение, которое применяется в SmartPricing: поскольку количество цен на широком диапазоне действительно может быть большим, то мы разработали специальный алгоритм, который автоматически рассчитывает перечень цен, который будет использоваться при моделировании спроса. Это позволяет полностью убрать ручное вмешательство в установление перечня цен, при этом соблюдаются все правила по округлениям цен. При этом, перечень формируется еще и таким образом, чтобы количество возможных цен было достаточно велико, чтобы найти максимально приближенную к оптимальной, однако, не так велико, чтобы растянуть схождение модели до бесконечности из-за огромного перечня возможных вариантов. Нюанс 3: какое вероятностное распределение выбрать? В модели ST предполагается, что спрос — это вероятностная величина, то есть для одной цены спрос может варьироваться в некотором диапазоне (см. серую гистограмму на графике ниже). ![]() График 4: Распределение спроса На графике представлена гистограмма спроса, построенная на реальных данных. Черная линия, которая обрамляет гистограмму — это распределение Пуассона, которое часто применяется для описания продаж. И в данном случае мы видим, что гистограмма очень хорошо совпадает с распределением Пуассона. Однако, распределений, которые могут подходить, может быть несколько. Например, Нормальное распределение также может подходить для товаров, которые продаются довольно большими объемами, однако, если характер спроса на товар отрывистый, если Вы можете увидеть много дней, в которых продаж не было вообще — выбор Пуассона или Нормального распределения становится не самым лучшим выбором. Таким образом, при формировании модели ST нужно быть очень внимательным к тому, а какое распределение выбрать, в зависимости от характера спроса на те или иные товары. Решение, которое применяется в SmartPricing: после длительных экспериментов удалось выбрать такое вероятностное распределение, которое может использоваться и для товаров, продающихся достаточно плохо, и для товаров, продающихся достаточно хорошо — гамма распределение. Нюанс 4: моделирование спроса в онлайн и оффлайн ритейле сильно отличается Отличается оно тем, что в онлайне открывается доступ к дополнительной информации, не доступной для офлайна: количество просмотров карточки товара. Отсюда вытекает, что для онлайн ритейла мы можем выбрать “бета распределение” спроса, что позволяет нам учесть, сколько человек посмотрело карточку товара с указанной ценой и сколько из них купило / не купило его. В оффлайне провернуть такой трюк получится, только если устанавливать камеры и напрямую отслеживать, куда смотрят люди в каждый момент времени, что довольно затратно само по себе. Решение, которое применяется в SmartPricing: как было сказано в предыдущем пункте, было выбрано Гамма распределение. Оно не требует учета трафика, что позволяет применить комплекс ST для оффлайн оптимизации. 2. Устанавливаем априорное распределениеДопустим, мы разрешили все вопросы, описанные на предыдущем этапе, выбрали Гамма распределение для нашей дискретной модели спроса и выбрали возможные цены для установки. Время пришло сделать стартовую версию модели, которая пока что ничего не знает о реальном спросе. Для этого, нам нужно построить наши ожидания о спросе на товар для каждой цены, которую мы можем установить (нюанс 2). В терминах байесовских моделей — установить априорные ожидания (prior). ![]() Формула Байеса Нюанс 5: установить априорное распределение — задача нетривиальная Для выбранного нами Гамма распределения для каждой из возможных цен, нам нужно установить, какой будет спрос в среднем для каждой из цен за 1 торговый день (допустим, мы можем менять цены каждый день). Кажется, вопрос не тривиален и непонятно, как это можно сделать. Мы можем, конечно, пойти посмотреть историю продаж этого товара и попытаться найти эти цены в истории. Однако, во-первых, крайне маловероятно, что мы найдем все цены из выбранного нами перечня, потому что нередки ситуации, когда одна и та же цена может стоять месяцами и никак не меняться, а во-вторых, далеко не факт, что мы продавали по ценам, которые точно находятся в нашем списке. Например, если продавали на 5 копеек ниже или выше, то это уже не та же самая цена, а значит, если жестко соблюдать идею дискретной функции спроса (нюанс 1), мы не можем взять эти данные и как-то их применить для установления априорной информации для близкой цены. Самый простой способ решения этой проблемы — установить одинаковую величину спроса для всех цен, например, 1 штука / 1 день. Даже если это будет не совсем верно. В конечном счете, для этого и существует ST — постепенно обновить эту априорную информацию через практику и понять, а какая величина спроса для каждой цены на самом деле. Так ведь? Такой подход при изучении источников, касающихся ST, можно встретить бесчисленное количество раз. И тут кроется ловушка. Решение, которое применяется в SmartPricing: Поскольку задача нетривиальная, то и решение не могло быть простым. После проведения значительного количества экспериментов в попытке выявить наилучший автоматический способ установления априорной информации, было выяснено, что лучшим подходом тут может служить применение машинного обучения (без него никуда). С одной стороны, это сближает оптимизацию цен на основе моделей МЛ с моделью ST, с другой, позволяет привлечь сильные стороны МЛ для преодоления трудностей в ST. В качестве подхода применяется следующая схема:
Такой подход позволяет сделает первичное приближение того, какие могут быть продажи у товара. Несмотря на то, что модель МЛ тут может быть достаточно базовой, это все равно в разы лучшее приближение для априорной информации, чем если мы установим фиксированные параметры, одни для всех товаров. 3. Выбираем цену и измеряем спросНюанс 6: неверная установка априорных распределений дорого стоит Поскольку задача установления априорных распределений — трудная, то возможны ошибки. Тот кто знаком с формулой Байеса может сказать — в этом и смысл, что ошибки будут корректироваться при поступлении новой информации. Все так, однако, давайте спросим: а на сколько больше потребуется итераций, если установить неверную величину априорного спроса? Давайте посмотрим, к чему приводит неверное установление априорных распределений с практической точки зрения. Для этого, проведем симуляцию, в которой будем пытаться ставить неправильные априорные вероятности и смотреть на то, как поведет себя алгоритм ST в процессе оптимизации. Предпосылки симуляции:
Предположим, что мы занизили в своих ожиданиях возможный спрос. Предсказали, что продажи по цене 2.99 будут не 30 шт, а 10 шт. На графике ниже представлено три блока:
![]() График 5: Ошибаемся в установке априорной информации Что же мы видим? ST систематически не верно ставит цену в 4.49, даже не пытаясь приблизиться к оптимальной цене 3.49 за первые 400 дней (а это больше года). Почему так происходит? Давайте рассмотрим упрощенный пример в два последовательных этапа оптимизации цен: 1 Этап, мы ничего не знаем о спросе, для каждой цены установили 10 шт.
При оптимизации выручки, мы выбираем цену, при которой у нас наибольшая ожидаемая выручка — 5.99 Мы установили эту цену и получили фидбек: по этой цене продалось 9 шт, обновляем априорную информацию, заново предсказываем, сколько штук будет продаваться по каждой из цен, и что же мы видим:
Цена 5.99 повторно становится максимально привлекательной из-за того, что ожидаемая выручка становится вновь самой высокой и модель будет выбирать и выбирать ее повторно, не пытаясь нащупывать другие цены. Мы видим ровно такое же поведение на графике, когда сэмплирование “застряло” на высоких ценах, не пытаясь попробовать понизить цены. Для сравнения, давайте посмотрим на вариант работы модели ST, когда априорная информация установлена на правильном уровне: ![]() ![]() График 6: устанавливаем априорную информацию правильно Здесь сразу видно, что модель ST буквально за несколько недель нащупала нужную цену в 3.49 и ставила ее основное время, отклоняясь вверх или вниз, “прощупывая” соседние цены, чтобы убедиться в правильности выбранной цены. Это ровно то поведение модели ST, которое ожидается. В точечных моделях значимая проблема заключается в “застревании” на каких-то определенных, неоптимальных ценах, без способности выйти из этой ситуации через установку каких-то новых цен. Как было продемонстрировано выше, при неправильной настройке априорной информации, ST будет страдать ровно от такого-же недуга. Решение, которое применяется в SmartPricing: Поскольку мы уже установили априорное распределение с помощью МЛ модели, это позволило избежать проблем со сходимостью ST. Еще больше неочевидных вещейКажется и так уже достаточно, что же еще может пойти не так? Нюанс 7: чем более отрывистый спрос на товар, тем больше времени понадобится на оптимизацию цены через ST Предыдущие исследования на симуляторе предполагали, что у нас есть довольно устойчивый спрос (без проседания в 0 в некоторые дни), однако, давайте не забывать, что не все товары могут похвастаться такой статистикой продаж. Как поведет себя ST при условии, что большинство дней остаются вовсе без продаж по товару, а когда продажи есть, то они единичные? Для этого, изменим условия симулятора: теперь вместо истинной линейной кривой спроса у нас будет вероятность того, будет ли куплен товар для каждой тестируемой цены. Зависимость при этом остается прежней — чем ниже цена, тем вероятность выше. Если “монетка” выпадает на “куплен”, то спрос — 1 шт, в противном случае — 0. Чтобы ST начал работать при таких условиях, нужно поменять вероятностное распределение на такое, которое учитывает только два возможных варианта (1 и 0). В данном случае, мы возьмем Биномиальное распределение (см. нюанс 3). ![]() График 7: оптимизация через ST для слабо продающегося товара После запуска симуляции мы получили результаты, которые можно интерпретировать как то, что ST не справляется с задачей установления точной оптимальной цены. Вместо этого устанавливаемые цены колеблются вокруг истинно оптимальной цены даже по прошествии 500 дней. В целом, нет оснований полагать, что модель не сойдется когда-то в будущем, но готовы ли Вы ждать 500 дней для выявления оптимальной цены по товару? Почему так происходит? Ответ довольно очевиден: если у нас товар продается в лучшем случае по 1 штуке в неделю, то любая модель будет страдать от того, что она не способна выявить истинную зависимость спроса от цены в течении довольно продолжительного периода времени. Поэтому, тут остается только “войти в положение” и понять, что любые модели — это не магия, которая возьмет информацию о кривой спроса из ниоткуда. Решение, которое применяется в SmartPricing: мы дали возможность пользователю выбрать, по каким товарам будет проводиться оптимизация с помощью ST. Поскольку модель ST не слишком подходит для такого типа товаров, имеет смысл рассмотреть другие подходы. Стоит дополнительно отметить, что несмотря на то, что в моделях оптимизации через многоруких бандитов есть и другие подходы (например, e-greedy и прочие), это не значит, что они могут успешно применяться. Дело в том, что неоднократно было показано, что ST — самый эффективный алгоритм, а, значит, другие алгоритмы из семейства многоруких бандитов будут показывать динамику хуже, чем ST и их нельзя рассматривать в качестве возможного выбора. Нюанс 8: так ли плохи точечные модели на самом деле? Ранее уже было описано, что точечные модели при оптимизации цен влияют сами на себя и из-за этого “застревают” на неоптимальных ценах, даже не пытаясь пробовать альтернативные цены. А что если мы им поможем попробовать разные цены? В данном иллюстративном примере мы сделаем простую вещь: в первую неделю на симуляторе установим максимально допустимую цену, во вторую неделю — минимально допустимую цену. Назовем это “инициализация”. В качестве ML модели возьмем обычную линейную регрессию (точечная модель), которая будет использоваться в попытке оценить кривую спроса и установить оптимальную цену на основе этой оценки. ![]() График 8: выявляем оптимальную цену с помощью линейной регрессии Давайте разберемся, что же мы видим на графике 8. Первые две недели были установлены цены, сперва самая высокая из доступных — 5.99, после нее — самая низкая из доступных — 1.99. Начиная с третьей недели ML модель могла самостоятельно устанавливать цену, которую она посчитала оптимальной. Начиная с третьей недели она установила сразу же оптимальную цену 3.49 и больше ее не меняла. Обратите внимание, как это отличается от модели ST (график 6), которая подошла к оптимальной цене довольно быстро, однако продолжила пробовать другие цены на всем оставшемся промежутке времени. Также хочется обратить внимание на накопленную потерянную выручку от установления неоптимальной цены. В случае нашего подхода с ML, график перестал расти после 3 недели, чего нельзя сказать о подходе ST. Почему так произошло? Во-первых, хочется напомнить, что одно из заявленных преимуществ ST над точечными ML моделями заключается в том, что ST продолжает “прощупывать” цены, даже после того, как она сошлась к оптимальной цене. Любое “прощупывание” — потеря выручки. Поэтому при применении модели ST нужно быть готовым к тому, что подвижность цен может значительно увеличиться по сравнению с тем, как было до применения каких-либо моделей. Во-вторых, чем более случайный характер носит спрос, тем сложнее ST определить оптимальную цену. Это продолжает приводить к значительным скачкам в устанавливаемых ценах, что опять таки приводит к потере выручки на оптимальных ценах. Почему же тогда ML модель установила сразу же нужную цену? Для этого есть несколько причин:
В качестве выводовВ данной статье мы попытались рассмотреть практические проблемы применения модели ST для оптимизации цен. Значительное количество проблем оказалось связано с выбором дискретной модели спроса, которая не позволяет учитывать весь перечень внешних факторов, влияющих на спрос, а также не позволяющая делиться информацией о спросе с “соседними ценами”. Значит ли это, что ST — не самый хороший метод оптимизации цен? Вовсе нет, потому что для онлайна эта модель получила широкое распространение и показала свою эффективность. Для офлайна все выглядит не так однозначно и кажется, что модель должна быть существенно доработана. В качестве возможного решения описанных проблем может служить применение классических ML моделей, но с доработкой. Доработка тут заключается в том, что вместо того, чтобы модель предсказывала точечное значение спроса, ее можно модифицировать так, чтобы она предсказала вероятностное распределение. Такой подход называется “Контекстный бандит”, когда учитывается не только распределение самой предсказываемой величины, но и “контекст”, который влияет на конечное распределение. Это позволяет значительно уточнить предсказания модели и сойтись модели ST значительно быстрее. Вот несколько примеров того, как могут быть доработаны модели деревьев решений и нейронной сети для использования в модели ST. Про линейных контекстных бандитов также не забываем. Упомянутая в статье платформа для data-driven динамического ценообразования SmartPricing — это основа для предсказуемого и прибыльного розничного бизнеса, сервис, который помогает подобрать выгодные ценовые решения для розничных компаний: для регулярных цен, промо, конкурентных цен, CTM и цен для новинок. Подробнее о системе — на https://myretailstrategy.ru/smartpricing/. Автор: Евгений Орлов, leading data scientist, myRetailStrategy |