Новый чекаут: есть ли эффект?
// Условие
Команда две недели тестировала новый чекаут: контроль A — старый (3 шага), тест B — новый (1 шаг). Метрика — конверсия в оплату.
result — dict с ключами conv_a, conv_b, p_value.// Данные
user_id, group (A/B), converted (0/1) — одна строка на юзера// Решение
Подсказка
Конверсия группы — это среднее по колонке converted: df.groupby('group')['converted'].mean().
Для теста двух долей подойдёт z-тест: посчитай общую долю p_pool, стандартную ошибку разницы и статистику z = (conv_b - conv_a) / se. p-value = 2 * (1 - stats.norm.cdf(abs(z))). Хи-квадрат по таблице 2×2 тоже принимается.
Стандартная ошибка (pooled): se = (p_pool*(1-p_pool)*(1/n_a + 1/n_b))**0.5.
Сначала попробуй сам → Показать решение
df = load_data()
from scipy import stats
s = df.groupby('group')['converted'].agg(['sum', 'count'])
conv_a = s.loc['A', 'sum'] / s.loc['A', 'count']
conv_b = s.loc['B', 'sum'] / s.loc['B', 'count']
# z-тест двух долей (pooled SE)
p_pool = df['converted'].mean()
se = (p_pool * (1 - p_pool) * (1 / s.loc['A', 'count'] + 1 / s.loc['B', 'count'])) ** 0.5
z = (conv_b - conv_a) / se
p_value = 2 * (1 - stats.norm.cdf(abs(z)))
result = {'conv_a': conv_a, 'conv_b': conv_b, 'p_value': p_value}
print(result)
stats.chi2_contingency по таблице 2×2 без поправки Йейтса: на таких выборках даёт то же p-value.Что скажешь продакту?
p-value порядка 10⁻⁶ — вероятность увидеть такую разницу случайно ничтожна, и +1.4 п.п. на чекауте — большие деньги. Небольшая разница размеров групп — норма: рандомизация никогда не делит трафик идеально пополам, 24 850 vs 25 150 легко проходит SRM-проверку. «Продлить тест» после достижения нужной выборки — лишний риск peeking-практик.