A/B-тестыОсновыMediumБесплатно~12 мин

Ранний восторг: хватает ли выборки?

// Условие

Тест нового онбординга идёт три дня, собрано по 700 юзеров на группу. В дашборде конверсия 8.0% против 10.0% — команда в восторге: «+2 пункта, останавливаем и катим!»

Что нужно
Посчитай p-value наблюдаемой разницы и оцени, сколько юзеров на группу нужно, чтобы надёжно ловить эффект +2 п.п. от базы 8% (α=0.05, мощность 80%). Сохрани в result — dict с ключами p_value, n_needed.

// Данные

df: user_id, group (A/B), converted (0/1) — одна строка на юзера
▶ Решить в A/B-тренажёре

// Решение

Подсказка

p-value — обычный z-тест двух долей на текущих данных.

Выборка на группу: n = (z_alpha + z_beta)**2 * (p1*(1-p1) + p2*(1-p2)) / mde**2, где z_alpha = 1.96 (α=0.05, двусторонний), z_beta = 0.84 (мощность 80%), p1 = 0.08, p2 = 0.10, mde = 0.02.

Сравни n_needed с фактическими 700 на группу — вот и ответ, почему «+2 пункта» пока ничего не значат.

Сначала попробуй сам → Показать решение
df = load_data()
from scipy import stats

s = df.groupby('group')['converted'].agg(['sum', 'count'])
pa = s.loc['A', 'sum'] / s.loc['A', 'count']
pb = s.loc['B', 'sum'] / s.loc['B', 'count']

p_pool = df['converted'].mean()
se = (p_pool * (1 - p_pool) * (1 / s.loc['A', 'count'] + 1 / s.loc['B', 'count'])) ** 0.5
z = (pb - pa) / se
p_value = 2 * (1 - stats.norm.cdf(abs(z)))

# Требуемая выборка на группу: α=0.05 (z=1.96), мощность 80% (z=0.84)
p1, p2, mde = 0.08, 0.10, 0.02
n_needed = (1.96 + 0.84) ** 2 * (p1 * (1 - p1) + p2 * (1 - p2)) / mde ** 2

result = {'p_value': p_value, 'n_needed': n_needed}
print(result)
Наблюдаемые +2 п.п. при 700 юзерах дают p ≈ 0.19 — такое запросто рисует шум. Чтобы надёжно ловить +2 п.п. от базы 8%, нужно ≈3200 юзеров на группу — в 4.5 раза больше собранного. Правило: выборку считают до запуска, а не смотрят «когда красиво».

Команда ждёт отмашку. Твой ответ?

  • Эффекта нет — новый онбординг не работает, выключаем
  • ✓ Разница в пределах шума (p ≈ 0.19), а выборки собрано в ~4.5 раза меньше нужной — продолжаем тест до ~3200 юзеров на группу, решение потом
  • +2 п.п. видно невооружённым глазом — раскатываем, статистика для перестраховщиков
  • Добавим ещё 100 юзеров и пересчитаем — этого хватит

Сейчас невозможно отличить реальный эффект от шума: p ≈ 0.19, а мощности при 700 юзерах хватает лишь на огромные эффекты. Говорить «эффекта нет» так же неверно, как «эффект есть» — данных просто недостаточно. Расчёт выборки (≈3200 на группу) должен был случиться до запуска; сейчас честный ход — продолжить тест до плановой выборки и не подглядывать в p-value каждый день.

// Похожие задачи

// Разобраться в теме

→ p-value простыми словами