Multipla jämförelser
Kunna korrigera för många samtidiga test och förklara varför benchmark-jakt ger falska framsteg.
Förkunskaper
Intuition
Testar du en hypotes med α = 0,05 är risken för falsklarm 5 %. Testar du tjugo oberoende hypoteser är risken att minst en ger falsklarm:
1 − 0,95²⁰ ≈ 64 %
Det är matematiken bakom en stor del av det som ser ut som framsteg i ML. Prova tjugo arkitekturvarianter, rapportera den som vann — och du har rapporterat brus.
| Antal test | P(minst ett falsklarm) |
|---|---|
| 1 | 5 % |
| 5 | 23 % |
| 20 | 64 % |
| 100 | 99,4 % |
Formellt
Bonferroni: använd tröskeln för test. Kontrollerar familywise error rate (risken för något falsklarm). Enkelt och konservativt — med 20 test blir tröskeln 0,0025, och verkliga effekter missas lätt.
Benjamini–Hochberg (FDR): sortera p-värdena , hitta största med , förkasta alla upp till . Kontrollerar andelen falska bland de förkastade i stället för risken för någon enda. Mycket mer kraftfull när många test görs, och standard i exempelvis genetik.
Det viktigaste är ändå inte korrektionen utan redovisningen: rapportera hur många varianter som provades. Ett resultat från «vi testade tre konfigurationer» och ett från «vi testade hundra» är olika starka, även med samma p-värde.
Benchmark-jakt är samma fenomen på fältnivå: hundratals forskargrupper testar mot samma benchmark, och de som råkar få höga tal publicerar. Därför krävs replikering på nya data — inte bara ett rekord.
Kod
import numpy as np
def bonferroni(p, alfa=0.05):
p = np.asarray(p)
return p <= alfa / len(p)
def benjamini_hochberg(p, alfa=0.05):
p = np.asarray(p); m = len(p)
ordning = np.argsort(p)
trosklar = (np.arange(1, m + 1) / m) * alfa
under = p[ordning] <= trosklar
k = np.max(np.where(under)[0]) + 1 if under.any() else 0
ut = np.zeros(m, bool); ut[ordning[:k]] = True
return ut
p = [0.001, 0.008, 0.02, 0.04, 0.06, 0.20, 0.31, 0.55]
print(bonferroni(p).astype(int)) # [1 0 0 0 0 0 0 0]
print(benjamini_hochberg(p).astype(int)) # [1 1 1 0 0 0 0 0]
# risken för minst ett falsklarm utan korrektion
for m in (1, 5, 20, 100):
print(m, round(1 - 0.95 ** m, 3))
Behärskning innebär
- Korrigerar för många samtidiga test
- Förklarar varför benchmark-jakt ger falska framsteg
- Väljer mellan Bonferroni och FDR
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- Wikipedia — Multiple comparisons problem (CC BY-SA 4.0) — CC BY-SA 4.0
- Wikipedia — False discovery rate (CC BY-SA 4.0) — CC BY-SA 4.0