Время прочтения: 8 мин.

А/В-тестирование – это метод, который используется для сравнения двух версий переменной, например, дизайна сайта при маркетинговом исследовании с целью выявления лучшей версии. Это критически важный метод исследования в Data Science, который часто используется различными организациями при принятии решений с целью оптимизации существующего продукта и максимизации прибыли.

Представлю, что компания, продающая мебель, хочет увеличить число кликов по баннеру «Мебель на заказ». Они значительно изменили дизайн сайта для этой цели. К сожалению, не существует способов предсказать, как именно изменится поведение людей на обновленном сайте по сравнению со старой версией. А/В-тестирование может помочь, например, измерить разницу в конверсии между двумя версиями сайта и сказать, является ли эта разница статистически значимой.

Основные понятия

Прежде чем перейти к проведению А/В-тестирования, введу следующие понятия:

  • Нулевая и альтернативная гипотезы
  • Уровень значимости (α)
  • P-value
  • Доверительный интервал
  • Статистическая мощность

Нулевая гипотеза в рамках А/В-тестирования – предположение о том, что разницы между версиями сайта А и В в действительности нет, а все наблюдаемые различия обусловлены случайностью. Моя задача в ходе А/В-тестирования – опровергнуть нулевую гипотезу. Альтернативная гипотеза в рамках А/В-тестирования утверждает, что версии сайта А и В различны с точки зрения поведения пользователей.

Уровень значимости – это порог вероятности для определения того, являются ли результаты эксперимента статистически значимыми. Чаще всего уровень значимости устанавливается равным 0,05. Это значит, что моё утверждение о значимости результата будет справедливо на 95%. Чем ниже выбранный уровень значимости, тем ниже риск того, что будет обнаружена разница, вызванная случайностью.

Pvalue – это вероятность наблюдения данного результата при условии, что нулевая гипотеза верна. Если p-value меньше, чем уровень значимости (α), то отвергается нулевая гипотеза в пользу альтернативной (то есть результаты являются статистически значимыми). Например, при уровне значимости 0,05 p-value должна быть меньше 0,05 для признания результатов эксперимента статистически значимыми.

Доверительный интервал – интервал значений, в котором, с вероятностью (1- α), лежит истинное значение переменной. Доверительный интервал является оценкой возможных значений переменной в зависимости от её стандартного отклонения.

Статистическая мощность – вероятность отклонения нулевой гипотезы в случае, если альтернативная гипотеза верна. Обычно статистическая мощность теста устанавливается равной 0,8. Это значение используется для вычисления размера выборки, необходимой для подтверждения гипотезы с необходимой силой эффекта.

Организация эксперимента

Для проведения А/В-теста требуется разделить всех пользователей на две группы: одна группа будет видеть старый дизайн сайта, а другая – новый. Пользователи распределяются между группами случайным образом. Как правило, группу, которой показывают новый дизайн сайта (В), называют тестовой, а группу, которой показывают старый дизайн (А) – контрольной.

Целевая метрика – CTR, то есть количество кликов на баннер, делённое на количество показов. Буду сравнивать среднее значение метрики CTR для контрольной и тестовой групп. Предположу, что в контрольной группе среднее значение метрики составляет 12%, а в тестовой – 14%.

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

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

В описании датасета нет информации о том, как именно были собраны данные, но можно предположить, как это было сделано. Перед началом сбора данных рассчитывается размер контрольной и тестовой групп, а также продолжительность эксперимента. Вероятнее всего, размер выборки, необходимой для проведения эксперимента, был рассчитан с помощью калькулятора. Пример такого калькулятора находится здесь. Калькулятор подсчитывает необходимое количество просмотров для каждой версии сайта. В моём случае количество просмотров каждой версии составило 147 239. Для планирования эксперимента это число необходимо поделить на количество пользователей, которое ежедневно будет видеть каждую версию сайта. Предположу, что ежедневный трафик в данном случае составил 10 000 пользователей, это означает, что только 5 000 пользователей могли увидеть каждую версию сайта. Таким образом, количество дней, в течение которых проводился эксперимент, составило 147 239/5 000 ≈ 29 дней.

Реализация на Python

Рассмотрю, как проанализировать результаты А/В-тестирования с помощью Python.

Импортирую библиотеки:

import numpy as np
import pandas as pd
import scipy.stats as stats
import statsmodels.stats.api as sms
import seaborn as sns
from math import ceil
from statsmodels.stats.proportion import proportions_ztest, proportion_confint

Для начала рассчитаю минимальный размер выборки, который нужно взять для наблюдения желаемого эффекта.  Допустим, я хочу достигнуть разницы в конверсии 2% за счёт введения нового дизайна сайта. Тогда с учётом изначальной конверсии 12%, статистической мощности 0,8 и уровня значимости 0,05 имею:

effect_size = sms.proportion_effectsize(0.12, 0.14)
required_n = sms.NormalIndPower().solve_power(effect_size, power=0.8, alpha=0.05, ratio=1)
required_n = ceil(required_n)
print(required_n)

Вывод:

Итак, для каждой группы (А или В) необходимо выбрать минимум 4 433 наблюдений.

Импортирую датасет:

df = pd.read_csv('ab_data.csv')
df.head()

Вывод:

Датасет содержит ID пользователей, время посещения, принадлежность к тестовой или контрольной группе, дизайн сайта, который видит пользователь, а также информацию о том, был ли клик на баннер для данного пользователя (1 – клик был, 0 – не был). ID пользователей не уникальны, т.к. некоторые пользователи заходили на сайт несколько раз.  Эти пользователи будут искажать результат эксперимента, согласно правилам проведения А/В-тестирования их нужно убрать.

# Пользователи, которые заходили на сайт несколько раз
session_counts = df['user_id'].value_counts(ascending=False)
multi_users = session_counts[session_counts > 1].count()
# Удаление пользователей с несколькими сессиями
users_to_drop = session_counts[session_counts > 1].index
df = df[~df['user_id'].isin(users_to_drop)]

Я должна случайным образом определить 4 433 пользователей, которые видели версию сайта А, и 4 433 пользователей, которые видели версию сайта В.

#  Определение выборок для контрольной и тестовой группы
control_sample = df[df['group'] == 'control'].sample(n=4433, random_state=43)
treatment_sample = df[df['group'] == 'treatment'].sample(n=4433, random_state=43)
ab_test = pd.concat([control_sample, treatment_sample], axis=0)
ab_test.reset_index(drop=True, inplace = True)

Далее, определю функции для стандартного отклонения (std_dev) и стандартной ошибки (std_error) на основе ранее импортированных библиотек.

def std_dev(x):
    return np.std(x, ddof=0)
def std_error(x):
    return stats.sem(x, ddof=0)

Посчитаю значение функций для контрольной и тестовой группы.

conversion_rate = ab_test.groupby('group')['converted'].agg([np.mean, std_dev, std_error])
conversion_rate.columns =['conversion_rate','std_deviation','std_error']
conversion_rate

Вывод:

Значения метрик conversion_rate, std_deviation и std_error в контрольной и тестовой группе посчитаны для наглядности. Например, видно, что conversion_rate в тестовой группе несколько выше, чем в контрольной, с примерно одинаковой ошибкой. Однако, как будет показано в дальнейшем, этот результат не является статистически значимым.

Рассчитаю количество «успехов» (т.е. конвертаций показа в клик) для контрольной и тестовой групп, а также общее количество показов.

# Количество показов для контрольной группы
control_results = ab_test[ab_test['group']=='control']['converted']
num_control = control_results.count()
# Количество показов для тестовой группы
treatment_results = ab_test[ab_test['group']=='treatment']['converted']
num_treatment = treatment_results.count()
# «Успехи»
successes = [control_results.sum(), treatment_results.sum()]
# Показы
nobs = [num_control, num_treatment]

Рассчитаю значение p-value, z-статистику и доверительный интервал с помощью статистических функций из модуля statsmodels.stats.proportion.

z_stat, pval = proportions_ztest(successes, nobs = nobs)
(lower_con, lower_treat), (upper_con, upper_treat) = proportion_confint(successes, nobs=nobs)

Вывод:

Как видно, p-value равно 0,538, что больше, чем 0,05 (уровень значимости). Таким образом, нельзя отвергнуть нулевую гипотезу. Это значит, что нет статистически значимого различия между версиями сайта А и В. Наблюдаемая разница в метрике CTR – результат действия случайных факторов.

Кроме того, я посчитала доверительный интервал для контрольной и тестовой групп, куда с 95-процентной вероятностью входит истинное значение конверсии для этих групп.

Если проделать аналогичные расчеты на всем объеме наблюдений (143 345 образцов в каждой группе А и В после удаления дублей), то получу аналогичный результат: p_value равно 0,232, что больше 0,05. Таким образом, нельзя отвергнуть нулевую гипотезу.

Это дополнительно доказывает, что для моих расчетов я имела право взять минимально допустимый объем выборки, равный, как показано выше, 4 433 образцам.

Подведение итогов

В моём случае А/В-тест показал отрицательный результат. Количество конвертаций показов в клик не зависит от версии сайта А или В, которую видит пользователь. Таким образом, можно сделать вывод, что дизайн сайта не влияет на конверсию. Или же, возможно, дизайн сайта имеет влияние, но версии А и В должны отличаться более радикальным образом. Например, нужно не просто изменить цвет обложки сайта, но и кардинально поменять дизайн кнопок и их размещение на подложке. Дальнейшая доработка дизайна сайта и последующие за этим новые А/В-тесты должны производиться при совместном участии продуктового аналитика и UX-дизайнера.