Освоение моделирования маркетингового Комплекса на Python

Автор: Дмитрий Иванов [Команда P9X]

~8 минут чтения

Что представляет собой эта серия статей?

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

Введение

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

  • Какие открытые пакеты мы можем использовать?
  • Что такое байесовский МММ?
  • Что такое байесовские априорные значения?
  • Разумно ли использовать априорные значения по умолчанию в pymc-marketing?

Затем мы перейдём к пошаговому руководству по Python, используя пакет pymc-marketing, углубляясь в следующие области:

  • Моделирование данных.
  • Обучение модели.
  • Валидация модели.
  • Восстановление параметров.

Полный блокнот можно найти здесь:

pymc_marketing/notebooks/1. training marketing mix models (MMM) in python.ipynb at main ·…

1.0 Фон МММ

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

1.1 Какие открытые пакеты мы можем использовать?

Когда дело доходит до МММ, мы можем использовать несколько пакетов с открытым исходным кодом:

  1. Python Совместимость: в отличие от Robyn, который доступен только в R, pymc-marketing ориентирован на более широкую аудиторию, предпочитающую работать в Python.
  2. Текущая доступность: Meridian ещё не выпущен (по состоянию на 23 сентября 2024 года), что делает pymc-marketing более доступным вариантом прямо сейчас.
  3. Будущие соображения: LightweightMMM будет выведен из эксплуатации после запуска Meridian, что ещё больше укрепит необходимость в надёжной альтернативе.
  4. Активное развитие: pymc-marketing постоянно совершенствуется благодаря обширному сообществу участников, что обеспечивает его актуальность новыми функциями и улучшениями.

Вы можете ознакомиться с пакетом pymc-marketing здесь, они предлагают несколько замечательных ноутбуков, чтобы проиллюстрировать некоторые функции пакета:

How-to – pymc-marketing 0.9.0 documentation

1.2 Что такое байесовский МММ?

Вы заметите, что 3 из 4 выделенных выше пакетов используют байесовский подход. Давайте потратим немного времени, чтобы понять, как выглядит байесовский МММ! Для новичков байесовский анализ — это своего рода кроличья нора, но мы можем разбить его на 5 ключевых моментов:

  1. Теорема Байеса — в байесовском МММ теорема Байеса используется для обновления наших представлений о том, как маркетинговые каналы влияют на продажи, по мере сбора новых данных.
  2. P(θ)Априорные значения представляют наши первоначальные представления о параметрах в модели, таких как влияние расходов на ТВ на продажи.
  3. P(Data | θ)Функция правдоподобия, которая отражает вероятность наблюдения данных о продажах при определённых уровнях маркетинговых вложений.
  4. P(θ | Data)Апостериорное значение — это то, что нас в конечном итоге интересует в байесовском МММ — это наше обновлённое представление о том, как различные маркетинговые каналы влияют на продажи после объединения данных и наших априорных предположений.
  5. Выборка — поскольку байесовский МММ включает в себя сложные модели с несколькими параметрами (например, адстоком, насыщением, эффектами маркетинговых каналов, контрольными эффектами и т. д.), вычисление апостериорного значения напрямую может быть затруднено. MCMC (Markov Chain Monte Carlo) позволяет нам аппроксимировать апостериорное значение, генерируя выборки из распределения каждого параметра.

1.3 Что такое байесовские априорные значения?

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

Общие распределения, используемые для априорных значений:

  • Нормальное: для параметров, где мы ожидаем, что значения будут группироваться вокруг среднего.
  • Полунормальное: для параметров, где мы хотим обеспечить положительность.
  • Бета: для параметров, которые ограничены между 0 и 1.
  • Гамма: для параметров, которые являются положительными и асимметричными.

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

1.4 Разумно ли использовать априорные значения по умолчанию в pymc-marketing?

При использовании пакета pymc-marketing априорные значения по умолчанию разработаны так, чтобы быть слабо информативными, что означает, что они предоставляют общие рекомендации, не будучи слишком конкретными. Они направляют модель, не ограничивая её слишком сильно. Этот баланс обеспечивает, что априорные значения направляют модель, не затмевая данные.

Чтобы построить надёжные модели, важно понимать априорные значения по умолчанию, а не использовать их вслепую. В следующих разделах мы рассмотрим различные априорные значения, используемые в pymc-marketing, и объясним, почему выбор по умолчанию является разумным для моделей маркетингового микса.

1.4.1 Адсток альфа

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

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

alpha = 1
beta_param = 3

x1 = np.linspace(0, 1, 100)
y1 = beta.pdf(x1, alpha, beta_param)

plt.figure(figsize=(8, 5))
plt.plot(x1, y1, color='blue')
plt.fill_between(x1, y1, color='blue', alpha=0.3)
plt.title('Geometric Adstock: Beta distribution (alpha=1, beta=3)')
plt.xlabel('Adstock alpha')
plt.ylabel('Probability density')
plt.grid(True)
plt.show()

Мы обычно ограничиваем значения адстока альфа между 0 и 1, что делает бета-распределение разумным выбором.

1.4.2 Сатурация ламда

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

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

alpha = 3
beta = 1

x2 = np.linspace(0, 10, 1000)
y2 = gamma.pdf(x2, alpha, scale=1/beta)

plt.figure(figsize=(8, 6))
plt.plot(x2, y2, 'b-')
plt.fill_between(x2, y2, alpha=0.2, color='blue')
plt.title('Logistic Saturation: Gamma Distribution (alpha=3, beta=1)')
plt.xlabel('Saturation lamda')
plt.ylabel('Probability density')
plt.grid(True)
plt.show()

1.4.3 Сатурация бета

Сатурация бета соответствует коэффициенту маркетингового канала, измеряющему влияние расходов на маркетинг.

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

sigma = 2

x = np.linspace(mu - 4*sigma, mu + 4*sigma, 100)
y = halfnorm.pdf(x, scale=sigma)

plt.figure(figsize=(8, 5))
plt.plot(x, y, color='blue')
plt.fill_between(x, y, color='blue', alpha=0.3)
plt.title('Saturation beta prior: HalfNormal Distribution (sigma=2)')
plt.xlabel('Saturation beta')
plt.ylabel('Probability Density')
plt.grid(True)
plt.show()

1.4.4 Гамма контроль

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

Для гамма-контроля используется нормальное распределение, которое допускает как положительные, так и отрицательные эффекты:

mu = 0
sigma = 2

x = np.linspace(mu - 4*sigma, mu + 4*sigma, 100)
y = norm.pdf(x, mu, sigma)

plt.figure(figsize=(8, 5))
plt.plot(x, y, color='blue')
plt.fill_between(x, y, color='blue', alpha=0.3)
plt.title('Control: Normal distribution (mu=0, sigma=2)')
plt.xlabel('Control value')
plt.ylabel('Probability density')
plt.grid(True)
plt.show()

2.0 Пошаговое руководство по Python

Теперь, когда мы рассмотрели теорию, давайте применим её на практике! В этом пошаговом руководстве мы рассмотрим:

  • Моделирование данных.
  • Обучение модели.
  • Валидация модели.
  • Восстановление параметров.

Цель — создать реалистичные тренировочные данные, где мы сами зададим параметры (адсток, насыщение, бета и т. д.), обучим и проверим модель, используя пакет pymc-marketing, а затем оценим, насколько хорошо наша модель восстановила параметры.

2.1 Моделирование данных

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

import pandas as pd
import numpy as np
from pymc_marketing.mmm.transformers import geometric_adstock, logistic_saturation
from sklearn.preprocessing import MaxAbsScaler

def data_generator(start_date, periods, channels, spend_scalar, adstock_alphas, saturation_lamdas, betas, freq="W"):
    '''
    Generates a synthetic dataset for a MMM with trend, seasonality, and channel-specific contributions.
    '''
    # [код для генерации данных]
    return df

2.2 Обучение модели

Теперь пришло время обучить модель. Для начала нам нужно подготовить обучающие данные:

date_col = "date"

y_col = "sales"

channel_cols = ["tv_spend_raw",
                "social_spend_raw",
                "search_spend_raw"]

control_cols = ["demand_proxy"]

X = df[[date_col] + channel_cols + control_cols]
y = df[y_col]

test_len = 8

train_idx = slice(0, len(df) - test_len)
out_of_time_idx = slice(len(df) - test_len, len(df))

2.3 Валидация модели

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

mmm_default.idata["sample_stats"]["diverging"].sum().item()

2.4 Восстановление параметров

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

2.4.1 Восстановление параметров — Адсток

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

fig = mmm_default.plot_channel_parameter(param_name="adstock_alpha", figsize=(9, 5))
ax = fig.axes[0]
ax.axvline(x=adstock_alphas[0], color="C0", linestyle="--", label=r"$alpha_1$")
ax.axvline(x=adstock_alphas[1], color="C1", linestyle="--", label=r"$alpha_2$")
ax.axvline(x=adstock_alphas[2], color="C2", linestyle="--", label=r"$alpha_3$")
ax.legend(loc="upper right");

2.4.2 Восстановление параметров — Сатурация

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

fig = mmm_default.plot_channel_parameter(param_name="saturation_lam", figsize=(9, 5))
ax = fig.axes[0]
ax.axvline(x=saturation_lamdas[0], color="C0", linestyle="--", label=r"$lambda_1$")
ax.axvline(x=saturation_lamdas[1], color="C1", linestyle="--", label=r"$lambda_2$")
ax.axvline(x=saturation_lamdas[2], color="C2", linestyle="--", label=r"$lambda_3$")
ax.legend(loc="upper right");

2.4.3 Восстановление параметров — Канальные беты

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

fig = mmm_default.plot_channel_parameter(param_name="saturation_beta", figsize=(9, 5))
ax = fig.axes[0]
ax.axvline(x=betas_scaled[0], color="C0", linestyle="--", label=r"$beta_1$")
ax.axvline(x=betas_scaled[1], color="C1", linestyle="--", label=r"$beta_2$")
ax.axvline(x=betas_scaled[2], color="C2", linestyle="--", label=r"$beta_3$")
ax.legend(loc="upper right");

2.4.4 Восстановление параметров — Канальный вклад

Сначала мы вычисляем истинные вклады для каждого канала. Мы также вычислим вклад спроса: помните, что мы включили прокси для спроса, а не сам спрос.

channels = np.array(["tv", "social", "search", "demand"])

true_contributions = pd.DataFrame({'Channels': channels, 'Contributions': contributions})
true_contributions= true_contributions.sort_values(by='Contributions', ascending=False).reset_index(drop=True)
true_contributions = true_contributions.style.bar(subset=['Contributions'], color='lightblue')

true_contributions

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

mmm_default.plot_waterfall_components_decomposition(figsize=(10,6));

Заключительные мысли

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


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