Зачем считать sample size заранее
Если решишь "запущу A/B на 1000 юзеров, посмотрим" — велик шанс закончить с p>0.05 и не понять было ли в принципе достаточно данных.
4 параметра
- Baseline conversion — текущая конверсия (e.g. 5%)
- MDE (Minimum Detectable Effect) — какую разницу хочешь поймать (e.g. +0.5%)
- alpha — приемлемая частота false positives (обычно 0.05)
- 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. Откатили рабочую фичу.