ab-тестыстатистикаmdeдельта-методаналитика

MDE в A/B-тесте: формула и размер выборки

2026-07-20 8 мин

MDE (Minimum Detectable Effect, минимальный детектируемый эффект) — это наименьшее изменение метрики, которое A/B-тест способен статистически надёжно отличить от нуля при заданных уровне значимости α и мощности 1−β. Если реальный эффект меньше MDE, тест с высокой вероятностью его «не заметит» (получите незначимый результат, даже если различие есть). MDE задаётся ДО запуска теста и жёстко связан с размером выборки: чем меньший эффект вы хотите ловить, тем больше нужно наблюдений — зависимость квадратичная.

Базовая формула размера выборки на одну группу для сравнения средних:

n ≈ (z_{1−α/2} + z_{1−β})² · 2σ² / Δ²

где Δ — это MDE (абсолютный), σ² — дисперсия метрики, z — квантили стандартного нормального распределения. При стандартных α = 0.05 (двусторонний) и мощности 80% множитель (1.96 + 0.84)² ≈ 7.85 ≈ 8, поэтому на две группы часто пишут удобное правило n ≈ 16·σ²/Δ². Ниже разберём каждую часть, посчитаем сходящийся пример и покажем дельта-метод для метрик-отношений (CTR, конверсия на сессию, ARPPU).

Что такое MDE простыми словами?

Представьте, что кнопка «Купить» даёт конверсию 10%. Вы меняете её цвет и надеетесь на прирост. Вопрос не «есть ли эффект вообще», а «какой минимальный прирост мы вообще сможем задетектировать на нашем трафике». Если за две недели набирается 8000 пользователей на группу, тест уловит прирост примерно от +1.3 п.п. (с 10% до 11.3%). Прирост в +0.3 п.п. останется в шуме — тест покажет «не значимо», и вы ошибочно решите, что идея не работает.

MDE бывает двух видов, и их постоянно путают:

ВидОбозначениеПример при base = 10%
АбсолютныйΔ (п.п.)+2 п.п. → 12%
ОтносительныйΔ/p (%)+20% → 12%

+2 п.п. на базе 10% — это те же +20% относительно. В интерфейсах калькуляторов (например в статистике A/B-дизайна) чаще вводят относительный MDE, но в формулу подставляется абсолютный Δ. Ошибка на этом шаге искажает выборку в разы.

Как MDE связан с размером выборки и мощностью?

Три величины образуют жёсткий треугольник: размер выборки, MDE и мощность. Зафиксировав любые две, вы определяете третью. Практический смысл:

Мощность 1−β — это вероятность обнаружить эффект, если он на самом деле равен MDE. Стандарт индустрии — 80%: то есть в 1 случае из 5 вы «промахнётесь» мимо реального эффекта размером ровно в MDE. Для критичных решений берут 90%.

Обратите внимание: MDE — это не «эффект, который мы ожидаем», а «эффект, который мы гарантированно не пропустим». Часто продакт хочет прирост +5%, а трафика хватает только на MDE +8%. Это значит: даже если фича даст ожидаемые +5%, тест с большой вероятностью закончится «не значимо». Такой тест бессмысленно запускать — либо копите трафик дольше, либо смиритесь с меньшей мощностью.

Как посчитать размер выборки: пример со сходящимися числами

Возьмём конверсию. Базовая конверсия p₁ = 0.10, хотим детектировать относительный прирост 20%, то есть p₂ = 0.12, абсолютный MDE Δ = 0.02.

Для доли дисперсия σ² = p·(1−p). Возьмём консервативно p = 0.11 (среднее двух групп): σ² = 0.11·0.89 = 0.0979.

Подставляем в формулу на группу:

n = (1.96 + 0.84)² · 2 · 0.0979 / 0.02²
n = 7.849 · 0.1958 / 0.0004
n = 1.5369 / 0.0004
n ≈ 3842

Итог: ≈ 3842 пользователя на группу, ≈ 7684 всего. Проверим правилом 16·σ²/Δ² (на две группы): 16 · 0.0979 / 0.0004 = 3916 — те же ~3900 на группу, расхождение из-за округления множителя 7.85 → 8. Числа сходятся.

Теперь уменьшим MDE вдвое — ловим +10% относительно (Δ = 0.01):

n = 7.849 · 2 · 0.0979 / 0.01² ≈ 15368 на группу

Выборка выросла ровно в 4 раза (3842 → 15368). Это и есть квадратичная плата за чувствительность.

Обратная задача — «какой MDE потяну на имеющемся трафике». Пусть есть 5000 на группу:

Δ = (z_{1−α/2} + z_{1−β}) · sqrt(2σ²/n)
Δ = 2.80 · sqrt(2·0.0979 / 5000)
Δ = 2.80 · sqrt(0.00003916)
Δ = 2.80 · 0.006258 ≈ 0.0175

MDE ≈ 1.75 п.п., то есть относительно базы 10% вы уловите минимум +17.5%. Меньше — не увидите.

Что такое дельта-метод и зачем он для ratio-метрик?

Формула выше работает для средних и долей, где единица рандомизации совпадает с единицей метрики (пользователь → его конверсия). Но в аналитике полно ratio-метрик, где числитель и знаменатель считаются на разных уровнях:

Здесь наблюдения внутри пользователя коррелированы, и наивная дисперсия занижена — тест даёт ложные срабатывания. Дельта-метод — это способ приблизить дисперсию отношения двух случайных величин через разложение Тейлора первого порядка. Для метрики R = X/Y (X — сумма числителя на юзера, Y — сумма знаменателя) дисперсия среднего оценивается так:

Var(R) ≈ (1/Ȳ²)·Var(X) + (X̄²/Ȳ⁴)·Var(Y) − 2·(X̄/Ȳ³)·Cov(X, Y)

Проще запомнить эквивалентную запись через относительные величины: дисперсия отношения ≈ R² · (CV²_X + CV²_Y − 2·ρ·CV_X·CV_Y), где CV — коэффициент вариации, ρ — корреляция числителя и знаменателя. Ключевой момент: игнорируя ковариацию (последний член), вы почти всегда переоцениваете дисперсию, а значит завышаете нужную выборку. Правильный дельта-метод даёт корректный σ², который дальше подставляется в ту же формулу размера выборки.

Данные для расчёта дисперсии удобно агрегировать SQL-ом до уровня пользователя перед выгрузкой в Python:

SELECT
    user_id,
    variant,
    SUM(clicks)      AS x,   -- числитель на юзера
    SUM(impressions) AS y    -- знаменатель на юзера
FROM ab_events
WHERE test_id = 'button_color_v3'
GROUP BY user_id, variant;

Как посчитать всё это в Python (scipy / statsmodels)?

Для долей проще всего взять готовый расчёт мощности из statsmodels. Он вернёт практически ту же выборку, что мы считали руками (арксинус-преобразование Коэна даёт чуть меньше — оно немного эффективнее грубого нормального приближения с пулированной дисперсией).

import numpy as np
from statsmodels.stats.power import NormalIndPower
from statsmodels.stats.proportion import proportion_effectsize

# Базовая 10%, целевая 12% (MDE = +2 п.п. = +20% относительно)
p1, p2 = 0.10, 0.12
effect = proportion_effectsize(p2, p1)   # эффект Коэна h

n = NormalIndPower().solve_power(
    effect_size=effect,
    alpha=0.05,
    power=0.80,
    alternative='two-sided',
)
print(round(n))   # ~3836 на группу — практически совпадает с ручным расчётом ~3842

Дельта-метод для ratio-метрики считается руками — это несколько строк на numpy по агрегированным на уровень пользователя данным:

import numpy as np

# x — клики на юзера, y — показы на юзера (из SQL выше)
def ratio_var(x, y):
    x, y = np.asarray(x, float), np.asarray(y, float)
    n = len(x)
    xbar, ybar = x.mean(), y.mean()
    var_x, var_y = x.var(ddof=1), y.var(ddof=1)
    cov_xy = np.cov(x, y, ddof=1)[0, 1]
    # дисперсия среднего отношения по дельта-методу
    var_ratio = (var_x / ybar**2
                 + xbar**2 / ybar**4 * var_y
                 - 2 * xbar / ybar**3 * cov_xy) / n
    return xbar / ybar, var_ratio

r, var_r = ratio_var(x, y)
se = np.sqrt(var_r)
# доверительный интервал для CTR
print(r, r - 1.96*se, r + 1.96*se)

Полученный se (или дисперсию на уровень наблюдения) подставляете в ту же формулу размера выборки, что и для средних. Разница только в том, что σ² берётся дельта-методом, а не наивно.

Частые ошибки при работе с MDE

ОшибкаПоследствие
Путают абсолютный и относительный MDEВыборка занижена/завышена в разы
Наивная дисперсия для CTR/ARPUЛожные срабатывания (α по факту выше 5%)
MDE подгоняют под имеющийся трафик задним числомТест недомощный, «не значимо» ничего не доказывает
Мощность по умолчанию не проверяютПоловина эффектов пропускается
Считают выборку по финальной конверсии, а не по σОшибка на волатильных метриках (выручка)

Отдельно про выручку: у неё тяжёлый хвост, дисперсия огромная, поэтому MDE по ARPU часто получается неприлично большим. Помогает либо винзоризация, либо CUPED (снижение дисперсии по ковариате), либо переход на более стабильную прокси-метрику вроде конверсии.

Краткий чек-лист перед запуском теста

MDE — это честный ответ на вопрос «что мы вообще способны увидеть на нашем объёме данных». Считать его до теста дисциплинирует: половина «неудачных» тестов на самом деле просто недомощные, и грамотный расчёт выборки экономит недели впустую потраченного трафика.


Потренировать SQL-агрегацию для расчёта дисперсии можно в SQL-тренажёре, а numpy и scipy для дельта-метода — в Python-тренажёре. Смотрите также разбор смежных метрик: конверсия и retention, подборку задач по A/B-тестам и статью A/B-тесты на Python со scipy.stats.

Хотите отработать дизайн A/B-тестов на реальных задачах с проверкой решения и разбором — в Pro-доступе открыты все 425 SQL и 402 Python-задачи, кейсы и AI мок-собесы по статистике.

Разбери A/B-тесты на практике
Python-тренажёр со scipy, задачи по статистике и мок-интервью.
Открыть Python-тренажёр →