Условие
В A/B-тесте сравниваем среднюю длительность сессии в контроле и тесте. Распределение очень скошенное (длинный правый хвост, медиана 90 сек, среднее 250 сек, есть сессии по 30 минут). Какой тест выбрать?
- Welch's t-test (двух выборок с разной σ²).
- Mann–Whitney U.
- Bootstrap.
- Permutation test.
Сравните, какие предположения каждый делает. Что бы вы реально применили в продакшене?
Решение
Сравнение
| Тест | Что сравнивает | Предположения | Чувствителен к выбросам |
|---|---|---|---|
| Welch's t | средние | независимые наблюдения, конечные σ²; нормальность желательна (или большие N через CLT) | сильно |
| Mann–Whitney U | стохастический порядок (P(X>Y) > 0.5) | независимость, непрерывность, одинаковая форма распределения (для интерпретации как медианы) | слабее |
| Bootstrap on mean | любой статистикой | независимость; распределение «достаточно богатое» | соответствует статистике |
| Permutation | любой статистикой | exchangeability под H₀ | гибкий |
Что выбрать
Welch t-test: при больших N (>10К на ветку) CLT срабатывает даже на скошенных данных. p-value обычно близок к корректному. Сравнивает средние, что соответствует выручке / экономике.
Mann–Whitney: сравнивает ранги, не средние. Менее чувствителен к выбросам, но интерпретация «B стохастически больше A», а не «среднее в B больше». На очень скошенных данных может сместить результат, если distributions меняют форму, а не только сдвиг.
Bootstrap: повторяем sampling с возвращением из обоих ветвей, считаем разность средних (или медиан). Лучший выбор, когда σ² нестабильна или есть очень тяжёлые хвосты.
Permutation: точно соответствует H₀ exchangeability. Дорого: 10К пермутаций × 2М наблюдений.
Код
import numpy as np
from scipy.stats import ttest_ind, mannwhitneyu
# Welch's t
t, p_t = ttest_ind(a, b, equal_var=False)
# Mann–Whitney
u, p_u = mannwhitneyu(a, b, alternative='two-sided')
# Bootstrap CI на разность средних
rng = np.random.default_rng(0)
def boot_diff(a, b, n_iter=10000):
diffs = np.empty(n_iter)
for i in range(n_iter):
sa = rng.choice(a, len(a), replace=True)
sb = rng.choice(b, len(b), replace=True)
diffs[i] = sb.mean() - sa.mean()
ci = np.percentile(diffs, [2.5, 97.5])
return diffs.mean(), ciТактический совет для проды
-
Выбор статистики по продукту: для выручки / времени сессии бизнес интересуется средним (т.к. оно агрегируется в total). Mann–Whitney не отвечает на этот вопрос.
-
Тяжёлые хвосты → стабилизация дисперсии:
- Log-преобразование (
log(1 + x)) — часто превращает в почти нормальное; t-test на логарифмах ок, но интерпретация: «среднее лог дохода», не средний доход. - Winsorize на 99% / 99.9% — обрезать выбросы; t-test становится стабильным.
- CUPED-стратификация — снижает дисперсию через ковариату (например, активность в предпериоде).
- Log-преобразование (
-
Большие N (>50К): CLT + Welch почти всегда корректен, но дисперсия оценки может быть огромной — отсюда нужны CUPED или bootstrap CI.
CUPED как стандарт в индустрии
Y' = Y - θ · (X - E[X]) где X — pre-period covariate
θ = Cov(Y, X) / Var(X)
Снижает Var(Y') в 30-70% — эффективно как «бесплатное» увеличение n.
Подводные камни
- Mann–Whitney = «тест медианы» — только если формы distributions одинаковы. Иначе он тестирует общее «stochastic dominance».
- t-test на 100 наблюдениях с экстремальным skew — p-value сильно смещён; bootstrap безопаснее.
equal_var=Trueвttest_ind(Student t) предполагает одинаковую дисперсию; Welch's =equal_var=False. На A/B всегда Welch.- Permutation не помогает с heavy tails: тоже сравнивает средние, которые нестабильны.
- Multiple metrics: если считаете 10 метрик, делите α / 10 (Bonferroni) или FDR.
- Outlier removal post-hoc — leakage: убираете «странные» строки на основании результата → искажение p-value.
- Двусторонний vs односторонний: бизнес обычно хочет «лучше или хуже» → двусторонний.
Эталонный ответ
В продакшене на тяжёлых хвостах:
- Welch's t-test с CUPED — стандарт индустрии для больших N.
- Bootstrap CI на разность средних — sanity-check.
- Mann–Whitney — sanity, но не основная метрика (не отвечает на «средний выше или ниже»).
- Winsorize / log-преобразование для стабилизации дисперсии — если нет CUPED.
t-test сравнивает средние (то, что нужно бизнесу для выручки/времени), Mann–Whitney — стохастический порядок. На скошенных малых выборках — bootstrap.