Зачем считать sample size заранее

Если решишь "запущу A/B на 1000 юзеров, посмотрим" — велик шанс закончить с p>0.05 и не понять было ли в принципе достаточно данных.

4 параметра

  1. Baseline conversion — текущая конверсия (e.g. 5%)
  2. MDE (Minimum Detectable Effect) — какую разницу хочешь поймать (e.g. +0.5%)
  3. alpha — приемлемая частота false positives (обычно 0.05)
  4. power (1 - beta) — вероятность поймать эффект если он есть (обычно 0.8)

Формула

n = 16 × p(1-p) / MDE²

Для baseline=5%, MDE=0.5%:

n = 16 × 0.05 × 0.95 / 0.005² = 30 400

То есть нужно 60К юзеров. Если в день приходит 1К → A/B на 60 дней.

Python

from statsmodels.stats.power import zt_ind_solve_power
from math import sqrt

effect = 0.005 / sqrt(0.05 * 0.95)
n_per_group = zt_ind_solve_power(
    effect_size=effect,
    alpha=0.05,
    power=0.8,
    alternative='larger'
)

Trade-off

  • Хочешь меньше юзеров → принимай больший MDE
  • Хочешь точнее → больше юзеров, дольше тест
  • Хочешь меньше FP → ниже alpha → больше юзеров

Подвох на собесе

"У нас в день 100 юзеров. Запустим A/B на месяц, получим 3000. Норм?"

❌ Без расчёта MDE — нет. С 3К юзеров можно поймать только большие эффекты (10%+).

Кейс из Halyk

Команда запустила A/B на новой кнопке. Через 2 недели разница 0.2% при baseline 4%. p=0.15. "Не сработало".

Реально: им нужно было 80К юзеров для MDE=0.2%, у них было 15К. Эффект мог быть, но они его не увидели → false negative. Откатили рабочую фичу.