Как правильно спланировать A/B тест?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как правильно спланировать A/B тест
Основные этапы планирования
Планирование A/B теста — это критический процесс, который определяет корректность выводов. Правильное планирование включает определение гипотезы, расчёт размера выборки, выбор метрик и периода теста.
1. Формулировка гипотезы
Нулевая гипотеза (H0): вариант A и вариант B не различаются Альтернативная гипотеза (H1): вариант B лучше/отличается от варианта A
Примеры гипотез:
- "Изменение цвета кнопки с синего на красный повысит CTR на 5%"
- "Новый алгоритм рекомендаций увеличит engagement на 10% или более"
2. Выбор метрики (Metric Selection)
Выбери одну первичную метрику и несколько вторичных:
# Пример метрик для e-commerce
Primary: conversion_rate = purchases / sessions
Secondary: avg_order_value, retention_rate, customer_satisfaction
Важно:
- Метрика должна быть измеримой и объективной
- Используй метрики с малой волатильностью для надёжности
- Избегай слишком сложных метрик на начальном этапе
- Убедись, что метрика отражает реальный бизнес-результат
3. Определение минимально значимого эффекта (MDE)
MDE (Minimum Detectable Effect) — минимальный прирост, который мы считаем практически важным.
# Пример: текущая конверсия 2%, MDE = 10% (относительный прирост)
# Ожидаемая конверсия в варианте B = 2% * 1.1 = 2.2%
current_conversion = 0.02
mde_relative = 0.10 # 10% увеличение
expected_conversion = current_conversion * (1 + mde_relative)
print(f"Expected: {expected_conversion:.4f}")
Выбор MDE:
- Слишком маленький MDE требует большой выборки и дорогой тест
- Слишком большой MDE может пропустить реальные эффекты
- Основывайся на бизнес-целях и текущих метриках
4. Расчёт размера выборки (Sample Size)
Используй формулу для расчёта требуемого размера выборки по группам:
import numpy as np
from scipy import stats
def calculate_sample_size(baseline_rate, mde, alpha=0.05, power=0.8):
"""
Расчёт размера выборки для бинарной метрики.
baseline_rate: текущий уровень конверсии (e.g., 0.02)
mde: относительный минимальный эффект (e.g., 0.10)
alpha: уровень значимости (type I error, обычно 0.05)
power: статистическая мощность (1 - beta, обычно 0.8)
"""
# Расчёт вероятностей
p1 = baseline_rate
p2 = baseline_rate * (1 + mde)
# Стандартные отклонения
s1 = np.sqrt(p1 * (1 - p1))
s2 = np.sqrt(p2 * (1 - p2))
pooled_std = np.sqrt((s1**2 + s2**2) / 2)
# Z-значения
z_alpha = stats.norm.ppf(1 - alpha / 2) # двусторонний тест
z_beta = stats.norm.ppf(power)
# Размер выборки на группу
n_per_group = (z_alpha + z_beta)**2 * (2 * pooled_std**2) / (p2 - p1)**2
return n_per_group
# Пример
baseline = 0.02 # 2% конверсия
mde = 0.10 # 10% относительный прирост
n = calculate_sample_size(baseline, mde)
print(f"Размер выборки на группу: {n:,.0f}")
print(f"Всего: {n * 2:,.0f} наблюдений")
print(f"При 10k трафика в день: {n * 2 / 10000:.1f} дней")
5. Выбор периода теста и интервала конфиденции
Минимальная продолжительность:
- Не менее 1 полного недельного цикла (чтобы учесть суточные колебания)
- Лучше 2-4 недели для стабильности
- Минимум 1000-5000 наблюдений на группу
Нельзя:
- Заканчивать тест раньше запланированного времени, если видно статистическую значимость (peeking problem)
- Изменять гипотезу после начала теста (HARKing — Hypothesizing After Results are Known)
6. Рандомизация и контроль
# Правильная рандомизация: по user_id
import hashlib
def get_variant(user_id, test_name, split=0.5):
"""
Детерминированная рандомизация: один пользователь всегда в одной группе.
"""
hash_value = int(hashlib.md5(f"{user_id}_{test_name}".encode()).hexdigest(), 16)
return "A" if hash_value % 100 < split * 100 else "B"
# Проверка баланса
test_users = range(10000)
variants = [get_variant(user_id, "button_color") for user_id in test_users]
print(f"A: {variants.count(A)}, B: {variants.count(B)}")
7. Статистический анализ результатов
from scipy.stats import chi2_contingency
def analyze_ab_test(conversions_a, total_a, conversions_b, total_b, alpha=0.05):
"""
Chi-square тест для сравнения двух пропорций.
"""
contingency_table = [
[conversions_a, total_a - conversions_a],
[conversions_b, total_b - conversions_b]
]
chi2, p_value, dof, expected = chi2_contingency(contingency_table)
rate_a = conversions_a / total_a
rate_b = conversions_b / total_b
lift = (rate_b - rate_a) / rate_a * 100
is_significant = p_value < alpha
print(f"Конверсия A: {rate_a:.4f} ({conversions_a}/{total_a})")
print(f"Конверсия B: {rate_b:.4f} ({conversions_b}/{total_b})")
print(f"Lift: {lift:.2f}%")
print(f"P-value: {p_value:.4f}")
print(f"Статистически значимо (alpha={alpha}): {is_significant}")
return is_significant, lift, p_value
# Пример
analyze_ab_test(conversions_a=200, total_a=10000,
conversions_b=240, total_b=10000)
8. Контроль побочных эффектов
- Multy-testing correction: если проверяешь много гипотез, используй Bonferroni коррекцию
- Симпсон парадокс: проверяй результаты по сегментам
- Утечка эффекта: если пользователи видят оба варианта, это нарушает тест
- Сезонность: учитывай дни недели, праздники, маркетинг-события
Чеклист планирования A/B теста:
- Сформулирована чёткая гипотеза
- Выбрана первичная метрика
- Определён MDE
- Рассчитан размер выборки
- Спланирован период теста (минимум 2 недели)
- Описана процедура рандомизации
- Определены критерии остановки
- Проверена мощность теста
- Согласован план анализа заранее
- Задокументировано, кто принимает решение по результатам
Правильное планирование гарантирует, что результаты теста будут надёжными и позволят принять правильное бизнес-решение.