Мультиканальная атрибуция на основе Воронки продаж

Это последний пост в серии статей об использовании многоканальной модели атрибуции в маркетинге. В предыдущих двух статьях (часть 1 и часть 2) мы рассмотрели простой и мощный подход, основанный на цепях Маркова, который позволяет эффективно использовать маркетинговые каналы.

В этой статье мы рассмотрим еще один интересный подход, который основан на эвристических и вероятностных методах. Опять же, основная идея проста и эффективна.

Воронка продаж

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

Принцип AIDA в маркетинге

  1. Осведомленность – клиент узнает о существовании продукта или услуги («Я не знал, что есть приложение для этого…»),
  2. Интерес – активное выражение интереса к группе продуктов («Мне нравится, как ваше приложение делает…»),
  3. Желание – стремление к определенному бренду или продукту («Думаю, что я могу купить годовой абонемент…»),
  4. Действие – следующий шаг к приобретению выбранного продукта («Где я могу ввести платежные реквизиты?»).

Для e-commerce мы можем придумать одно или несколько условий (событий / действий), которые служат доказательством прохождения каждого шага последовательности продаж.

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

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

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

  • 0 шаг (необходимое условие) – клиент посещает сайт в первый раз
  • 1-й шаг (осведомленность) – посещает две страницы сайта
  • 2-й шаг (интерес) – обзор страницы продукта
  • 3-й шаг (желание) – добавляет продукт в корзину покупок
  • 4-й шаг (действие) – завершает покупку

Во-вторых, нам нужно извлечь данные, содержащие сеансы, в которых произошли соответствующие события. Мы будем моделировать эти данные следующим кодом:

Код на R

library(tidyverse)
library(purrrlyr)
library(reshape2)
 
##### simulating the "real" data #####
set.seed(454)
df_raw <- data.frame(customer_id = paste0('id', sample(c(1:5000), replace = TRUE)), date = as.POSIXct(rbeta(10000, 0.7, 10) * 10000000, origin = '2017-01-01', tz = "UTC"), channel = paste0('channel_', sample(c(0:7), 10000, replace = TRUE, prob = c(0.2, 0.12, 0.03, 0.07, 0.15, 0.25, 0.1, 0.08))), site_visit = 1) %>%
 
mutate(two_pages_visit = sample(c(0,1),
10000,
replace = TRUE,
prob = c(0.8, 0.2)),
product_page_visit = ifelse(two_pages_visit == 1,
sample(c(0, 1),
length(two_pages_visit[which(two_pages_visit == 1)]),
replace = TRUE, prob = c(0.75, 0.25)),
0),
add_to_cart = ifelse(product_page_visit == 1,
sample(c(0, 1),
length(product_page_visit[which(product_page_visit == 1)]),
replace = TRUE, prob = c(0.1, 0.9)),
0),
purchase = ifelse(add_to_cart == 1,
sample(c(0, 1),
length(add_to_cart[which(add_to_cart == 1)]),
replace = TRUE, prob = c(0.02, 0.98)),
0)) %>%
dmap_at(c('customer_id', 'channel'), as.character) %>%
arrange(date) %>%
mutate(session_id = row_number()) %>%
arrange(customer_id, session_id)
df_raw <- melt(df_raw, id.vars = c('customer_id', 'date', 'channel', 'session_id'), value.name = 'trigger', variable.name = 'event') %>%
filter(trigger == 1) %>%
select(-trigger) %>%
arrange(customer_id, date)      select(-path_no)

[свернуть]

Образец данных выглядит так:
Таблица с данными для анализа

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

Важное значение в этом подходе имеет то, что нам нужно приписать исходный маркетинговый канал, который привел клиента к первому шагу. Например, клиент сначала просматривает страницу продукта (шаг 2, интерес) перейдя по каналу: channel_1. Это означает, что любые будущие посещения страниц продукта с других каналов не будут отнесены до тех пор, пока клиент не совершит покупку и не начнет новое путешествие к продажам.

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

Код на R

### removing not first events ###
df_customers <- df_raw %>%
 group_by(customer_id, event) %>%
 filter(date == min(date)) %>%
 ungroup()

[свернуть]

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

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

Код на R

### Sales Funnel probabilities ###
sf_probs <- df_customers %>%
  
 group_by(event) %>%
 summarise(customers_on_step = n()) %>%
 ungroup() %>%
  
 mutate(sf_probs = round(customers_on_step / customers_on_step[event == 'site_visit'], 3),
 sf_probs_step = round(customers_on_step / lag(customers_on_step), 3),
 sf_probs_step = ifelse(is.na(sf_probs_step) == TRUE, 1, sf_probs_step),
 sf_importance = 1 - sf_probs_step,
 sf_importance_weighted = sf_importance / sum(sf_importance)
 )

[свернуть]

Визуализируем нашу Воронку:

Код на R

### Sales Funnel visualization ###
df_customers_plot <- df_customers %>%
  
 group_by(event) %>%
 arrange(channel) %>%
 mutate(pl = row_number()) %>%
 ungroup() %>%
  
 mutate(pl_new = case_when(
 event == 'two_pages_visit' ~ round((max(pl[event == 'site_visit']) - max(pl[event == 'two_pages_visit'])) / 2),
 event == 'product_page_visit' ~ round((max(pl[event == 'site_visit']) - max(pl[event == 'product_page_visit'])) / 2),
 event == 'add_to_cart' ~ round((max(pl[event == 'site_visit']) - max(pl[event == 'add_to_cart'])) / 2),
 event == 'purchase' ~ round((max(pl[event == 'site_visit']) - max(pl[event == 'purchase'])) / 2),
 TRUE ~ 0
 ),
 pl = pl + pl_new)
 
df_customers_plot$event <- factor(df_customers_plot$event, levels = c('purchase',
 'add_to_cart', 
 'product_page_visit',
 'two_pages_visit',
 'site_visit'
 ))
 
# color palette
cols <- c('#4e79a7', '#f28e2b', '#e15759', '#76b7b2', '#59a14f',
 '#edc948', '#b07aa1', '#ff9da7', '#9c755f', '#bab0ac')
 
ggplot(df_customers_plot, aes(x = event, y = pl)) +
 theme_minimal() +
 scale_colour_manual(values = cols) +
 coord_flip() +
 geom_line(aes(group = customer_id, color = as.factor(channel)), size = 0.05) +
 geom_text(data = sf_probs, aes(x = event, y = 1, label = paste0(sf_probs*100, '%')), size = 4, fontface = 'bold') +
 guides(color = guide_legend(override.aes = list(size = 2))) +
 theme(legend.position = 'bottom',
 legend.direction = "horizontal",
 panel.grid.major.x = element_blank(),
 panel.grid.minor = element_blank(),
 plot.title = element_text(size = 20, face = "bold", vjust = 2, color = 'black', lineheight = 0.8),
 axis.title.y = element_text(size = 16, face = "bold"),
 axis.title.x = element_blank(),
 axis.text.x = element_blank(),
 axis.text.y = element_text(size = 8, angle = 90, hjust = 0.5, vjust = 0.5, face = "plain")) +
 ggtitle("Sales Funnel visualization - all customers journeys")

[свернуть]

Воронка продаж

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

Код на R

### computing attribution ###
df_attrib <- df_customers %>%
 # removing customers without purchase
 group_by(customer_id) %>%
 filter(any(as.character(event) == 'purchase')) %>%
 ungroup() %>%
  
 # joining step's importances
 left_join(., sf_probs %>% select(event, sf_importance_weighted), by = 'event') %>%
  
 group_by(channel) %>%
 summarise(tot_attribution = sum(sf_importance_weighted)) %>%
 ungroup()

[свернуть]

В результате мы получили количество конверсий, которые были распределены по каналам маркетинга:
Количество конверсий на основе мультиканальной атрибуции по Воронке продаж

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

Автор: Сергей Брыль, английский оригинал тут.

Добавить комментарий

Ваш e-mail не будет опубликован.