Перейти к содержанию

Статистика сравнения

Эта страница — вывод того, что считают ranklens.stats, ranklens.aggregate и ranklens compare: какая гипотеза проверяется, откуда интервал, p-value и q-value и почему им можно верить.

Единица наблюдения — запрос

Для метрики \(M\) (например, NDCG@10) и запроса \(q\), который есть в обоих прогонах, разница

\[ \delta_q = M_B(q) - M_A(q). \]

Всё дальнейшее — о среднем \(\bar\delta = \frac1n \sum_q \delta_q\) по \(n\) парным запросам. Запросы из одного прогона отбрасываются: парному тесту нужны пары.

Ресемплируются запросы, а не строки выдачи. Документы одной выдачи зависимы: если ресемплировать строки, получится больше «независимых» наблюдений, чем есть, и интервал станет уже правды. Вывод — о совокупности запросов, из которой взята выборка, а не о документах или пользователях.

Интервал: парный bootstrap

Из \(n\) разниц \(B\) раз берётся выборка того же размера с возвращением, для каждой считается среднее \(\bar\delta^{*}_b\). Интервал уровня \(1-\alpha\) — перцентили:

\[ \left[\, \bar\delta^{*}_{(\alpha/2)},\ \bar\delta^{*}_{(1-\alpha/2)} \,\right]. \]

Он отвечает на вопрос «насколько точно измерено среднее», но гипотезу не проверяет. Покрытие проверено симуляцией: на 1000 выборок 95%-й интервал содержит истинное среднее в 95.3% случаев. На малых выборках со скошенными разницами перцентильный интервал бывает уже, чем нужно, — поэтому p-value считается отдельно.

p-value: перестановочный тест

Гипотеза. \(H_0\): распределение \(\delta_q\) симметрично относительно нуля — для каждого запроса всё равно, какой прогон назвать A, а какой B.

При \(H_0\) знак каждой разницы случаен. Тест \(m\) раз переворачивает знаки независимо с вероятностью ½ и считает, сколько раз \(b\) среднее по модулю не меньше наблюдаемого:

\[ p = \frac{b + 1}{m + 1}, \qquad b = \#\left\{ j : \Bigl|\tfrac1n \textstyle\sum_q s_{jq}\,\delta_q\Bigr| \ge |\bar\delta| \right\}, \quad s_{jq} \in \{-1, +1\}. \]

Единицы в числителе и знаменателе — наблюдаемая расстановка знаков: она тоже принадлежит множеству перестановок. Поэтому \(p > 0\) всегда, а \(P_{H_0}(p \le \alpha) \le \alpha\) для любого \(m\) — тест точный, а не асимптотический. При \(m = 10\,000\) минимальное значение ≈ \(10^{-4}\).

p-value дискретен с шагом \(1/(m+1)\), поэтому равномерность под \(H_0\) проверяется долей отвержений на уровнях 0.05, 0.1, 0.2, а не тестом Колмогорова — Смирнова.

Много сравнений: Бенджамини — Хохберг

При 40 сегментах и \(\alpha = 0.05\) даже одинаковые модели дают в среднем \(40 \cdot 0.05 = 2\) «значимых» сегмента. Поправка Бонферрони (порог \(\alpha/m\)) контролирует вероятность хотя бы одной ошибки (FWER) и на десятках сегментов почти ничего не пропускает. BH контролирует другое — FDR, ожидаемую долю ложных среди объявленных находками:

\[ \mathrm{FDR} = \mathbb{E}\left[\frac{V}{\max(R, 1)}\right] \le \alpha, \]

где \(R\) — число находок, \(V\) — число ложных среди них.

Процедура. Отсортируем p-values: \(p_{(1)} \le \dots \le p_{(m)}\). Находки — все гипотезы с рангом не больше \(k = \max\{ i : p_{(i)} \le \tfrac{i}{m}\alpha \}\). Эквивалентно — через q-value, которое печатается в отчёте:

\[ q_{(i)} = \min_{j \ge i} \min\!\left( \frac{m}{j}\, p_{(j)},\ 1 \right), \]

и находка — это \(q < \alpha\). Минимум по \(j \ge i\) нужен, чтобы q не убывал при росте p: иначе более сильное свидетельство получило бы больший q.

from ranklens.stats import benjamini_hochberg

# 0.01 * 3/1 = 0.03;  0.04 * 3/2 = 0.06;  0.5 * 3/3 = 0.5
print(benjamini_hochberg([0.01, 0.04, 0.5]))
(0.03, 0.06, 0.5)

p = 0.04 по отдельности проходит порог 0.05, а среди трёх сравнений — уже нет.

Когда BH корректен. Для независимых p-values (и для положительно зависимых, PRDS). Сегменты не пересекаются по запросам, значит их сравнения независимы — ровно условие теоремы. Чтобы этой независимости не мешала общая случайность, каждый сегмент получает свой поток случайных чисел, порождённый из seed: при общем потоке сегменты одного размера получали бы одинаковые ресемплы.

Что считается семьёй. С --segments — сегменты одной метрики; без них — метрики между собой.

Интервалы не поправляются. Интервал сегмента может не содержать ноль при \(q \ge \alpha\) — решает q-value.

Сколько нужно запросов: MDE

Минимальный обнаружимый эффект — наименьшая истинная разница, которую двусторонний тест уровня \(\alpha\) обнаружит с вероятностью (мощностью) \(1-\beta\). По ЦПТ \(\bar\delta \approx \mathcal N(\Delta, \sigma^2/n)\), где \(\sigma\) — стандартное отклонение \(\delta_q\). Отвержение — когда \(|\bar\delta| > z_{1-\alpha/2}\,\sigma/\sqrt n\). Требуем, чтобы при истинной разнице \(\Delta\) это происходило с вероятностью \(1-\beta\) (вклад противоположного хвоста пренебрежимо мал):

\[ \Delta - z_{1-\alpha/2}\frac{\sigma}{\sqrt n} = z_{1-\beta}\frac{\sigma}{\sqrt n} \quad\Longrightarrow\quad \mathrm{MDE} = \bigl(z_{1-\alpha/2} + z_{1-\beta}\bigr)\frac{\sigma}{\sqrt n}, \qquad n = \left(\frac{(z_{1-\alpha/2} + z_{1-\beta})\,\sigma}{\Delta}\right)^{2}. \]

При \(\alpha = 0.05\) и мощности 0.8 множитель ≈ 1.96 + 0.84 = 2.80:

from ranklens.stats import mde, required_queries

print(f"MDE на 200 запросах при sd = 0.1: {mde(sd=0.1, n_queries=200):.4f}")
for delta in (0.02, 0.01, 0.005):
    print(f"чтобы увидеть +{delta}: {required_queries(delta, sd=0.1)} запросов")
MDE на 200 запросах при sd = 0.1: 0.0198
чтобы увидеть +0.02: 197 запросов
чтобы увидеть +0.01: 785 запросов
чтобы увидеть +0.005: 3140 запросов

Незначимый результат на малой выборке не означает «эффекта нет»: он значит, что эффект ниже разрешающей способности этой выборки.

Неточная разметка: PPI++

Всё выше предполагает, что метрика по запросу измерена верно. Если разметка систематически ошибается — LLM завышает оценки длинным документам, один асессор строже консилиума, — дельта \(\bar\delta\) смещена, и интервал останется узким вокруг неверного числа: ресемплинг запросов этого не видит.

Две разметки. Дешёвая (proxy: LLM, один асессор) есть на всех запросах; эталонная (gold: консилиум, эксперты) — на случайной подвыборке \(G\) из \(n\) запросов. \(U\) — остальные \(N\) запросов, только с proxy. Для каждого запроса — дельта «B минус A» по proxy-разметке \(\delta^{p}_q\) и, на \(G\), по gold-разметке \(\delta^{g}_q\).

Оценка (prediction-powered inference):

\[ \hat\Delta_\lambda = \lambda\,\frac1N \sum_{q \in U} \delta^{p}_q + \frac1n \sum_{q \in G} \bigl(\delta^{g}_q - \lambda\,\delta^{p}_q\bigr). \]

Второе слагаемое — поправка: на тех же запросах видно, насколько proxy ошибается именно в этой разнице. Несмещённость для любого \(\lambda\): \(G\) — случайная выборка, поэтому \(\mathbb E\,\overline{\delta^p}_U = \mathbb E\,\overline{\delta^p}_G\), и слагаемые с \(\lambda\) сокращаются в среднем: \(\mathbb E\,\hat\Delta_\lambda = \mathbb E\,\delta^g\). Если люди размечали «интересные» запросы, а не случайные, это равенство неверно, и оценка смещена.

Дисперсия. \(U\) и \(G\) не пересекаются, слагаемые независимы:

\[ \operatorname{Var}\hat\Delta_\lambda = \frac{\lambda^2 \sigma_p^2}{N} + \frac{\sigma_g^2 - 2\lambda c + \lambda^2 \sigma_p^2}{n}, \qquad c = \operatorname{Cov}(\delta^g, \delta^p). \]

PPI++: \(\lambda\) по данным. Производная по \(\lambda\) равна нулю при

\[ \lambda^{*} = \frac{c}{\bigl(1 + n/N\bigr)\,\sigma_p^{2}}, \]

\(c\) оценивается на \(G\), \(\sigma_p^2\) — по всем proxy-дельтам. \(\lambda = 0\) — только gold, \(\lambda = 1\) — классический PPI; \(\lambda^*\) не хуже ни того, ни другого: хороший proxy получает \(\lambda\) около 1, бесполезный — около 0. Интервал и p-value — нормальное приближение.

Симуляция: 2000 повторов, \(N = 2000\), \(n = 200\), истинная дельта 0.010:

proxy разброс PPI++ PPI (\(\lambda=1\)) только gold \(\hat\lambda\)
хороший, смещён на +0.006 0.0029 0.0032 0.0071 0.83
плохой 0.0067 0.0091 0.0069 0.17
без связи с gold 0.0070 0.0102 0.0070 0.00

Все три несмещены; proxy без поправки дал бы 0.016. Покрытие 95% интервала PPI++ — 0.945–0.956. При плохом proxy классический PPI хуже, чем «только gold», — поэтому \(\lambda\) оценивается, а не фиксируется.

Чего эти числа не говорят

  • Не «отличаются ли ранжирования». Одинаковый NDCG возможен при совершенно разном порядке документов — для этого ranklens.metrics.rbo.
  • Не «заметят ли пользователи». Это онлайн-эксперимент.
  • Не «верна ли разметка» — если не использовать gold-подвыборку и PPI++ (выше).