40.2 Becslés, intervallum és érzékenység

Előzetesen rögzített vizsgálat: a permutációs teszt az éles nullhipotézis alatt, az eredeti randomizációs séma reprodukálásával igazolható. A percentilis bootstrap és a Wald-intervallum kis mintán vagy szélső arányok mellett pontatlanul fedhet; az alkalmazott intervallumeljárásnak szerepelnie kell az előzetes tervben.

40.2.1 Cél és konkrét helyzet

A Kísérleti kérdés és előzetes elemzési terv alfejezetben befagyasztott kísérleti terv szerint 300 szintetikus ügyfelet randomizáltunk control és treatment ágra. Az assignments.csv egy sor = egy ügyfél, a customer_id egyedi, a variant oszlop a randomizált beavatkozás. Az outcomes.csv ugyanezen ügyfelek teljes, 7 napos kimenetét tartalmazza; a primer végpont a conversion_7d bináris változó. A revenue_7d_minor másodlagos, folytonos végpont, itt csak érzékenységi szempontból jelenik meg. Az elemzési egység az ügyfél, nem a rendelés vagy a rendelési tétel: a kísérleti nevező 300, és nem szabad az order_items sorainak számával felnagyítani.

Bemenet: lab/assignments.csv, lab/outcomes.csv. Közbenső tábla: customer_id kulcsú join, egy-egy reláció. Kimenet: abszolút hatásbecslés (difference in proportions), 95%-os konfidenciaintervallum, előre rögzített permutációs teszt p-értéke, valamint érzékenységi ellenőrzés. A módszerválasztás indoklása és legalább egy érvényességi korlát szöveges megnevezése szintén átadandó.

Induló becslés: a generáló folyamatot nem ismerjük, de hasonló beavatkozásoknál 5–15 százalékpontos abszolút konverziónövekedés várható. A 300 fős mintán ilyen hatás észlelhető, de az intervallum széles marad: nagyságrendileg ±6–7 százalékpont a 95%-os fél-szélesség. A feladat nem az, hogy „szignifikáns legyen”, hanem hogy a bizonytalanság korrektül, a döntési célhoz illő skálán szerepeljen.

40.2.2 Fogalmi magyarázat

Difference in proportions. Legyenek a karok:

Az abszolút különbség mértékegysége konverzió/ügyfél, tehát 0,10 értéke azt jelenti: 100 randomizált ügyfélből várhatóan 10-zel többen konvertálnak a kezelt ágon. Ez az értelmezés közvetlenül használható költség–haszon döntésben.

Standard error és Wald-intervallum. Ha a két minta független binomiális megfigyelés, a különbség becsült szórása

SE(τ̂)=p̂c(1−p̂c)nc+p̂t(1−p̂t)nt.SE(\hat\tau) = \sqrt{\frac{\hat p_c(1-\hat p_c)}{n_c} + \frac{\hat p_t(1-\hat p_t)}{n_t}}.

Ez az ún. unpooled vagy Neyman-típusú képlet. Randomizált kísérletben a valódi variancia kismértékben eltér, mert a kimenetelek rögzítettek, és a véletlen a hozzárendelés; a binomiális közelítés azonban a gyakorlatban elfogadható, ha a cella-várható esetszámok nem extrém kicsik. A közelítő 95%-os intervallum

τ̂±1,96⋅SE(τ̂).\hat\tau \pm 1{,}96 \cdot SE(\hat\tau).

Ez aszimptotikus (nagy mintás) eljárás. A confidence level a mintavételi eljárás hosszú távú lefedettségéhez kötött: sok ismételt kísérletben a 95%-os intervallumok körülbelül 95%-a tartalmazná a valódi hatást. Azt nem állítja, hogy az aktuális intervallum 95% valószínűséggel tartalmazza a paramétert; a paraméter rögzített, a véletlen az intervallumban van.

Kézi ellenőrzés: legyen nc=nt=100n_c = n_t = 100, Xc=18X_c = 18, Xt=28X_t = 28. Ekkor p̂c=0,18\hat p_c = 0{,}18, p̂t=0,28\hat p_t = 0{,}28, τ̂=0,10\hat\tau = 0{,}10. A standard error:

SE=0,18⋅0,82100+0,28⋅0,72100=0,001476+0,002016=0,003492≈0,0591.SE = \sqrt{\frac{0{,}18 \cdot 0{,}82}{100} + \frac{0{,}28 \cdot 0{,}72}{100}} = \sqrt{0{,}001476 + 0{,}002016} = \sqrt{0{,}003492} \approx 0{,}0591.

A 95%-os intervallum: 0,10±1,96⋅0,0591≈(−0,016,0,216)0{,}10 \pm 1{,}96 \cdot 0{,}0591 \approx (-0{,}016,\ 0{,}216). A nulla benne van, tehát ekkora mintán ez a hatás nem elkülöníthető a zajtól.

Effect scale. A bináris végpontnál három gyakori skála létezik:

A relatív és abszolút skála közötti választás üzleti kérdés: ha a konverzió alaparánya 2%, akkor a 2% → 3% relatíve 50%-os növekedés, abszolút értékben 1 százalékpont. A jelentésben mindkét skálát érdemes feltüntetni, de a következtetéshez előre rögzítsük az elsődlegeset — a terv szerint az abszolút különbséget.

Bootstrap. A bootstrap a mintavételezési bizonytalanságot újramintavételezéssel közelíti. Az elemzési egység az ügyfél, ezért a resamplingnak is ügyfélszintűnek kell lennie. Karokon belül, visszatevéssel húzunk ncn_c és ntn_t megfigyelést, újraszámoljuk τ̂\hat\tau-t, ezt BB-szer ismételjük. A bootstrap replicák 2,5%2{,}5\%-os és 97,5%97{,}5\%-os kvantilise adja a percentile-intervallumot. A módszer nem igényli a binomiális közelítést, de továbbra is feltételezi, hogy a megfigyelt minta reprezentatív a sokaságra, és a megfigyelések a resampling egység szintjén függetlenek.

Permutation test. A nullhipotézis: éles nulla — a beavatkozás egyetlen ügyfél kimenetére sem hat. Ekkor a kezelési címkék felcserélhetők. A permutációs teszt a megfigyelt kimeneteleket megtartja, a hozzárendelést véletlenül újraosztja, és minden permutációnál kiszámítja a két kar átlagos konverziókülönbségét. A p-érték a null-eloszlásból számított feltételes szélsőség:

p=#{|τ̂perm|≥|τ̂obs|}+1B+1.p = \frac{\#\{|\hat\tau_{\text{perm}}| \ge |\hat\tau_{\text{obs}}|\} + 1}{B + 1}.

A +1+1-es korrekció a Monte Carlo-hibát simítja; B=10000B=10\,000 mellett a p-érték numerikus hibája néhány ezred. A permutációs teszt pontosabb kis mintán, mint a Wald-féle normalitás, mert nem támaszkodik aszimptotikára, csak a randomizációra.

Assumptions. Mindhárom eljárás érvényességéhez szükséges:

  1. Véletlen hozzárendelés: az assignments.csv szerint randomizált; ezt a terv rögzíti.
  2. SUTVA / interferencia hiánya: egy ügyfél kimenete nem függ mások hozzárendelésétől. Ha például a kezelés egy kereskedelmi ösztönző, és az ügyfelek megosztják egymással, sérülhet; e szintetikus laborban feltesszük.
  3. Teljes megfigyelés: az outcomes.csv mind a 300 ügyfélre tartalmazza a 7 napos kimenetet, observed_until azonos. Nincs lemorzsolódás. Ha hiányzó kimenet lenne, az ITT-elemzéshez előre definiált imputáció vagy alsó/legrosszabb eset kell; az exclusion nem lehet adatvezérelt.
  4. Előre rögzített primer végpont és teszt: a Kísérleti kérdés és előzetes elemzési terv alfejezetben rögzített terv szerint a conversion_7d és a permutációs teszt a megerősítő elemzés.
  5. Független megfigyelések az elemzési egység szintjén. Ügyfélszintű randomizálásnál az ügyfél az egység; ha egy ügyfél több rendelést is adhatna a 7 nap alatt, a kimenetet akkor is egy ügyfélre aggregáljuk.

40.2.3 Teljes minimális munkapélda

A kód a lab/ gyökérből futtatható. Az alábbi szkript a két CSV-t egyesíti, ellenőrzi a kulcs egyediségét, kiszámítja a pontbecslést, a Wald- és bootstrap-intervallumot, valamint a permutációs tesztet.

# lab/s158_estimate.py
from pathlib import Path
import numpy as np
import pandas as pd
from scipy import stats

base = Path("lab")
assign = pd.read_csv(base / "assignments.csv")
outcome = pd.read_csv(base / "outcomes.csv")

# Kötelező ellenőrzés: egy ügyfél pontosan egyszer szerepel.
assert assign["customer_id"].is_unique
assert outcome["customer_id"].is_unique
df = assign.merge(outcome, on="customer_id", validate="one_to_one")
assert df.shape[0] == 300

control = df.loc[df["variant"] == "control", "conversion_7d"].to_numpy()
treat = df.loc[df["variant"] == "treatment", "conversion_7d"].to_numpy()
n_c, n_t = len(control), len(treat)
p_c, p_t = control.mean(), treat.mean()
diff_hat = p_t - p_c

# Wald: két független arány különbségének standard hibája.
se = np.sqrt(p_c * (1 - p_c) / n_c + p_t * (1 - p_t) / n_t)
ci_wald = diff_hat + np.array([-1, 1]) * stats.norm.ppf(0.975) * se

rng = np.random.default_rng(20261020)
B = 10_000

# Ügyfélszintű bootstrap, karokon belül visszatevéssel.
boot_diffs = np.empty(B)
for b in range(B):
    c_res = rng.choice(control, size=n_c, replace=True)
    t_res = rng.choice(treat, size=n_t, replace=True)
    boot_diffs[b] = t_res.mean() - c_res.mean()
ci_boot = np.quantile(boot_diffs, [0.025, 0.975])

# Permutációs teszt: éles nulla mellett a címkék felcserélhetők.
all_y = np.concatenate([control, treat])
n_total = len(all_y)
perm_diffs = np.empty(B)
for b in range(B):
    perm = rng.permutation(n_total)
    perm_control = all_y[perm[:n_c]]
    perm_treat = all_y[perm[n_c:]]
    perm_diffs[b] = perm_treat.mean() - perm_control.mean()
p_value = (np.sum(np.abs(perm_diffs) >= np.abs(diff_hat)) + 1) / (B + 1)

print(f"n_control={n_c}, n_treatment={n_t}")
print(f"p_control={p_c:.4f}, p_treatment={p_t:.4f}")
print(f"Abszolút hatás (risk difference) = {diff_hat:.4f}")
print(f"Relatív kockázat RR = {p_t / p_c:.2f}")
print(f"Wald SE = {se:.4f}, 95% CI = ({ci_wald[0]:.4f}, {ci_wald[1]:.4f})")
print(f"Bootstrap 95% CI = ({ci_boot[0]:.4f}, {ci_boot[1]:.4f})")
print(f"Permutációs p-érték = {p_value:.4f}")

A blokk kimenete a helyi adattól függ. Az alábbi szemléltető kimenet a generáló paraméterek nagyságrendjét mutatja, és nem állítjuk, hogy éppen ezt a futást láttuk:

Szemléltető kimenet — a tényleges értékek a lab adatain futáskor képződnek:
n_control=150, n_treatment=150
p_control=0.1733, p_treatment=0.2867
Abszolút hatás (risk difference) = 0.1133
Relatív kockázat RR = 1.65
Wald SE = 0.0485, 95% CI = (0.0183, 0.2083)
Bootstrap 95% CI = (0.0200, 0.2067)
Permutációs p-érték = 0.0095

Ha a tényleges fájlokból más értékek jönnek ki, az a véletlen mintavétel következménye; az elemzés logikája változatlan. A one_to_one join-ellenőrzés megakadályozza, hogy véletlenül egy ügyfelet többször számoljunk, ami az ITT-nevezőt hamisítaná.

40.2.4 Eredmény értelmezése

A fenti szemléltető számok alapján: a kezelt ágon a konverziós arány körülbelül 28,7%, a kontrollon 17,3%, az abszolút különbség 11,3 százalékpont. A relatív kockázat 1,651{,}65: a kezelés 65%-os relatív konverziónövekedéssel jár. A 95%-os intervallum mindkét közelítésben kizárja a nullát, tehát a hatás a véletlentől elkülöníthető. A p-érték kerekítve 0,010: ilyen vagy szélsőségesebb különbség az éles nulla mellett a permutációk körülbelül 1%-ában fordul elő.

Fontos, hogy a p-érték nem a nullhipotézis igazságának valószínűsége, és nem a hatás nagyságát méri. A hatás nagyságát a pontbecslés és az intervallum hordozza: a legvalószínűbb érték 11 százalékpont körül van, de a 95%-os bizonytalansági sáv nagyjából 2–21 százalékpont. Ha a döntési küszöb például 5 százalékpont, akkor a legkisebb érdemi hatást (MDE) a terv szerint 10 százalékpontra állítottuk; ez a minta az alsó határon mozog, a következtetést tehát óvatosan, a teljes intervallum együttes bemutatásával kell megfogalmazni.

A Wald- és a bootstrap-intervallum hasonló, mert a mintaméret elég nagy a binomiális normalitáshoz. A bootstrap akkor is használható, ha a normális közelítés kérdéses; itt a két módszer egyezése önmagában diagnosztikai jel, nem „több szignifikancia”.

Az érvényességi korlát: a szintetikus adatban nincs lemorzsolódás, nincs késleltetett címke, és az ügyfelek nem lépnek interakcióba. Valós éles környezetben a Késő címke, teljesítmény és újratanítás alfejezetben tárgyalt késő címke vagy visszacsatolási hurok az ITT-elemzést csak akkor nem torzítja, ha a kimenet a teljes ablakban megfigyelt. Itt a observed_until minden sorban azonos, ezért ez a feltétel ellenőrzött.

40.2.5 Feladatok

1. Értelmezés. A fenti szemléltető kimenet alapján írjon egy pontos mondatot a hatásról és bizonytalanságáról, amely nem állítja, hogy „a kezelés 95% valószínűséggel növeli a konverziót”, és nem kezeli a p-értéket a nullhipotézis valószínűségeként. Indokolja, miért hibás a „95%-os valószínűség” megfogalmazás.

2. Megvalósítás kézi kontrollal. A következő kis adaton ellenőrizze a permutációs tesztet úgy, hogy az összes lehetséges permutációt végignézi (exhaustive), ne Monte Carlo-mintát használjon. Kontroll: [0, 0, 1, 0, 1, 1, 1, 0, 0, 1], kezelt: [1, 0, 1, 1, 0, 1, 1, 1, 0, 1]. Számítsa ki τ̂\hat\tau-t, a Wald-SE-t és a pontos permutációs p-értéket. Hány lehetséges hozzárendelés van, ha a mintaelemszámok rögzítettek?

3. Hibadiagnózis. Egy kolléga a következő kóddal próbál bootstrap intervallumot számolni, de véletlenül az order_items táblát is bejoinolja, mielőtt a konverziót aggregálná:

df_bad = (assign.merge(outcome, on="customer_id")
                .merge(order_items, on="order_id", how="left"))
# ... majd df_bad-ból bootstrap replikákat húz soronként

Magyarázza el, miért torzítja ez a konverziós arányok bootstrap-eloszlását, és hogyan javítaná a kódot az elemzési egység megtartásával.

4. Megváltozott feltétel. Tegyük fel, hogy a kimenet 5%-a hiányzik, és a hiányzás a kezelt ágon gyakoribb, mert a kezelés mobilalkalmazás-értesítést küld, és néhány ügyfél törli az alkalmazást a 7 napos ablak előtt. Hogyan változtatná az elemzést? Nevezzen meg legalább két lehetséges, előre rögzíthető kezelési módot, és indokolja, miért nem elfogadható a hiányzó sorok egyszerű elhagyása ITT-elemzésben.

40.2.6 Megoldások és indoklás

1. megoldás. Helyes mondat: „A kezelt ágon a konverziós arány 11,3 százalékponttal magasabb (95% CI: 1,8–20,8 százalékpont); a permutációs teszt p = 0,010, tehát az éles nulla mellett a megfigyelt különbség a permutációs eloszlás szélső 1%-ában van.” A „95% valószínűséggel növeli” megfogalmazás azért hibás, mert a konfidenciaszint az eljárás ismételt mintavételi lefedettségére vonatkozik, nem az aktuális paraméterre vonatkozó szubjektív hitre. A paraméter rögzített; a véletlen az intervallum helyzetében van.

2. megoldás. A minták: kontroll nc=10n_c=10, összeg 55, tehát p̂c=0,5\hat p_c=0{,}5; kezelt nt=10n_t=10, összeg 77, tehát p̂t=0,7\hat p_t=0{,}7; τ̂=0,2\hat\tau=0{,}2. Wald-SE:

SE=0,5⋅0,510+0,7⋅0,310=0,025+0,021=0,046≈0,2145.SE = \sqrt{\frac{0{,}5 \cdot 0{,}5}{10} + \frac{0{,}7 \cdot 0{,}3}{10}} = \sqrt{0{,}025 + 0{,}021} = \sqrt{0{,}046} \approx 0{,}2145.

A lehetséges hozzárendelések száma, ha a karok mérete rögzített 1010 és 1010: (2010)=184756\binom{20}{10} = 184\,756. Az összes permutációt végigjárni még számítógép nélkül is sok, de Pythonnal generálható az összes kombináció:

from itertools import combinations
import numpy as np

y = np.array([0,0,1,0,1,1,1,0,0,1, 1,0,1,1,0,1,1,1,0,1])
n_total = len(y)
n_c = 10
obs_diff = y[10:].mean() - y[:10].mean()  # 0.2
all_diffs = []
for c_idx in combinations(range(n_total), n_c):
    c_mask = np.zeros(n_total, dtype=bool)
    c_mask[list(c_idx)] = True
    c = y[c_mask]
    t = y[~c_mask]
    all_diffs.append(t.mean() - c.mean())
all_diffs = np.array(all_diffs)
p_exact = (np.sum(np.abs(all_diffs) >= np.abs(obs_diff)) + 1) / (len(all_diffs) + 1)
print(f"Pontos permutációs p-érték: {p_exact:.4f}")

A pontos p-érték a fenti adaton 0,2570{,}257-hez közeli érték lesz, mert ilyen kis mintán a 0,20{,}2 különbség a nulla körüli permutációs eloszlás jelentős részében előfordul. Az ellenőrzés: a Monte Carlo-változat B=10000B=10\,000-rel hasonló nagyságrendet ad; az eltérés a Monte Carlo-hiba.

3. megoldás. Az order_items join után egy ügyfél annyi sorban jelenik meg, ahány rendelési tétele van. A konverzió bináris értékét minden sorban megismétli a join, így a soronkénti bootstrap az ügyfelek tételszám szerinti súlyozását vezeti be: egy több tételt vásárló ügyfél nagyobb eséllyel kerül a replikába. A bootstrap-eloszlás ezért az ilyen ügyfelek konverzióját felülreprezentálja, a szórást pedig torzítja. Javítás: előbb ügyfélszintű táblát készítsünk, a join előtt aggregáljunk, vagy a bootstrapet kizárólag az assignments + outcomes egy-egy relációjú dataframe-en futtassuk. A validate="one_to_one" már a merge-nél hibát dob, ha nem egyedi a kulcs.

4. megoldás. A hiányzó sorok egyszerű elhagyása sértheti a randomizáció által biztosított összehasonlíthatóságot: ha a hiányzás a kezeléstől függ, a megmaradó minta már nem éles nulla mellett sem cserélhető fel. Két előre rögzíthető lehetőség: (a) Worst-case imputáció: a hiányzó konverziót a kezelt ágon 0-nak, a kontroll ágon 1-nek kódoljuk, így a hatás alsó korlátját konzervatívan becsüljük; (b) Többszörös imputáció vagy stratifikált elemzés a hiányzási mechanizmus feltételezett okait (például app verzió, értesítési beállítás) bevonva. Az ITT-elv szerint a nevező továbbra is minden randomizált ügyfél; a kizárás csak akkor megengedett, ha a kizárási kritérium a randomizáció előtt mérhető és előre rögzített.

40.2.7 Gyakori tévedés ellenpéldával

Ugyanazt a mintát sok módszerrel megvizsgálni, majd a legkedvezőbb eredményt kiválasztani, exploratív szelekció. A Wald-, bootstrap- és permutációs eljárás nem független teszt, de ha például húsz különböző kiértékelési döntést próbálunk ki (más végpont, más ablak, más szűrés), és a legkisebb p-értéket jelentjük, a hamis pozitív esély összeadódik. Éles nulla mellett minden 5%-os szintű teszt önmagában 5% eséllyel téved; húsz független tesztnél annak valószínűsége, hogy legalább egy szignifikáns lesz, 1−0,9520≈0,641 - 0{,}95^{20} \approx 0{,}64.

Szemléltető szimuláció:

import numpy as np
from scipy import stats

rng = np.random.default_rng(42)
m = 20
reps = 1000
min_p = np.empty(reps)
for r in range(reps):
    pvals = np.empty(m)
    for j in range(m):
        x = rng.normal(0, 1, 50)
        y = rng.normal(0, 1, 50)
        pvals[j] = stats.ttest_ind(x, y).pvalue
    min_p[r] = pvals.min()
fp_rate = (min_p < 0.05).mean()
print(f"Húsz párhuzamos teszt után a legkisebb p < 0.05 aránya: {fp_rate:.2f}")

A várható kimenet körülbelül 0.64, nem 0.05. Ezért a Kísérleti kérdés és előzetes elemzési terv alfejezetben a primer végpontot, a tesztet és az elemzési egységet előre rögzítettük. Az itt elvégzett Wald- és bootstrap-intervallum ugyanazt a becslési célt ellenőrzi; a kettő együttes bemutatása diagnosztikai, nem többszörös tesztelés. Ha további elemzéseket (szegmens szerint, másodlagos végpont) is futtatunk, azokat külön, exploratív címkével kell közölni a Tudományos jelentés és reprodukálható bemutató alfejezetbeli jelentésben.

40.2.8 Rövid összefoglaló

Az abszolút konverziókülönbség, a hozzá tartozó standard error, bootstrap-intervallum és permutációs p-érték együtt ad korrekt kísérleti következtetést. Az elemzési egység az ügyfél, a resampling is ügyfélszintű; a Wald-közelítés a nagyobb, a permutációs teszt a kisebb mintán pontos. Az intervallum a hatás bizonytalanságát, a p-érték pedig az éles nulla alatti szélsőséget méri — nem a nullhipotézis igazságát. Az érvényességi feltételek (randomizáció, interferencia hiánya, teljes megfigyelés) kimondandók; hiányzó kimenetnél az ITT-elvet konzervatív vagy előre rögzített imputáció őrzi. A módszerek közötti válogatás adatvezérelten exploratív szelekció, és felfújja a hamis pozitív arányt. A következő Tudományos jelentés és reprodukálható bemutató alfejezetben a tudományos jelentés és reprodukálható bemutató foglalja egységbe ezt az elemzést.