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

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

Зачем sequential testing

Классический A/B: заранее посчитал sample size, ждёшь до конца, смотришь p-value. На практике PM подсматривает каждый день. Если останавливаться на первой «значимости», ложно-позитивных в 3–10 раз больше, чем кажется. Sequential testing — методы, которые позволяют смотреть в любой момент, не теряя гарантий по alpha.

Peeking-bias и его цена

WITH simulated_peeking AS (
    SELECT
        run_id,
        day,
        cumulative_p_value,
        MIN(cumulative_p_value) OVER (PARTITION BY run_id ORDER BY day) AS min_p_so_far
    FROM null_simulation_runs
)
SELECT
    COUNT(DISTINCT CASE WHEN min_p_so_far < 0.05 THEN run_id END)::NUMERIC * 100
    / COUNT(DISTINCT run_id) AS false_positive_rate_pct
FROM simulated_peeking;

Симуляция показывает, что peeking 30 раз превращает заявленный alpha 5% в фактические ~25%.

Alpha-spending O'Brien-Fleming

Идея: делим alpha по «информационной шкале». На ранних просмотрах используем очень маленький alpha, на финальном — близкий к 0.05.

WITH config AS (
    SELECT 0.05::NUMERIC AS total_alpha, 5::INT AS planned_looks
),
schedule AS (
    SELECT
        gs AS look_number,
        gs::NUMERIC / planned_looks AS information_fraction,
        total_alpha
    FROM config, generate_series(1, planned_looks) gs
)
SELECT
    look_number,
    information_fraction,
    -- O'Brien-Fleming приближение: z-граница ~ z_alpha / sqrt(t)
    -- z_0.05/2 ≈ 1.96; пересчёт в эффективный alpha
    2 * (1 - 0.5 * (1 + ERF(1.96 / SQRT(information_fraction) / SQRT(2)))) AS alpha_for_look
FROM schedule;

В Postgres нет встроенной ERF (некоторые дистрибутивы её добавляют), часто считают вне или через polynomial approximation. Логика: на 1-м просмотре alpha < 0.001, на финальном ≈ 0.04.

mSPRT в SQL

Modified Sequential Probability Ratio Test от Optimizely. Считает «mixture likelihood ratio» — растёт постепенно:

WITH cumulative AS (
    SELECT
        day,
        SUM(CASE WHEN variant = 'B' THEN revenue ELSE 0 END) OVER (ORDER BY day) AS s_b,
        SUM(CASE WHEN variant = 'A' THEN revenue ELSE 0 END) OVER (ORDER BY day) AS s_a,
        SUM(CASE WHEN variant = 'B' THEN 1 ELSE 0 END) OVER (ORDER BY day) AS n_b,
        SUM(CASE WHEN variant = 'A' THEN 1 ELSE 0 END) OVER (ORDER BY day) AS n_a
    FROM ab_daily
),
test_stat AS (
    SELECT
        day,
        n_a, n_b,
        (s_b / NULLIF(n_b, 0) - s_a / NULLIF(n_a, 0)) AS diff,
        -- упрощённое: |z| > порог = решение
        (s_b / NULLIF(n_b, 0) - s_a / NULLIF(n_a, 0))
        / NULLIF(SQRT(
            (s_a / NULLIF(n_a, 0) * (1 - s_a / NULLIF(n_a, 0))) / NULLIF(n_a, 0)
            + (s_b / NULLIF(n_b, 0) * (1 - s_b / NULLIF(n_b, 0))) / NULLIF(n_b, 0)
          ), 0) AS z
    FROM cumulative
)
SELECT
    day,
    z,
    CASE WHEN ABS(z) > 2.5 THEN 'STOP — reject H0' ELSE 'continue' END AS decision
FROM test_stat;

Порог 2.5 — пример, реальный msprt-порог зависит от заданного τ (prior variance).

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

Always-valid p-value

Aaditya Ramdas и команда Berkeley предложили AV-p-values, которые остаются валидными при любом числе просмотров. В SQL обычно делают post-hoc adjustment к классическому p:

SELECT
    day,
    classical_p_value,
    -- Bonferroni-like adjustment for N looks
    LEAST(classical_p_value * planned_looks, 1.0) AS always_valid_p
FROM ab_daily_p_values;

Грубо, но проще, чем mSPRT — годится для дашбордов.

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

Ошибка 1. Пытаться имитировать sequential testing «глазами». «Если 3 дня подряд p < 0.05» — это не sequential, и не контролирует alpha.

Ошибка 2. Бесконечное подсматривание. Если число просмотров неизвестно, нужен фреймворк always-valid, не fixed alpha-spending.

Ошибка 3. Альфа-спендинг для ratio-метрик без delta method. SRM / clicks-per-session — нужна вариация ratio (delta method) до того, как считаете границы.

Ошибка 4. Игнорировать SRM check на ранних шагах. Sample Ratio Mismatch (бакетинг сломан) часто проявляется в первые часы. Если sequential test «находит эффект» — проверьте SRM.

Ошибка 5. Сообщать «classical p» при sequential дизайне. В отчёте — корректированный p и информация о фреймворке (mSPRT / O'Brien-Fleming).

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

FAQ

Можно ли sequential без библиотеки?

Базовое alpha-spending — да, по табличным границам. mSPRT — лучше через сервис (Optimizely / GrowthBook).

Когда выбрать sequential vs fixed-horizon?

Sequential — когда хотите ранний stop. Fixed — когда команда дисциплинирована, готова ждать.

Какой alpha-spending для 10 просмотров?

O'Brien-Fleming или Pocock; таблицы по α=0.05, K=10 в учебниках. Точные значения — пакет gsDesign в R.

Sequential vs Bayesian?

Bayesian decision (posterior probability) даёт интуитивную остановку, но требует prior. Sequential — частотный, без приоров.

Минимум на early stop?

Никогда не останавливать до контрольной точки SRM и до minimum sample for variance estimation (обычно n > 1000 на ARM).