Овладение искусством оптимизации ценообразования – решение науки о данных
Mastering the art of pricing optimization - a solution in data science.
Раскрытие секретов реальных решений науки о данных для оптимизации ценообразования в рознице

Содержание:
1. Обзор2. Моделирование эластичности3. Оптимизация
1. Обзор
Ценообразование играет очень важную роль в мире бизнеса. Сбалансированность между объемом продаж и маржой является очень важной для успеха любого бизнеса. Как мы можем сделать это с помощью науки о данных? В этом разделе мы построим интуицию эффективного решения науки о данных для оптимизации ценообразования, а затем мы рассмотрим детали и код каждого компонента.
Примечание – существуют разные типы стратегий ценообразования, но в этой статье мы сосредоточимся на построении стратегии ценообразования для обычных бизнесов/известных брендов с достаточным количеством данных о истории изменения цен. Давайте рассмотрим базовый подход, который мы пытаемся следовать, прежде чем перейти к деталям –
- ИИ и будущее колледж-футбола
- Создание простого образа Docker для науки о данных
- ИИ не должен тратить время на переизобретение ETL

Мы построили график продаж и цен для товара 1. За последние 9 месяцев произошло 2 изменения цен, и, разумеется, мы можем видеть их влияние на продажи. Когда цены были ниже, продажи были выше. Теперь вопрос в том, как количественно оценить влияние изменения цен на продажи в прошлом и предсказать оптимальную цену для товара в будущем.
Интересное наблюдение с января по апрель, цена была фиксирована на уровне $5, но мы все равно наблюдаем колебания продаж. Это вполне нормально, так как в реальном мире существует множество внешних факторов, влияющих на продажи, таких как сезонность, праздники, акции, маркетинговые расходы и т. д. Поэтому мы не моделируем фактические продажи, а базовые продажи, которые мы получаем, используя различные модели.

Вы можете заметить, что мы смотрим на более плавный тренд продаж в серии базовых продаж. Это на 100% точно? Определенно нет! Наука о данных – это все о том, как близко мы можем приблизиться к реальности. Перейдем к процессу –
Допустим, нас наняли с просьбой предоставить цены для тысяч товаров в разных магазинах группы Retailmart. Цены на один и тот же товар могут различаться в разных магазинах. Компания предоставила нам данные за последние 5 лет. Каков должен быть наш подход к решению этой задачи?
Давайте разберемся на примере ценового метра. Предположим, у нас есть ценовой метр, и мы установили минимальное и максимальное значения, а стрелка может двигаться между этими двумя крайностями. В настоящее время стрелка указывает на текущую цену. Наша цель – остановить стрелку в точке, где мы можем максимизировать прибыль.
Теперь, когда мы двигаем стрелку вправо (т.е. мы повышаем цену), продажи начнут снижаться, а маржа будет увеличиваться, но
- Можем ли мы количественно оценить это снижение? Да, мы можем, и это называется эластичностью цены товара. Простыми словами, эластичность цены для товара будет означать процентное изменение продаж при изменении цены на 1%.
- В реальном мире продажи часто зависят от акций, праздников, дополнительных скидок и т. д., но для оптимизации цены нам нужно исключить влияние всех этих внешних факторов и вычислить базовые продажи.
- Когда мы количественно оценим изменение продаж относительно изменения цены, нам нужен ответ, На какой позиции остановить стрелку? Для этого нам нужна цель, которая в большинстве случаев заключается в максимизации прибыли. Прибыль = Продажи * Маржа, поэтому мы должны остановиться в позиции, где значение прибыли будет максимальным. Математически это понятие нелинейной оптимизации, где значение может изменяться в пределах границ.
- Бизнес-правила важны, мы должны убедиться, что конечные рекомендованные цены соответствуют этим правилам.
Итак, это основные шаги, которые мы будем следовать для определения правильной цены для каждого товара в заданном магазине. Давайте рассмотрим эти шаги более подробно —
1. Базовые продажи/базовые единицы
Этот шаг является предварительным для последующих шагов. Как уже указано, мы хотим моделировать влияние цен на продажи. Идеальный сценарий – это иметь продажи, которые влияют только на цены, но в практическом мире это никогда не бывает —
Поэтому мы хотим симулировать продажи для нашего идеального сценария, и мы делаем это с помощью модели временных рядов по следующему уравнению —
Продажи ~ функция[Базовые продажи + (промо-эффект) + (эффект от праздников) + (любой другой эффект)]
Обратите внимание, что иногда у нас нет фактических данных о внешних факторах, влияющих на продажи. В таком случае мы можем использовать фиктивные переменные, чтобы учесть все такие факторы. Простым примером может быть, если в определенный месяц мы видим внезапное увеличение продаж, но цена остается постоянной, мы можем ввести простую фиктивную переменную со значением 1 для этого месяца и 0 для остальных месяцев.
2. Эластичность цены
Эластичность цены относится к процентному изменению продаж в отношении процентного изменения цены товара для данного магазина.
В качестве примера рассмотрим два товара – молоко и зеленый чай ABC. Как вы думаете, какой из них будет иметь высокую эластичность цены?
Молоко, являясь неотъемлемым товаром на каждый день и имея высокую конкуренцию, проявляет высокую эластичность цены. Даже незначительное изменение цены может значительно повлиять на продажи из-за его широкого спроса. С другой стороны, зеленый чай ABC, который может быть доступен в ограниченном количестве магазинов, имеет низкую эластичность цены. Незначительное изменение цены на зеленый чай ABC вряд ли окажет существенное влияние на продажи из-за его присутствия на рынке ниши.
Как мы будем моделировать это?
Базовые продажи ~ функция[(цена) + тренд]
Коэффициент переменной цены будет использоваться в качестве эластичности цены. Переменная тренда используется для учета увеличения продаж из-за долгосрочного тренда, а не обязательно из-за изменения цены. Мы рассмотрим более подробные сведения о вычислении эластичностей в разделе “Эластичность цены” ниже.
3. Нелинейная оптимизация в рамках границ
На этом шаге мы получим ответ на вопрос, где следует остановить указатель.
Сначала мы определяем нашу целевую функцию – максимизация прибыли
Затем мы определяем начальную и конечную точку метра цены, которая определяет нижнюю и верхнюю границы цены
Мы уже вычислили базовые продажи и эластичности цены, которые количественно характеризуют чувствительность продаж к цене. Мы поместим все эти входные данные в нашу функцию нелинейной оптимизации, и мы получим оптимальную цену.
Простыми словами, алгоритм будет пробовать разные цены в пределах границ и проверять значение целевой функции, которое в нашем случае является прибылью. Он вернет нам цену, при которой удалось получить максимальное значение для нашей целевой функции. (В линейной оптимизации представьте, как работает градиентный спуск). Мы рассмотрим более подробные сведения о вычислении оптимальных цен в разделе “Оптимизация” ниже.
4. Бизнес-правила
Можем ли мы непосредственно внедрять оптимальные цены в наши магазины?
Нет, но что остается? Соблюдение бизнес-правил является одним из самых важных требований для любого бизнеса.
Но о каких правилах мы говорим в отношении ценообразования —
- Правила окончания чисел — Общей практикой является ценообразование товара по цене $999 или $995 вместо $1000. Есть несколько психологических причин для этого, поэтому нам нужно убедиться, что наши конечные рекомендуемые цены соответствуют таким правилам, если они применимы.
- Правила разрывов товаров — Можете ли вы продавать одну упаковку Магги, цена на единицу которой выше, чем у 4-упаковки Магги? Нет, верно. Часто, если размер упаковки увеличивается, стоимость за единицу должна уменьшаться или оставаться прежней.
Итак, это примеры некоторых бизнес-правил, которые хочет применить бизнес. Мы выполним некоторые дополнительные шаги постобработки оптимальных цен, чтобы получить окончательно рекомендуемые цены.
Теперь, когда вы знакомы с общим процессом, пришло время углубиться в более подробности и программирование.
2. Моделирование эластичности
В этом разделе мы разберем, как можно использовать эту концепцию для определения оптимальных цен для тысяч изделий в нескольких магазинах. Допустим, нам нужно определить эластичность цены для закуски Yochips, продаваемой в магазине в Калифорнии в течение последних 3 лет. Давайте сначала рассмотрим определение эластичности цены:
Эластичность цены определяется как процентное изменение продаж при изменении цены на 1%.
Теперь вы можете задаться вопросом, какой алгоритм я могу использовать для вычисления эластичности цены для товара, например, Yochips?
Давайте рассмотрим некоторые детали из экономической книги о модели постоянной эластичности цены и посмотрим, можем ли мы связать ее с алгоритмом науки о данных.
Мультипликативная форма функции спроса будет:
Yi = α*Xi (где y будет продажами/спросом, а x будет ценой)
Взяв логарифм от обеих сторон
log(Yᵢ) = log(α*Xᵢ^β)
log(Yᵢ) = log(α) + β*log(Xᵢ) ……….Уравнение(1)
log(α) можно рассматривать как перехват как β₀
log(Yᵢ) = β₀ + β₁*log(Xᵢ) ………….Уравнение(2)
Теперь возьмем производную от обеих сторон, получим
δY/Y = β₁*δX/X
Термин на левой стороне представляет собой % изменение Y, которое является % изменением продаж, в то время как термин справа представляет собой % изменение цены. Теперь, когда
% изменение цены = 1%; тогда δX/X = 1
δY/Y = β₁
Это означает, что процентное изменение продаж будет β₁ и это наша эластичность.
Теперь, если вы заметили, Уравнение 2 является Уравнением регрессии, где логарифм(продаж) регрессируется относительно логарифма(цены), и коэффициент логарифма(цены) будет нашей эластичностью цены.
Ура! Теперь мы знаем, что вычисление эластичности так же просто, как обучение модели регрессии.
Но есть еще одна хитрость. Уравнение функции спроса имеет некоторые предположения, и одно из предположений заключается в том, что продажи зависят только от цены, но это обычно не так в реальном мире, потому что обычно на продажи влияют множество факторов, таких как акции, праздники, события и т. д. Так каково решение? Нам нужно вычислить составляющую продаж, в которой мы можем устранить влияние всех этих дополнительных событий.
Одну вещь следует уточнить: базовые продажи относятся к единицам продаж, а не к денежным продажам. Таким образом, в уравнении 2 мы должны регрессировать цену относительно базовых единиц, а не относительно фактических единиц продаж. Теперь вопрос: как мы можем получить базовые единицы из фактических единиц продаж?
Давайте разберем это на примере. Ниже вы можете увидеть еженедельный график временного ряда для единиц продаж и цен на продажу:

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

На приведенном выше графике мы разложили исходные логарифмы единиц продаж (серый цвет) на логарифмы базовых единиц (желтая линия)
Вот код, с помощью которого вы можете разложить временной ряд и получить трендовую составляющую, становящуюся базовыми продажами:-
# Определение входных переменных
timestamp_var = "week_ending_sunday"
baseline_dep_var = "ln_sales"
changepoint_prior_scale_value = 0.3
list_ind_vars_baseline = ['event_type_1_Cultural','event_type_1_National','event_type_1_Religious','event_type_1_Sporting']
# Подготовка данных
df_item_store = df_item_store.rename(columns={timestamp_var: 'ds', baseline_dep_var: 'y'})
df_item_store['ds'] = pd.to_datetime(df_item_store['ds'])
# Инициализация и обучение модели
model = Prophet(changepoint_prior_scale= changepoint_prior_scale_value) # Значение по умолчанию changepoint_prior_scale = 0.05
for regressor in list_ind_vars_baseline:
model.add_regressor(regressor)
model.fit(df_item_store)
# Прогнозирование и извлечение составляющей уровня
forecast = model.predict(df_item_store)
level_component = forecast['trend']
Ниже представлены входные параметры, которые мы должны определить:
- changepoint_prior_scale_value — Этот параметр контролирует плавность тренда. Подробнее об этом можно прочитать в документации модели Prophet.
- list_ind_vars_baseline — Включает все дополнительные события, которые оказали влияние на продажи, такие как фестивали, спортивные события, культурные события и т.д.
Вот как параметр changepoint_prior_scale_value влияет на тренд. Когда значение мало, то тренд становится почти прямой, а когда значение высоко, тренд становится менее плавным.
Код простой: сначала мы переименовываем переменные “ln_sales” в “y” и “week” в “ds”, чтобы соответствовать требованиям модели Prophet. Затем мы инициализируем модель Prophet, указывая параметр “changepoint_prior_scale”. Затем мы добавляем дополнительные переменные событий и праздников в модель. Наконец, мы создаем прогнозы, используя тот же набор данных, на котором мы обучили модель и извлекли составляющую тренда.
Отлично. Теперь у нас есть базовая серия единиц и мы можем подогнать модель линейной регрессии между базовыми единицами (которые уже находятся в логарифмической шкале, потому что мы разложили логарифмическую серию base_units) и логарифмом(цены). Ниже приведено уравнение:-
log(базовые единицы) = перехват + эластичность*log(цена)
С помощью этого уравнения мы можем вычислить значение эластичности. На практике не все серии хорошо поддаются моделированию, поэтому в разных товарах может ожидаться некоторые неожиданные значения эластичности. Какое же решение? Если мы сможем каким-то образом выполнить регрессию с ограничениями на значение эластичности. Но как это реализовать? С помощью оптимизационной функции.
Для любой оптимизации необходимы следующие основные требования:
- Целевая функция — это уравнение, которое мы пытаемся минимизировать/максимизировать. В нашем случае это функция потерь, которую мы используем в линейной регрессии MSE (предсказанное-фактическое => [перехват + эластичность*ln_цена — фактическое]²)
- Начальные значения параметров, которые мы пытаемся оптимизировать, в нашем случае это перехват и эластичность. Изначально они могут быть любыми случайными значениями.
- Границы для параметров, это минимальное и максимальное значения для перехвата и эластичности
- Алгоритм оптимизации — это зависит от библиотеки, но вы можете использовать значения по умолчанию, и это должно дать вам правильные результаты
Теперь давайте посмотрим на код:
# Подготовка матрицы для передачи в оптимизационный алгоритм
x = df_item_store_model
x["intercept"] = 1
x = x[["intercept","ln_sell_price","ln_base_sales"]].values.T
actuals = x[2]
from scipy.optimize import minimize
# Определение целевой функции для минимизации
def objective(x0):
return sum(((x[0]*x0[0] + x[1]*x0[1]) - actuals)**2) # (перехват*1 + эластичность*(ln_sell_price) -ln_base_sales)^2
# Определение начального предположения
x0 = [1, -1]
# Определение границ для переменных
bounds = ((None, None), (-3,-0.5))
# Использование алгоритма оптимизации SLSQP для минимизации целевой функции
result = minimize(objective, x0, bounds=bounds, method='L-BFGS-B')
# Вывод результатов оптимизации
print(result)
# Сохранение значения эластичности цены товара в датафрейме
price_elasticity = result.x[1]
df_item_store_model["price_elasticity"] = result.x[1]
Обратите внимание на то, что мы определили начальное значение параметра для перехвата как 1 и упругость как -1. Для перехвата не определены границы, в то время как для упругости определены границы (-3, -0.5). Это основная причина, по которой мы выполняем регрессию через оптимизационную функцию. После выполнения оптимизации мы сохраняем оптимизированное значение параметра упругости цены. Ура! Мы рассчитали упругость цены!
Таким образом, наши йочипсы в магазине в Калифорнии имеют упругость цены -1,28.
Давайте также рассмотрим упругость цены для некоторых других серий:
Низкая упругость цены: Незначительное изменение продаж при увеличении цены. Ниже представлен график для товара с упругостью цены -0,5.

Упругость цены VoAGI: Умеренное снижение продаж при увеличении цены. Ниже представлен график для товара с упругостью цены -1,28.

Высокая упругость цены: Значительное снижение продаж при увеличении цены. Ниже представлен график для товара с упругостью цены -2,5.

Используя тот же подход, мы можем рассчитать упругость цены для всех товаров. В следующей статье мы рассмотрим, как мы можем использовать эти значения упругости для определения оптимизированных цен для каждого товара.
3. Оптимизация
В предыдущем разделе мы уже определили упругость цены для йочипсов в нашем магазине в Калифорнии. Но это не помогает менеджеру магазина, он хочет знать, как изменить цену йочипсов для максимизации дохода. В этой статье мы разберем методологию оптимизации цен.
Но перед этим есть несколько вопросов, которые мы должны задать менеджеру магазина.
В: Существуют ли какие-то ограничения на минимальное и максимальное изменение цены, которые следует учитывать при оптимизации цен?
Исходя из беседы с менеджером магазина, мы установили, что уменьшение цены не должно превышать 20%, а увеличение цены также должно быть ограничено 20%.
Текущая цена йочипсов составляет $3,23, и теперь мы знаем, что оптимизированная цена должна быть в диапазоне от $2,58 до $3,876. Но как мы можем получить оптимизированную цену?
Но как мы можем получить оптимизированную цену, которая максимизирует доход? Давайте посчитаем некоторые математические операции:
Оптимизированный доход = Общее количество проданных единиц * (Оптимизированная цена)
Нам нужно оптимизировать цену, чтобы максимизировать доход. Но общее количество проданных единиц также изменится при изменении цены. Перепишем вышеприведенное уравнение, и мы можем назвать общее количество проданных единиц при оптимизированной цене оптимизированными единицами:
Оптимизированный доход = Оптимизированные единицы * (Оптимизированная цена)……………(eq1)
Мы уже знаем, что —
Упругость = %изменение в проданных единицах / %изменение в цене
Следовательно:-
Оптимизированные единицы = Базовые единицы + изменение единиц при оптимизированной цене
Здесь базовые единицы обозначают общее количество продаж по текущей цене, которое составляет $2,58
Оптимизированные единицы = (Базовые единицы + (Базовые единицы * упругость цены * (% изменение оптимизированной цены по сравнению с обычной ценой) ………. (eq2)
Вставим eq2 в eq1
Оптимизированный доход = (Базовые единицы + (Базовые единицы * упругость цены * (% изменение оптимизированной цены по сравнению с обычной ценой) * (Оптимизированная цена) …….. (eq3)
Оптимизированный доход = (Базовые единицы + (Базовые единицы * упругость цены * [(Оптимизированная цена — Текущая цена)/ Текущая цена]* (Оптимизированная цена)…………..eq(4)
Ниже приведены ключевые параметры в уравнении оптимизации (eq4):
Базовые единицы = Средние продажи единицы по текущей цене.
Эластичность цены = вычисленное значение для эластичности цены товара
Текущая цена = Последняя цена продажи
Отлично! В нашем уравнении, помимо оптимизированной цены, у нас есть данные для всех остальных переменных. Какой алгоритм мы можем использовать для вычисления оптимизированной цены, максимизирующей прибыль? Мы просто можем использовать алгоритм оптимизации.
Какие компоненты необходимы для оптимизации:
- Целевая функция, которую необходимо минимизировать/максимизировать: Мы уже определили целевую функцию, которая заключается в максимизации оптимизированной прибыли, как определено в уравнении (4).
- Границы: Как определено руководителем магазина, нам необходимо, чтобы оптимизированная цена не менялась более чем на 20%. Таким образом, нижняя граница = Текущая цена (1–0.2) и Верхняя граница = Текущая цена (1+0.2)
- Алгоритм оптимизации: Мы будем использовать библиотеку Scipy.optimize из Python для реализации оптимизации.
Давайте посмотрим на код:
# Берем последние 6 недельные средние продажи базовых единиц#--------------------------------------------------# Ранжирование столбца с датамиdf_item_store_optimization["rank"] = df_item_store_optimization["ds"].rank(ascending=False)# Выбор последних 6 недель из базы данных_sales_df = df_item_store_optimization.loc[df_item_store_optimization["rank"] <= 6].groupby("id")["base_sales"].mean().reset_index()df_item_store_optimization_input.rename(columns = {"base_sales":"base_units"}, inplace=True)# Определение минимальной и максимальной границы для цены на продажу#--------------------------------------------------# Создание UB и LB с диапазоном в 20%df_item_store_optimization_input["LB_price"] = df_item_store_optimization_input["sell_price"] - (0.2*df_item_store_optimization_input["sell_price"])df_item_store_optimization_input["UB_price"] = df_item_store_optimization_input["sell_price"] + (0.2*df_item_store_optimization_input["sell_price"])
Вышеуказанный код помогает нам подготовить данные для оптимизации. Во-первых, мы вычисляем базовые единицы как среднее значение базовых продаж (трендовая составляющая декомпозированного ряда) за последние 6 недель. Мы уже обсудили методологию вычисления базовых продаж в предыдущем разделе.
Затем мы определяем LB_price и UB_price, уменьшая и увеличивая их на 20% от текущей цены продажи соответственно.
Давайте определим код для выполнения оптимизации.
from scipy.optimize import minimize# Определение целевой функции для минимизацииdef objective(opti_price): df_item_store_optimization_input["opti_price"] = opti_price df_item_store_optimization_input["optimized_units"] = df_item_store_optimization_input["base_units"] + (df_item_store_optimization_input["base_units"]*\ ((df_item_store_optimization_input["opti_price"]/df_item_store_optimization_input["sell_price"]) - 1)*\ (df_item_store_optimization_input["price_elasticity"])) df_item_store_optimization_input["optimized_revenue"] = df_item_store_optimization_input["optimized_units"]*df_item_store_optimization_input["opti_price"] return -sum(df_item_store_optimization_input["optimized_revenue"])# Определение начального значенияopti_price = df_item_store_optimization_input["sell_price"][0]# Определение границ для переменныхbounds = ((df_item_store_optimization_input["LB_price"][0], df_item_store_optimization_input["UB_price"][0]),)# # Использование алгоритма оптимизации для минимизации целевой функцииresult = minimize(objective, opti_price, bounds=bounds)# Вывод результата оптимизацииprint(result)
Вышеуказанный код даст нам оптимизированную цену. Можете ли вы догадаться, почему мы определяем отрицательную оптимизированную прибыль в целевой функции? Что такое -(-1)? Это 1. Мы минимизируем целевую функцию, и использование отрицательного знака для оптимизированной прибыли приведет к максимизации оптимизированной прибыли.
Более того, мы можем инициализировать переменную opti_price любым случайным значением, просто для облегчения быстрой сходимости мы инициализируем ее текущей ценой продажи. В границах мы определяем LB и UB, которые мы создали в вышеуказанном коде.
Ура! Мы нашли оптимизированную цену для Yochips и готовы предложить ее руководителю магазина в Калифорнии.

Наше рекомендация будет снизить цены на Yochips на 10.2% до $2.9. Это приведет к максимальному доходу.
Это последний шаг в подходе к оптимизации цен, и в целом этот подход настолько мощный, что он может помочь нам возвращать оптимизированные цены для каждого товара в каждом магазине.
Одним из ограничений вышеуказанного подхода является отсутствие достаточной истории изменения цен для некоторых товаров. В таком случае мы используем другие техники, но если доля таких товаров незначительна, то средняя эластичность цены на уровне категории может быть использована для таких товаров.
Надеюсь, вам понравилась эта статья!