Как посчитать SRM в SQL

Проверь себя · 1/3разбор после ответа
Запустили A/B-тест с планом 50/50, а в логах видим 53/47 при миллионе пользователей. Что описывает термин SRM (Sample Ratio Mismatch) применительно к этой ситуации?

Зачем SRM

SRM (Sample Ratio Mismatch) — это когда фактическое распределение пользователей между вариантами A и B отличается от ожидаемого (например, от 50/50). Если есть SRM, тест сломан, а его результатам доверять нельзя. Проверка на SRM — обязательный этап перед анализом любого A/B-теста.

Формула

Chi-square test:

χ² = Σ ((observed - expected)² / expected)

Если p-value < 0.001 (или 0.005), значит, обнаружен SRM.

Базовый расчёт

WITH observed AS (
    SELECT
        variant,
        COUNT(DISTINCT user_id) AS n
    FROM ab_test_assignments
    WHERE test_id = 123
    GROUP BY variant
),
total AS (
    SELECT SUM(n) AS total_n FROM observed
)
SELECT
    o.variant,
    o.n AS observed,
    t.total_n * 0.5 AS expected,  -- 50/50 split
    POW(o.n - t.total_n * 0.5, 2) / (t.total_n * 0.5) AS chi_sq_contribution
FROM observed o, total t
ORDER BY o.variant;

Сложите все chi_sq_contributions. Сравните сумму с критическим значением chi-square (df=1 при двух вариантах): 10.83 соответствует p=0.001.

Когда SRM критична

При 50/50:

  • N=10,000: 5050/4950 — нормально (chi² = 1.0, p ≈ 0.32)
  • N=10,000: 5300/4700 — SRM (chi² = 36, p < 0.0001)

«Допустимый» перекос зависит от размера выборки. На большой выборке даже разница в 1% означает SRM.

Закрепи формулу srm в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать srm в Telegram

Причины SRM

  1. Бот-трафик неравномерно распадается по вариантам.
  2. Баг в логике бакетирования — назначение в вариант смещено.
  3. Пропуски в трекинге — события теряются у одного из вариантов.
  4. Кеширование — старые пользователи застревают в старом бакете.
  5. Падение варианта — вариант B крашится, и его пользователей трекается меньше.
-- Drill: SRM by date
SELECT
    DATE_TRUNC('day', assigned_at) AS day,
    variant,
    COUNT(*) AS users,
    COUNT(*) FILTER (WHERE variant = 'A')::NUMERIC * 100 / COUNT(*) OVER (PARTITION BY DATE_TRUNC('day', assigned_at)) AS pct_a
FROM ab_test_assignments
WHERE test_id = 123
GROUP BY DATE_TRUNC('day', assigned_at), variant
ORDER BY day, variant;

Если SRM появилась после какого-то дня, разбирайтесь с деплоем именно за эту дату.

SRM по сегментам

SRM в целом в норме, но в отдельном сегменте — сломан:

SELECT
    u.country,
    COUNT(*) FILTER (WHERE a.variant = 'A') AS a_users,
    COUNT(*) FILTER (WHERE a.variant = 'B') AS b_users,
    COUNT(*) FILTER (WHERE a.variant = 'A')::NUMERIC * 100 / COUNT(*) AS pct_a
FROM ab_test_assignments a
JOIN users u ON u.user_id = a.user_id
WHERE a.test_id = 123
GROUP BY u.country
HAVING ABS(COUNT(*) FILTER (WHERE a.variant = 'A')::NUMERIC * 100 / COUNT(*) - 50) > 3
ORDER BY 4;

Частые ошибки

Ошибка 1. Игнорировать SRM. SRM — это проблема качества данных. Не доверяйте значимым результатам, пока не исключили SRM.

Ошибка 2. Слишком мягкий порог. α = 0.05 для SRM даёт много ложных тревог. Берите 0.001 или 0.005.

Ошибка 3. Проверять SRM только на старте. Перепроверяйте SRM регулярно — перекос нередко возникает уже в середине теста.

Ошибка 4. Не смотреть SRM по сегментам. В целом всё в норме, но в отдельном сегменте распределение перекошено. Перепроверьте стратификацию.

Ошибка 5. SRM в триггерных экспериментах. Логика триггера может срабатывать по-разному в разных вариантах. Проверяйте SRM ещё на пуле до экспозиции.

Связанные темы

FAQ

Какой порог для SRM?

Берите p < 0.001 или 0.005. Порог держат строгим намеренно: SRM — критичная защитная проверка, и лучше лишний раз перепроверить тест, чем пропустить смещение.

SRM есть — что делать?

Остановите тест и разберитесь, где именно ломается — в распределении по вариантам или в трекинге событий. После того как нашли и починили причину, перезапускайте эксперимент заново.

Появился SRM один раз — перезапускать?

Да, перезапускать. Смещённым данным доверять нельзя, а цена починки почти всегда ниже цены неверного решения по продукту.

SRM в триггерных экспериментах?

Проверяйте SRM на пуле пользователей до экспозиции. Иногда сам триггер срабатывает смещённо и по-разному заводит людей в варианты — тогда причина именно в логике триггера, а не в самом сплите.

Есть ли инструменты с авто-проверкой SRM?

Да, Statsig, Optimizely и Eppo встроили проверку SRM из коробки. С 2024 года это фактически обязательная функция любой серьёзной A/B-платформы.