Тестовое для аналитика данных для Softwise (Adsterra)

Автор

Михаил Лагунов

Условие задачи

В файле test_task_data.csv – содержится выборка данных по первому дню проведения A/B – теста.

По информации от заказчика теста мы оцениваем, что происходит с системой при более быстрой работе модулей показа рекламы. Гипотеза: при использовании нового промежуточного хостинга (группа B) вырастет количество засчитанных нами показов.

Требуется:

  1. Визуализировать данные из файлика для заказчика теста, который не работает в отделе аналитики

  2. Сделать выводы о наблюдаемых явлениях – выводы кончено, предварительные ведь всего 1 день прошёл

  3. Проверить все ли в порядке с запуском теста, можно ли его продолжать.

Настройка окружения

library(data.table) # работа с табличными данными
library(dplyr) # для дополнительных функций обработки данных
library(echarts4r) # для построения красивых графиков
library(gt) # для работ с таблицами
library(boot) # для проведения бутстрепа
library(here) # для удобной работы с файловыми пространствами, независимо от операционной системы

set.seed(456) # для воспроизводимости результатов

Загрузка и описание данных

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). Это говорит о том, что истинная разница средних значений между группами может быть незначительной, и мы не можем с уверенностью утверждать, что наблюдаемая разница является статистически значимой.

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

Заключение

В ходе нашего анализа мы пришли к нескольким важным выводам:

  1. Разбиение на группы было сделано случайным образом, что видно на графиках. Это хороший знак, так как помогает нам быть уверенными в том, что результаты не искажены.

  2. К сожалению, у нас нет данных для A/A теста, который мог бы помочь проверить, равны ли выборки. Это создает некоторые трудности, так как мы не можем полностью оценить однородность групп.

  3. Предварительный анализ показал, что данные не распределены нормально, и дисперсии в группах различаются. На графиках видно, что распределение сильно скошено, поэтому классический t-тест не подходит. Вместо этого мы использовали тест Манна-Уитни и непараметрический бутстреп. Тест Манна-Уитни показал, что между группами есть значимая разница, но результаты бутстрепа не подтвердили это, так как доверительный интервал включает 0.

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