library(data.table) # работа с табличными данными
library(dplyr) # для дополнительных функций обработки данных
library(echarts4r) # для построения красивых графиков
library(gt) # для работ с таблицами
library(boot) # для проведения бутстрепа
library(here) # для удобной работы с файловыми пространствами, независимо от операционной системы
set.seed(456) # для воспроизводимости результатовТестовое для аналитика данных для Softwise (Adsterra)
Условие задачи
В файле test_task_data.csv – содержится выборка данных по первому дню проведения A/B – теста.
По информации от заказчика теста мы оцениваем, что происходит с системой при более быстрой работе модулей показа рекламы. Гипотеза: при использовании нового промежуточного хостинга (группа B) вырастет количество засчитанных нами показов.
Требуется:
Визуализировать данные из файлика для заказчика теста, который не работает в отделе аналитики
Сделать выводы о наблюдаемых явлениях – выводы кончено, предварительные ведь всего 1 день прошёл
Проверить все ли в порядке с запуском теста, можно ли его продолжать.
Настройка окружения
Загрузка и описание данных
dt <- fread(here('data/test_task_data.csv'))
head(dt) |> gt()| test_group | price | pl_category | OS | br | geo | id_placement | id_landing | gross | imp | conv |
|---|---|---|---|---|---|---|---|---|---|---|
| B | CPA | Other | iOS | Chrome | US | 15938057 | 2771498 | 0.0000000 | 1 | 0 |
| B | Other | Adult | iOS | Google Search App for iOS | FR | 16120841 | 0 | 0.0000000 | 0 | 0 |
| B | CPA | Movies | Android | Chrome Mobile | US | 16220050 | 2747354 | 0.0000000 | 1 | 0 |
| A | RTB | Downloads | Windows | Chrome | ZA | 15287331 | 2436322 | 0.0010632 | 1 | 0 |
| B | RTB | Anime | Mac OS X | Chrome | US | 16192721 | 2180232 | 0.0049610 | 4 | 0 |
| B | CPM | Adult | Mac OS X | Safari | US | 14932547 | 2322908 | 0.0051000 | 3 | 0 |
test_group указывает, к какой группе принадлежит реклама. В данном случае это может быть группа A или группа B;
price указывает тип модели ценообразования, используемой для рекламы;
pl_category указывает категорию продукта или услуги, к которой относится реклама;
OS означает операционную систему устройства, на котором отображается реклама;
br указывает браузер или приложение, через которое пользователь взаимодействует с рекламой;
geo указывает географическое местоположение пользователя, который видит рекламу;
id_placement уникальный идентификатор размещения рекламы;
id_landing уникальный идентификатор целевой страницы, на которую пользователь попадает после нажатия на рекламу;
gross указывает выручку, связанную с рекламной кампанией;
imp указывает количество показов рекламы;
conv указывает количество конверсий, которые произошли в результате показов рекламы.
Изучение данных
Параллельно с базовым анализом данных мы будем изучать качество разбиения выборки на группы A и B. Наведите на столбцы для просмотра точных значений.
dt |>
group_by(test_group, OS) |>
summarise(n = n(), .groups = 'drop_last') |>
arrange(desc(n)) |>
e_chart(OS) |>
e_bar(n) |>
e_title('Число объявлений по ОС для тестовых групп A и B') |>
e_legend(right = 80, top = '16%') |>
e_tooltip(trigger = 'axis')dt |>
group_by(test_group, br) |>
summarise(n = n(), .groups = 'drop_last') |>
arrange(desc(n)) |>
e_chart(br) |>
e_bar(n) |>
e_title('Число объявлений по браузерам для тестовых групп A и B') |>
e_flip_coords() |>
e_legend(right = 87, top = '16%') |>
e_tooltip(trigger = 'axis') |>
e_grid(left = 180)dt |>
group_by(test_group, pl_category) |>
summarise(n = n(), .groups = 'drop_last') |>
arrange(desc(n)) |>
e_chart(pl_category) |>
e_bar(n) |>
e_title('Число объявлений по категориям продукта для тестовых групп A и B') |>
e_flip_coords() |>
e_legend(right = 87, top = '16%') |>
e_tooltip(trigger = 'axis') |>
e_grid(left = 150)dt |>
group_by(test_group, geo) |>
summarise(n = n(), .groups = 'drop_last') |>
arrange(desc(n)) |>
e_chart(geo) |>
e_bar(n) |>
e_title('Число объявлений по регионам для тестовых групп A и B') |>
e_legend(right = 87, top = '16%') |>
e_tooltip(trigger = 'axis')Анализируя графики, мы можем утверждать, что данные разбиты на группы A и B случайным образом, общее соотношение следующее:
dt |> count(test_group) |> gt()| test_group | n |
|---|---|
| A | 133966 |
| B | 134156 |
Далее я буду проводить анализ A/B теста, однако данные доступны только за один день, и у нас нет возможности провести A/A тест для проверки равенства выборок. Тем не менее, сосредоточимся на имеющихся данных.
Предварительный анализ
На этапе предварительного анализа я планирую использовать несколько статистических тестов для оценки данных. В первую очередь, необходимо проверить нормальность распределения и равенство дисперсий в выборках. Для этого я применю следующие тесты:
Тест на равенство дисперсий, который позволит оценить, равны ли дисперсии между группами A и B.
Тест Шапиро-Уилка, который помогут определить, имеют ли выборки A и B нормальное распределение.
Эти тесты помогут мне сделать обоснованные выводы о применимости дальнейших статистических методов к данным.
Тест на равенство дисперсий
res <- var.test(imp ~ test_group, data = dt)
print(res)
F test to compare two variances
data: imp by test_group
F = 0.88928, num df = 133965, denom df = 134155, p-value < 2.2e-16
alternative hypothesis: true ratio of variances is not equal to 1
95 percent confidence interval:
0.8798145 0.8988564
sample estimates:
ratio of variances
0.8892845
Тест на равенство дисперсий показывает p-value 2.6843762^{-102}, Это очень маленькое значение p, что указывает на то, что мы можем отвергнуть нулевую гипотезу о равенстве дисперсий. В контексте теста это означает, что существует статистически значимая разница между дисперсиями двух групп.
Тест Шапиро-Уилка
Тест Шапиро-Уилка проводился на 5000 случайных записей из каждой группы, так как это является лимитом для данной функции.
shapiro.test(sample(dt[test_group == 'A', imp], 5000))
Shapiro-Wilk normality test
data: sample(dt[test_group == "A", imp], 5000)
W = 0.038648, p-value < 2.2e-16
shapiro.test(sample(dt[test_group == 'B', imp], 5000))
Shapiro-Wilk normality test
data: sample(dt[test_group == "B", imp], 5000)
W = 0.11413, p-value < 2.2e-16
Тесты Шапиро-Уилка показывают, что выборки из групп A и B не имеют нормального распределения, так как значения p-value очень малы.
dt |>
e_chart() |>
e_density(imp) |>
e_legend(show = FALSE) |>
e_title('Плотность распределения показов объявлений')На графике видно, что распределение количества показов объявлений сильно сколено влево и существенно отличается от нормального распределения.
Это означает, что для дальнейшего анализа данных, могут потребоваться непараметрические методы или методы, которые не предполагают нормальности распределения и равенства дисперии, поскольку стандартные методы (т. тест) могут быть неуместны.
На следующем этапе мы попытаемся оценить значимость данных с помощью теста Манна-Уитни и бутстрап-анализа.
Тест Манна-Уитни
res <- wilcox.test(imp ~ test_group, data = dt)
print(res)
Wilcoxon rank sum test with continuity correction
data: imp by test_group
W = 8945094230, p-value = 0.0297
alternative hypothesis: true location shift is not equal to 0
Результаты теста Манна-Уитни показали, что p-value составляет 0.0297. Поскольку это значение меньше стандартного уровня значимости 0.05, мы можем отвергнуть нулевую гипотезу о том, что истинное смещение местоположения между группами равно 0. Это свидетельствует о наличии статистически значимой разницы между количеством засчитанных показов для групп A и B.
В качестве альтернативного теста используем непараметрический бутстреп.
Непараметрический бутстреп
Проведем бутстреп на 1000 выборках. В качестве идеи будет сравнивать разницу средних по группам.
# Функция для вычисления разницы средних
mean_diff <- function(data, indices) {
d <- data[indices, ]
mean_diff <- mean(d[test_group == "B", imp]) - mean(d[test_group == "A", imp])
return(mean_diff)
}
# Применение бутстрепа
boot_results <- boot(dt, mean_diff, R = 1000, parallel = "multicore")
print(boot_results)
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = dt, statistic = mean_diff, R = 1000, parallel = "multicore")
Bootstrap Statistics :
original bias std. error
t1* 0.1630491 -0.005144951 0.09252147
# Доверительный интервал
boot_ci <- boot.ci(boot_results, type = "perc")
print(boot_ci)BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 1000 bootstrap replicates
CALL :
boot.ci(boot.out = boot_results, type = "perc")
Intervals :
Level Percentile
95% (-0.0135, 0.3496 )
Calculations and Intervals on Original Scale
В результате анализа можно сказать, что средняя разница между группами A и B составляет примерно 0.16, но доверительный интервал показывает, что эта разница может быть незначительной, так как включает 0. Это говорит о том, что различия между группами могут быть случайными и не обязательно указывают на реальное влияние.
Обобщение выводов из двух статистических тестов
В ходе анализа данных были проведены два теста: тест Манна-Уитни и непараметрический бутстреп. Результаты теста Манна-Уитни показали p-value равное 0.0297, что указывает на статистически значимую разницу между группами A и B. Это значение меньше стандартного уровня значимости 0.05, что позволяет отвергнуть нулевую гипотезу о равенстве медиан.
Однако результаты непараметрического бутстрепа предоставили доверительный интервал, который включает 0, с диапазоном (-0.013, 0.35). Это говорит о том, что истинная разница средних значений между группами может быть незначительной, и мы не можем с уверенностью утверждать, что наблюдаемая разница является статистически значимой.
Следует также отметить, что данные были собраны только за один день, что ограничивает надежность полученных результатов. Таким образом, выводы являются предварительными, и для более точного анализа и уверенности в выводах необходимо собрать данные за более продолжительный период времени. Это позволит учесть возможные колебания и тренды, которые могут влиять на результаты, и даст возможность более обоснованно оценить различия между группами.
Заключение
В ходе нашего анализа мы пришли к нескольким важным выводам:
Разбиение на группы было сделано случайным образом, что видно на графиках. Это хороший знак, так как помогает нам быть уверенными в том, что результаты не искажены.
К сожалению, у нас нет данных для A/A теста, который мог бы помочь проверить, равны ли выборки. Это создает некоторые трудности, так как мы не можем полностью оценить однородность групп.
Предварительный анализ показал, что данные не распределены нормально, и дисперсии в группах различаются. На графиках видно, что распределение сильно скошено, поэтому классический t-тест не подходит. Вместо этого мы использовали тест Манна-Уитни и непараметрический бутстреп. Тест Манна-Уитни показал, что между группами есть значимая разница, но результаты бутстрепа не подтвердили это, так как доверительный интервал включает 0.
С учетом всего этого, я предлагаю продолжить тестирование, собрав больше данных и проведя более глубокий анализ. Это поможет нам получить более точные и надежные выводы.