Анализ микро- и макроцелей
Проект МастерСлух™
Обзор данных
| Первые строки набора данных | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Источник данных: Директ | |||||||||||||||||||||
| Date | Calls | B24 | Forms | EMails | Goals | page2 | page3 | page4 | min3 | min6 | min8 | dl1 | dl2 | dl3 | dl4 | dl5 | dl6 | dl7 | dl8 | dl9 | dl10 |
| 2024-01-10 | 2 | 0 | 2 | 0 | 4 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
| 2024-01-11 | 0 | 1 | 0 | 0 | 1 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
| 2024-01-15 | 0 | 0 | 3 | 0 | 3 | 1 | 1 | NA | NA | NA | NA | 1 | 1 | 1 | 1 | 1 | NA | NA | NA | NA | NA |
| 2024-01-16 | 0 | 1 | 0 | 1 | 2 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
| 2024-01-17 | 1 | 0 | 0 | 0 | 1 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
| 2024-01-18 | 0 | 1 | 0 | 0 | 1 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
| Последние строки набора данных | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Источник данных: Директ | |||||||||||||||||||||
| Date | Calls | B24 | Forms | EMails | Goals | page2 | page3 | page4 | min3 | min6 | min8 | dl1 | dl2 | dl3 | dl4 | dl5 | dl6 | dl7 | dl8 | dl9 | dl10 |
| 2024-03-27 | 2 | 1 | 0 | 0 | 3 | 18 | 12 | 7 | 10 | 5 | 3 | 26 | 22 | 18 | 15 | 12 | 10 | 9 | 8 | 7 | 5 |
| 2024-03-28 | 1 | 0 | 0 | 1 | 2 | 13 | 11 | 8 | 7 | 6 | 5 | 25 | 21 | 16 | 15 | 13 | 13 | 12 | 12 | 10 | 9 |
| 2024-03-29 | 0 | 1 | 0 | 0 | 1 | 9 | 4 | 2 | 5 | 3 | 2 | 19 | 17 | 10 | 9 | 6 | 6 | 2 | 2 | 2 | 2 |
| 2024-03-30 | 0 | 0 | 0 | 1 | 1 | 12 | 8 | 5 | 6 | 3 | 2 | 20 | 16 | 14 | 12 | 10 | 9 | 9 | 8 | 7 | 7 |
| 2024-03-31 | NA | NA | NA | NA | NA | 7 | 4 | 3 | 5 | 4 | 4 | 20 | 16 | 13 | 8 | 8 | 6 | 6 | 5 | 3 | 3 |
| 2024-04-01 | NA | NA | NA | NA | NA | 14 | 10 | 6 | 7 | 5 | 4 | 25 | 18 | 15 | 13 | 9 | 6 | 6 | 5 | 4 | 4 |
| Глосарий по макро и микроцелям | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Goals | Calls | B24 | Forms | EMails | page2 | page3 | page4 | min3 | min6 | min8 | dl |
| Сумма главных целей | Главная цель. Звонок | Главная цель. Отправка сообщения через виджит Б24 | Главная цель. Отправка формы с сайта | Главная цель. Клик или копирование email | Микроцель. Просмотрено 2 страницы | Микроцель. Просмотрено 3 страницы | Микроцель. Просмотрено 4 страницы | Микроцель. Проведено на сайте от 3 минут | Микроцель. Проведено на сайте от 6 минут | Микроцель. Проведено на сайте от 8 минут | Микроцель. Специальная многосоставная цель |
Из-за того, что дополнительные микроцели были настроены в конце февраля при соединении данных в один набор, где ключом был столбец «Дата», образовалось множество пропущенных значений.
Рассмотрим данные на графике.
Код
# преобразуем данные в длинный форма
plot_df <- df |>
pivot_longer(
cols = 2:ncol(df),
names_to = "Name",
values_to = "Value"
)
# строим график
ggplot(
plot_df,
aes(
x = Date ,
y = Value,
group = Name,
fill = Name)
) +
geom_col()+
scale_x_date(
date_breaks = "2 day",
date_labels = "%d.%m"
) +
theme_minimal() +
labs(
title = "Данные по макро- и микроцелям",
subtitle = "Источник: Директ",
x = NULL,
y = "Кол-во целей",
fill = NULL
) +
theme(
plot.title = element_text(size = 12, color = "gray40"),
plot.subtitle = element_text(size = 10, color = "gray50"),
axis.title = element_text(size = 8, color = "gray50"),
axis.text = element_text(size = 7, color = "gray50"),
axis.text.x = element_text(angle = 90),
panel.grid = element_blank(),
legend.position = "top",
legend.justification = "left",
legend.box.spacing = unit(0.1, "cm"),
legend.text = element_text(size = 8, color = "gray50"),
plot.margin = ggplot2::margin(
t = 0.3,
r = 0.3,
b = 0.3,
l = 0.3,
"cm"
)
)Данные начинают поступать в нормальном объеме с 24.02.24. С этой даты сформируем новый набор данных.
Проверим по колонкам кол-во пропущенных значений.
Код
# проверка на NA по столбцам
na_df <- df |>
reframe(
across(
where(is.numeric),
list(na = function(x, ...) sum(is.na(x)))
)
)
# строим график для анализа NA
na_df_plt <- na_df |>
pivot_longer(
cols = ends_with("na"),
names_to = "Name",
values_to = "Value"
) |>
ggplot(aes(x = Name, y = Value)) +
geom_col(fill = '#ff79c6') +
theme_minimal() +
labs(
title = " NA по макро- и микроцелям",
subtitle = "Источник: Директ",
x = NULL,
y = "Кол-во целей"
) +
theme(
plot.title = element_text(size = 12, color = "gray40"),
plot.subtitle = element_text(size = 10, color = "gray50"),
axis.title = element_text(size = 8, color = "gray50"),
axis.text = element_text(size = 8, color = "gray50"),
axis.text.x = element_text(angle = 90),
panel.grid = element_blank(),
plot.margin = ggplot2::margin(
t = 0.3,
r = 0.3,
b = 0.3,
l = 0.3,
"cm"
)
)
# создаем интерактивный график
plotly::ggplotly(na_df_plt)Итог
- Необходимо уменьшить объем данных.
- Либо удалить NA значения либо заменить их на 0. Замена не совсем верное решение, однако мы и не бозон Хиггса исследуем. Для наших целей приемлемое решение.
Все манипуляции делаются для минимизации ошибок в расчетах.
Препроцессинг данных
Уменьшим объем данных.
Код
sf <- df |>
filter(Date >= "2024-02-24")
gt(head(sf)) |>
tab_header(
title = "Обработанные данные",
subtitle = "Источник данных: Директ"
) |>
tab_options(table.font.size = "small")| Обработанные данные | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Источник данных: Директ | |||||||||||||||||||||
| Date | Calls | B24 | Forms | EMails | Goals | page2 | page3 | page4 | min3 | min6 | min8 | dl1 | dl2 | dl3 | dl4 | dl5 | dl6 | dl7 | dl8 | dl9 | dl10 |
| 2024-02-24 | NA | NA | NA | NA | NA | 21 | 2 | NA | 62 | 19 | 16 | 6 | 3 | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 1 |
| 2024-02-25 | 1 | 1 | 0 | 0 | 2 | 10 | 2 | 2 | 35 | 12 | 8 | 16 | 9 | 6 | 5 | 4 | 4 | 3 | 3 | 3 | 3 |
| 2024-02-26 | NA | NA | NA | NA | NA | 9 | 1 | NA | 53 | 20 | 16 | 19 | 10 | 6 | 6 | 5 | 2 | 2 | 2 | 2 | 1 |
| 2024-02-27 | NA | NA | NA | NA | NA | 8 | 4 | 2 | 2 | 1 | 1 | 18 | 12 | 12 | 8 | 5 | 3 | 2 | 2 | 2 | 2 |
| 2024-02-28 | 1 | 0 | 0 | 0 | 1 | 9 | 5 | 3 | 7 | 4 | 2 | 27 | 21 | 15 | 10 | 7 | 6 | 4 | 2 | 2 | 2 |
| 2024-02-29 | 1 | 1 | 0 | 0 | 2 | 7 | 4 | 1 | 12 | 4 | 3 | 15 | 11 | 8 | 6 | 3 | 3 | 3 | 3 | 3 | 2 |
Проверяем на пропущенные значения.
Код
# проверка на NA по столбцам
na_df <- sf |>
reframe(
across(
where(is.numeric),
list(na = function(x, ...) sum(is.na(x)))
)
)
# строим график для анализа NA
na_df_plt <- na_df |>
pivot_longer(
cols = ends_with("na"),
names_to = "Name",
values_to = "Value"
) |>
ggplot(aes(x = Name, y = Value)) +
geom_col(fill = '#ff79c6') +
theme_minimal() +
labs(
title = " NA по макро- и микроцелям",
subtitle = "Источник: Директ",
x = NULL,
y = "Кол-во целей"
) +
theme(
plot.title = element_text(size = 12, color = "gray40"),
plot.subtitle = element_text(size = 10, color = "gray50"),
axis.title = element_text(size = 8, color = "gray50"),
axis.text = element_text(size = 8, color = "gray50"),
axis.text.x = element_text(angle = 90),
panel.grid = element_blank(),
plot.margin = ggplot2::margin(
t = 0.3,
r = 0.3,
b = 0.3,
l = 0.3,
"cm"
)
)
# создаем интерактивный график
plotly::ggplotly(na_df_plt)Так намного лучше.
Разбить данные по неделям и найти подходящие цели.
Код
sf <- df |>
filter(Date >= "2024-02-24")
micro_sf <- sf |>
mutate(Week = clock::date_format(Date, format = "%W")) |>
reframe(
across(c(2:ncol(sf)), sum),
.by = c(Week)
) |>
select(1,7:ncol(sf)) |>
slice(2:6)
micro_sf[is.na(micro_sf)] <- 0
gt(micro_sf, rowname_col = "Week") |>
tab_header(
title = "Микроцели сгруппированные по неделям",
subtitle = "Источник данных: Директ"
) |>
data_color(
columns = 1:ncol(micro_sf),
fn = \(v) lapply(v, \(x) if (x < 30) "darkred" else if (x > 100) "darkgreen" else "grey"),
apply_to = "text"
)| Микроцели сгруппированные по неделям | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Источник данных: Директ | ||||||||||||||||
| page2 | page3 | page4 | min3 | min6 | min8 | dl1 | dl2 | dl3 | dl4 | dl5 | dl6 | dl7 | dl8 | dl9 | dl10 | |
| 09 | 77 | 28 | 0 | 133 | 56 | 41 | 187 | 121 | 94 | 71 | 50 | 37 | 29 | 25 | 19 | 17 |
| 10 | 89 | 51 | 29 | 75 | 27 | 0 | 172 | 122 | 88 | 72 | 56 | 40 | 36 | 32 | 28 | 26 |
| 11 | 87 | 50 | 32 | 64 | 36 | 26 | 190 | 153 | 119 | 98 | 84 | 71 | 61 | 55 | 43 | 37 |
| 12 | 89 | 51 | 40 | 66 | 34 | 27 | 186 | 146 | 119 | 97 | 85 | 68 | 58 | 52 | 43 | 38 |
| 13 | 93 | 59 | 38 | 56 | 36 | 28 | 179 | 148 | 117 | 99 | 78 | 71 | 62 | 54 | 44 | 39 |
Код
nano_tbl <- micro_sf |>
pivot_longer(
cols = -Week,
names_to = "Goals",
values_to = "Value"
) |>
pivot_wider(
names_from = "Week",
values_from = "Value"
)
gt(nano_tbl, rowname_col = "Goals") |>
tab_header(
title = "Nanoplot",
) |>
cols_nanoplot(
columns = 2:ncol(nano_tbl),
plot_type = "bar",
missing_vals = "zero",
new_col_name = "Значения неделям",
plot_height = "2.5em",
options = nanoplot_options(
data_bar_stroke_color = "gray",
data_bar_fill_color = "#ff79c6")
)|>
tab_options(
table.width = px(300),
column_labels.hidden = TRUE
) |>
cols_align(
align = "center",
columns = everything()
)| Nanoplot | |
|---|---|
| page2 | |
| page3 | |
| page4 | |
| min3 | |
| min6 | |
| min8 | |
| dl1 | |
| dl2 | |
| dl3 | |
| dl4 | |
| dl5 | |
| dl6 | |
| dl7 | |
| dl8 | |
| dl9 | |
| dl10 | |
Итог
Особое внимание уделить микроцелям:
- dl1
- dl2
- dl3
Остальные микроцели тоже могут подойти, но на выделенные обращаем внимание в первую очередь.
Микроцель «min8» может не подойти, но надо смотреть уровень корреляции и значение объясняющего коэффициента \(R^2\) в регрессионном анализе.
Корреляционный анализ
Попробуем удалить строки с NA и провести корранализ.
Код
# создаем матрицу p-value
df_psych <- cor_df |>
psych::corr.test(adjust = "BH")
# создаем график
ggcorrplot::ggcorrplot(
corr = df_psych$r,
hc.order = FALSE,
type = "lower",
method = "square",
lab = TRUE,
lab_size = 3,
p.mat = df_psych$p,
pch.cex = 8,
tl.cex = 8,
pch.col = "red",
title = "Корреляционная матрица",
outline.color = "white",
lab_col = "gray20",
show.diag = TRUE
) +
theme(
plot.title = element_text(size = 12, color = "gray40"),
axis.text = element_text(color = "gray50"),
axis.text.x = element_text(angle = 90),
panel.grid = element_blank()
)Анализ без удаленных строк.
Код
# создаем матрицу p-value
df_psych <- cor_df |>
psych::corr.test(adjust = "BH")
# создаем график
ggcorrplot::ggcorrplot(
corr = df_psych$r,
hc.order = FALSE,
type = "lower",
method = "square",
lab = TRUE,
lab_size = 3,
p.mat = df_psych$p,
pch.cex = 8,
tl.cex = 8,
pch.col = "red",
title = "Корреляционная матрица",
outline.color = "white",
lab_col = "gray20",
show.diag = TRUE
) +
theme(
plot.title = element_text(size = 12, color = "gray40"),
axis.text = element_text(color = "gray50"),
axis.text.x = element_text(angle = 90),
panel.grid = element_blank()
)Итог
При втором варианте обработки данных (замена NA значений на 0) убивал силу корреляции. Это следовало ожидать, так как мы добавили больше нулей в данные, поэтому этот способ не лучший для анализа, так как NA не равно 0.
Тут нужно быть внимательным к интерпретации NA. Как объяснить причину их появления? Можно ли удалить строки с NA?
В нашем случаи NA появились, входе обработки данных, когда соединяли матрицу главных целей с матрицей микроцелей. Образовались дни, когда главных целей не было вообще, а микроцели поступали.
С одной стороны в нашем случаи нули это уместное решение, так как это можно интерпретировать, что рекламные кампании работали (потому что поступали микроцели), но не приносили главных целей. С другой стороны если нет данных по макроцелям, значит можно их удалить, так как мы не можем анализировать пустое место.
В любом случаи наши корр. матрицы не отличаются критично. Поэтому берем в работу любую.
Цветовым кодированием обозначена сила корреляции и её направление. Красные крестики в квадратах означают, что мы не прошли проверку уровня \(\alpha\). Т.е. не можем принять альтернативную гипотезу о том, что данные имеют взаимосвязь между собой.
Проверку проходили с поправкой на множественные сравнения Бенджамини — Хохберга.
Проблемой множественных сравнений (multiple comparisons problem), заключается в следующем. Если мы проверяем сразу несколько гипотез, то у нас возрастает групповая вероятность ошибки первого рода (Family-wise error rate) — вероятность ошибки первого рода для хотя бы одной из множества гипотез.
Например, если вы коррелируете 10 переменных друг с другом, то вы проверяете 45 гипотез о связи. Пять процентов из этих гипотез, т.е. в среднем 2-3 гипотезы у вас будут статистически значимыми даже если никаких эффектов на самом деле нет!
Поэтому если проверяется сразу много гипотез, то необходимо применять поправки на множественные сравнения. Эти поправки позволяют контролировать групповую вероятность ошибки первого рода на желаемом уровне.
Микроцели для тестирования
Отметим, что у нас высокий уровень конверсии между суммой целей «Goals» и входящими звонками «Calls». Это означает, что большая часть суммированной цели состоит из звонков. По нашим фактическим данным это действительно так. В мае поступило больше обращений через звонки, чем через другие каналы. А это значит, с большой долей вероятности, тестируя микроцели мы будем увеличивать кол-во входящих звонков.
Статистически достоверной корреляции между главными целями Б24, Forms, Emails и микроконверсиями не обнаружено.
Тестируем следующие цели в порядки очереди:
- dl3
- dl6
- min6
- page2
Дополнительно тестируем (при отрицательных результатах)
- dl5
- dl4
Проведем регрессионый анализ с выбранными целями для окончательного утверждения на тестирование.
Возможно, стоит провести многофакторный анализ для создания специальных целей типа dl3 + page2.