Фото Энни Спратт на Unsplash
Представьте, что вы работаете в отделе маркетинга и хотите выяснить, окупились ли ваши рекламные инвестиции. Люди, которые читали мои другие статьи, знают, как это сделать: моделирование маркетингового микса! Этот метод увлекателен, потому что он работает и в мире без файлов cookie.
Введение в моделирование маркетингового микса в Python
Я также рассматривал байесовское моделирование маркетингового микса — способ получить более надёжные модели и оценки неопределённости для всего, что вы прогнозируете.
Байесовское моделирование маркетингового микса в Python с помощью PyMC3
Байесовский подход отлично работает для однородных данных, то есть эффекты ваших рекламных расходов сопоставимы по всему набору данных. Но что происходит, когда у нас есть разнородный набор данных, например, расходы по нескольким странам? Есть два очевидных способа справиться с этим:
- Игнорировать тот факт, что в наборе данных несколько стран, и построить одну большую модель.
- Построить одну модель для каждой страны.
К сожалению, у обоих методов есть свои недостатки. Если игнорировать страну, у вас получится слишком грубая модель; вероятно, она будет недообученной. С другой стороны, если вы построите модель для каждой страны, у вас может получиться слишком много моделей, за которыми нужно следить. И что ещё хуже, если в некоторых странах мало точек данных, ваша модель там может переобучиться.
Обычно эффективнее создать гибридную модель, которая находится где-то между этими двумя подходами: байесовское иерархическое моделирование! Вы можете прочитать об этом подробнее здесь:
Байесовское иерархическое моделирование в PyMC3
Какую пользу мы можем извлечь из этого в нашем случае? Например, байесовское иерархическое моделирование может создать модель, в которой значения переноса ТВ в соседних странах будут не слишком далеки друг от друга, что противодействует эффектам переобучения.
Однако если данные предполагают, что параметры на самом деле полностью отличаются, байесовская иерархическая модель сможет это уловить, если будет достаточно данных.
В дальнейшем я покажу вам, как объединить байесовское моделирование маркетингового микса (BMMM) с байесовским иерархическим моделированием (BHM), чтобы создать — возможно, вы догадались — байесовскую иерархическую модель маркетингового микса (BHMMM) в Python с помощью PyMC.
BHMMM = BMMM + BHM
Исследователи из бывшей Google Inc. также написали статью об этой идее, которую я рекомендую вам изучить позже. [1] Вы сможете понять эту статью достаточно хорошо после того, как ознакомитесь с моими статьями о BMMM и BHM.
Обратите внимание, что я больше не использую PyMC** 3**, а PyMC, которая является обновлением этой замечательной библиотеки. К счастью, если вы раньше знали PyMC3, вы сможете разобраться в PyMC. Давайте начнём!
Подготовка
Сначала мы загрузим синтетический набор данных, который я придумал, который подходит для тренировочных целей.
dataset_link = "https://raw.githubusercontent.com/Garve/datasets/fdb81840fb96faeda5a874efa1b9bbfb83ce1929/bhmmm.csv"
data = pd.read_csv(dataset_link)
X = data.drop(columns=["Sales", "Date"])
y = data["Sales"]
Данные, созданные автором. Изображение автора.
Теперь позвольте мне скопировать некоторые функции из моей другой статьи, одну для вычисления экспоненциального насыщения и одну для работы с переносами. Я скорректировал их — то есть изменил theano.tensor на aesara.tensor, а tt на at — чтобы они работали с новой PyMC.
import aesara.tensor as at
def saturate(x, a):
return 1 - at.exp(-a*x)
def carryover(x, strength, length=21):
w = at.as_tensor_variable(
[at.power(strength, i) for i in range(length)]
)
x_lags = at.stack(
[at.concatenate([
at.zeros(i),
x[:x.shape[0]-i]
]) for i in range(length)]
)
return at.dot(w, x_lags)
Мы можем начать моделирование сейчас.
Построение BHMMM
Прежде чем приступить к полной модели, мы могли бы начать с построения отдельных моделей, чтобы посмотреть, что произойдёт, и получить базовый уровень.
Отдельные модели
Если мы будем следовать методологии отсюда, мы получим следующее для Германии:
Прогноз модели для Германии. Изображение автора.
Достаточно хорошая подгонка. Однако для Швейцарии у нас есть только 20 наблюдений, поэтому прогнозы не слишком велики:
Прогноз модели для Швейцарии. Изображение автора.
Это именно та причина, по которой подход с отдельными моделями иногда проблематичен. Есть основания полагать, что люди в Швейцарии не слишком отличаются от людей в Германии в отношении воздействия на них средств массовой информации, и модель должна быть в состоянии это уловить.
Мы также можем увидеть, чему модель Швейцарии научилась относительно параметров:
Апостериорные значения для модели Швейцарии. Изображение автора.
Апостериорные значения всё ещё достаточно широки из-за нехватки точек данных в Швейцарии. Вы можете увидеть это по параметрам car_ справа: 94% HDI переносов почти охватывает весь возможный диапазон между 0 и 1.
Давайте теперь построим настоящую BHMMM, чтобы особенно Швейцария могла извлечь выгоду из большего количества данных, которые у нас есть из Германии и Австрии.
Реализация PyMC
Мы вводим несколько гиперприорных значений, которые формируют базовое распределение по всем странам. Например, перенос моделируется с помощью бета-распределения. У этого распределения есть два параметра α и β, и мы резервируем два гиперприорных значения car_alpha и car_beta для моделирования этих параметров.
В строке 15 вы можете увидеть, как затем используются гиперприорные значения для определения переноса по странам и каналам. Кроме того, я использую больше шагов настройки, чем обычно — 3000 вместо 1000 — потому что модель довольно сложная. Большее количество шагов настройки облегчает модели процесс вывода.
with pm.Model() as bhmmm:
coef_lam = pm.Exponential("coef_lam", lam=10)
sat_lam = pm.Exponential("sat_lam", lam=10)
car_alpha = pm.Exponential("car_alpha", lam=0.01)
car_beta = pm.Exponential("car_beta", lam=0.01)
base_lam = pm.Exponential("base_lam", lam=10)
for country in X["Country"].unique():
X_ = X[X["Country"] == country]
channel_contributions = []
for channel in ["TV", "Radio", "Banners"]:
coef = pm.Exponential(f"coef_{channel}_{country}", lam=coef_lam)
sat = pm.Exponential(f"sat_{channel}_{country}", lam=sat_lam)
car = pm.Beta(f"car_{channel}_{country}", alpha=car_alpha, beta=car_beta)
channel_data = X_[channel].values
channel_contribution = pm.Deterministic(
f"contribution_{channel}_{country}",
coef * saturate(carryover(channel_data, car), sat),
)
channel_contributions.append(channel_contribution)
base = pm.Exponential(f"base_{country}", lam=base_lam)
noise = pm.Exponential(f"noise_{country}", lam=0.001)
sales = pm.Normal(
f"sales_{country}",
mu=sum(channel_contributions) + base,
sigma=noise,
observed=y[X_.index].values,
)
trace = pm.sample(tune=3000)
И это всё!
Проверка выходных данных
Давайте посмотрим только на то, насколько хорошо модель фиксирует данные.
Результаты прогнозирования BHMMM для Германии и Австрии. Изображение автора.
Я не буду проводить сейчас никаких реальных проверок с помощью метрик, но по графикам мы видим, что производительность Германии и Австрии выглядит вполне прилично.
Если мы сравним Швейцарию из BHMMM с версией BMMM, которую мы видели ранее, мы также увидим, что теперь она выглядит намного лучше.
Результаты прогнозирования BHMMM (слева) и BMMM (справа) для Швейцарии. Изображение автора.
Это возможно только потому, что мы дали Швейцарии некоторый контекст, используя данные других похожих стран.
Мы также можем увидеть, как сузились апостериорные значения переносов Швейцарии:
Изображение автора.
Некоторые распределения всё ещё немного дикие, и нам пришлось бы разобраться, как это исправить. Могут быть проблемы с выборкой или плохие априорные значения, среди прочего. Однако мы не будем делать этого здесь.
Заключение
В этой статье мы кратко рассмотрели две разные байесовские концепции:
- Байесовское моделирование маркетингового микса для анализа маркетинговых расходов, а также
- Байесовское иерархическое моделирование.
Объединив оба подхода, мы создали ещё более совершенную байесовскую модель маркетингового микса. Это особенно удобно, если вы имеете дело с некоторой иерархией, например, при построении модели маркетингового микса для нескольких связанных стран.
Этот метод работает так хорошо, потому что он даёт модели контекст: если вы скажете модели предоставить прогноз для одной страны, она сможет учесть информацию о других странах. Это имеет решающее значение, если модель должна работать с набором данных, который в противном случае был бы слишком мал.
Ещё одна мысль, которую я хочу вам предложить на вашем пути, заключается в следующем: в этой статье мы использовали иерархию стран. Однако вы можете подумать и о других иерархиях, например, о иерархии каналов. Иерархия каналов может возникнуть, если вы скажете, что разные каналы должны вести себя не слишком по-разному, например, если ваша модель учитывает не только расходы на баннеры, но и расходы на баннеры на веб-сайте A и расходы на баннеры на веб-сайте B, где поведение пользователей на веб-сайтах A и B не слишком отличается.
Ссылки
[1] Y. Sun, Y. Wang, Y. Jin, D. Chan, J. Koehler, Geo-level Bayesian Hierarchical Media Mix Modeling (2017)
Надеюсь, вы узнали что-то новое, интересное и полезное сегодня. Спасибо за чтение!
Если у вас есть вопросы, напишите мне в LinkedIn!
И если вы хотите глубже погрузиться в мир алгоритмов, попробуйте мою новую публикацию Всё об алгоритмах! Я всё ещё ищу авторов!
Всё об алгоритмах
