18.4 Kísérlet eredményének tudományos közlése

18.4.1 Cél és konkrét helyzet

A Northstar kísérlet lezárult: 300 ügyfél randomizálva a treatment és control karra, a primer kimenet a randomizálás után 7 nappal mért conversion_7d (0/1). A bemenet a lab/assignments.csv és a lab/outcomes.csv; a megfigyelési egység egy ügyfél, ezért az egyesítés kulcsa customer_id. A cél most nem új becslő építése, hanem a kísérlet tudományos közlése: egy rövid jelentés, amelyben a becsült hatás, a bizonytalanság, a design problémái és a döntési javaslat külön szakaszban szerepel.

Induló becslés: a szimuláció generáló hatása 10 százalékpont volt, de a 300 elemű minta ettől véletlenül eltérhet. A jelentésnek ezért nem a generáló értéket, hanem a mintából számolt becslést és annak intervallumát kell tárgyalnia. A döntési kérdés: érdemes-e a kezelést a teljes ügyfélkörre bevezetni?

18.4.2 Hatás és intervallum

A kísérleti hatást az átlagos kezelési hatás (average treatment effect, ATE) becslőjével adjuk meg. Legyen (Y_i \in {0, 1}) az (i)-edik ügyfél konverziója, (Z_i \in {0, 1}) a véletlen kezeléskiosztás (0 = kontroll, 1 = kezelés), (n_1) és (n_0) a két kar létszáma. A becslő

[ \hat{\tau} = \bar{y}_1 - \bar{y}_0, \qquad \bar{y}j = \frac{1}{n_j} \sum{i: Z_i = j} Y_i, ]

ahol (\bar{y}_j) dimenzió nélküli arány, értéke 0 és 1 közé esik, így (\hat{\tau}) tartománya ([-1, 1]). 100-zal szorozva a hatást százalékpontban kapjuk: ha (\hat{\tau} = 0{,}08), akkor a kezelés 8 százalékponttal növeli a becsült konverziót.

A standard hiba bináris kimenet esetén, független csoportokra:

[ \widehat{SE}(\hat{\tau}) = \sqrt{ \frac{\bar{y}_1 (1 - \bar{y}_1)}{n_1} + \frac{\bar{y}_0 (1 - \bar{y}_0)}{n_0} }. ]

A számlálóbeli (\bar{y}(1-\bar{y})) a csoporton belüli variancia becslése; a nevező az adott kar mintanagysága. A standard hiba ugyanabban az egységben van, mint (\hat{\tau}), tehát arány, illetve 100-zal szorozva százalékpont. A Nagy számok és centrális határeloszlás alfejezetben látott gondolat ismétlődik: az átlag ingadozása (\sigma/\sqrt{n}) nagyságrendű, itt csak mindkét kar varianciáját összeadjuk, mert a két mintaátlag különbségének varianciája a varianciák összege.

Közelítő 95%-os konfidenciaintervallum:

[ \left[ \hat{\tau} - z_{0{,}975} \widehat{SE}, ; \hat{\tau} + z_{0{,}975} \widehat{SE} \right], \qquad z_{0{,}975} \approx 1{,}96. ]

Az intervallum gyakorisági értelmezésű: ha az eljárást sok független kísérleten megismételnénk, az így számolt intervallumok körülbelül 95%-a fedné a valódi hatást. A konkrét intervallumra nem mondjuk, hogy „95% valószínűséggel tartalmazza a hatást”, mert a valódi hatás paraméter, nem véletlen változó ebben a keretben. A pontos értelmezéshez és a különbséghez lásd Standard error és konfidenciaintervallum és a Bayesi alternatívát Credible interval és posterior predictive check.

Kis mintán a fenti Wald-intervallum kiléphet a ([-1, 1]) tartományból. Kézi ellenőrzés: ha (n_0 = n_1 = 4), (\bar{y}_0 = 1/4), (\bar{y}_1 = 3/4), akkor

[ \hat{\tau} = 0{,}5, \quad \widehat{SE} = \sqrt{\frac{0{,}25 \cdot 0{,}75}{4} + \frac{0{,}75 \cdot 0{,}25}{4}} = \sqrt{0{,}09375} \approx 0{,}306, ]

tehát a 95%-os intervallum (0{,}500 \pm 1{,}96 \cdot 0{,}306 = [-0{,}100; 1{,}100]). A felső határ nagyobb 1-nél, ami mutatja, hogy ilyen kis minta esetén a normál közelítés nem megbízható. A labor jelentésében ezért a fő következtetést a 300 ügyfélre számolt intervallummal, a kis mintás alternatívát pedig ügyfélszintű bootstrap segítségével adjuk meg.

18.4.3 Külső érvényesség

A külső érvényesség (external validity) azt kérdezi: a kísérletben becsült hatás milyen populációra, időszakra és megvalósításra vihető át. A belső érvényesség a kísérleten belüli torzítatlanságot jelenti; a kettő független.

A Northstar esetben négy korlátot kell a jelentésben megnevezni:

  1. Populáció: a 300 szintetikus ügyfél adott segment és region eloszlást követ. Más összetételű ügyfélkörre a hatás nagysága változhat.
  2. Időszak: a kísérlet 2025. július 1. és 8. között zajlott. Más szezon, ünnepi időszak vagy kampány alatt a kezelés hatása eltérhet (lásd az időtípusok időzóna-kezelését Dátumok, időzónák és kategóriák alfejezetben).
  3. Megvalósítás: a treatment a szimuláció egyetlen működési formája. Más üzenet, új csatorna vagy rosszabb kivitelezés nem ugyanazt a hatást garantálja.
  4. Megfigyelési ablak: a kimenet fix 7 napos. A hosszabb távú hatás, a lemorzsolódás vagy a későbbi konverzió itt nem mérhető.

A statisztikai szignifikancia nem pótolja ezt a kérdést. Egy eredmény lehet belsőleg torzítatlan, szignifikáns, mégsem általánosítható a célpopulációra.

18.4.4 Feltáró és megerősítő elemzés

A megerősítő (confirmatory) elemzés az előre rögzített primer kérdés: a conversion_7d aránykülönbsége a két kar között. Ehhez tartozik az előre választott ITT-definíció (Randomizálás és kísérleti protokoll): a nevezőben mind a 300 randomizált ügyfél szerepel, függetlenül attól, hogy a kezelést megkapta-e vagy megnyitotta-e. Az erre számolt intervallumot használjuk döntési bemenetként.

A feltáró (exploratory) elemzés minden, ami utólag merül fel: a revenue_7d_minor összehasonlítása, szegmensenkénti bontás, időbeli görbék, alcsoport-eltérések. Ezek fontos hipotéziseket adhatnak a következő kísérlethez, de nem ugyanazzal a megerősítő erővel bírnak. A jelentésben ezért külön cím alatt, „Feltáró megfigyelések” néven szerepeljenek, a primer becsléstől vizuálisan is elválasztva.

A megkülönböztetés oka a többszörös próba és a szelektív közlés: ha sok utólagos metszetet nézünk, a véletlen kiugrások közül válogatunk. A primer elemzés előre rögzítése védi a p-érték értelmezhetőségét; a feltáró eredmény csak következő kísérleti tervet indokolhat.

18.4.5 Döntési veszteség

A döntési veszteség (decision loss) a becslést a döntési kontextushoz köti. A statisztikai kérdés „van-e hatás?”, a döntési kérdés „érdemes-e bevezetni?”. A kettő közötti híd a minimális gyakorlati hatás (minimum practical effect) és a tévedés költsége.

Legyen (\theta) a valódi hatás százalékpontban, és (\theta_{\min} = 3) százalékpont az a küszöb, amely alatt a bevezetés üzletileg nem éri meg. A döntési szabály egyszerű formája:

A harmadik eset a bizonytalanság explicit elismerése: a minta nem elég a döntéshez, nem „majdnem szignifikáns” eredmény. A veszteség itt kétféle lehet, és mindkettőt érdemes megnevezni: a téves bevezetés költsége (ha a valódi hatás negatív vagy (\theta_{\min}) alatti), és az elmaradt haszon költsége (ha a valódi hatás (\theta_{\min}) felett van, de elutasítjuk). A veszteség skálája pénzben vagy más üzleti célban fejezhető ki; a kísérleti adatban a revenue_7d_minor EUR-centben van, de a konverziós döntéshez itt nem adunk meg vállalati árazást, mert a labor szintetikus.

18.4.6 Teljes minimális példa

A következő kód a két laborfájlt egyesíti, kiszámolja a hatásbecslést, a normál közelítésű intervallumot és egy ügyfélszintű bootstrap intervallumot. A kódot ebben a generálásban nem futtattuk; a megjegyzett kimenet szemléltető, a tényleges számok a te futásodtól függenek. A kód Linux, macOS és Windows PowerShell alatt is futtatható, a munkakönyvtár a projektgyökér.

import numpy as np
import pandas as pd
from pathlib import Path

root = Path("lab")
assign = pd.read_csv(root / "assignments.csv")
out = pd.read_csv(root / "outcomes.csv")

df = (
    assign.merge(out, on="customer_id", validate="one_to_one")
    .sort_values("customer_id")
)

# Ellenőrző kapu: ITT-nevező és séma
assert df["customer_id"].is_unique
assert df.shape[0] == 300
assert df["conversion_7d"].isin([0, 1]).all()
assert set(df["variant"]) == {"control", "treatment"}

by = df.groupby("variant")["conversion_7d"]
means = by.mean()          # shape: (2,)
ns = by.size()             # shape: (2,)

diff = means["treatment"] - means["control"]
se = float(np.sqrt(
    (means["treatment"] * (1 - means["treatment"]) / ns["treatment"])
    + (means["control"] * (1 - means["control"]) / ns["control"])
))
z = 1.959963984540054      # normális 0.975 kvantilis
lo = diff - z * se
hi = diff + z * se

# Ügyfélszintű percentile bootstrap
rng = np.random.default_rng(20261020)
B = 2000
c = df.loc[df["variant"] == "control", "conversion_7d"].to_numpy()
t = df.loc[df["variant"] == "treatment", "conversion_7d"].to_numpy()
boot_diffs = np.empty(B)
for b in range(B):
    cb = rng.choice(c, size=c.size, replace=True)
    tb = rng.choice(t, size=t.size, replace=True)
    boot_diffs[b] = tb.mean() - cb.mean()

boot_lo, boot_hi = np.quantile(boot_diffs, [0.025, 0.975])

print(f"n_control={ns['control']}, n_treatment={ns['treatment']}")
print(f"mean_control={means['control']:.4f}, mean_treatment={means['treatment']:.4f}")
print(f"diff={diff:.4f}, SE={se:.4f}")
print(f"normal_CI=[{lo:.4f}, {hi:.4f}]")
print(f"bootstrap_CI=[{boot_lo:.4f}, {boot_hi:.4f}]")

# Döntési szabály
theta_min = 0.03
if lo > theta_min:
    decision = "bevezetés"
elif hi < 0:
    decision = "elutasítás"
else:
    decision = "további adat"

print(f"decision_with_theta_min={decision} (theta_min={theta_min})")

Egy lehetséges szemléltető futás kimenete:

n_control=150, n_treatment=150
mean_control=0.1867, mean_treatment=0.2867
diff=0.1000, SE=0.0472
normal_CI=[0.0074, 0.1926]
bootstrap_CI=[0.0067, 0.1933]
decision_with_theta_min=további adat (theta_min=0.03)

A pontos számok a véletlen generálás miatt eltérhetnek; a fenti kimenet csak a formátumot mutatja. A laborban a saját futást tüntesd fel a jelentésben.

18.4.7 Eredmény értelmezése

A kód előbb szerződés-kapuval ellenőrzi a bemenetet: a validate="one_to_one" garantálja, hogy egy ügyfélhez pontosan egy kimenet tartozik, a shape == (300, ...) pedig az ITT-nevezőt. A bootstrap az ügyfélszintű független mintavételi egységet tartja meg: a karokon belül újramintavételezünk egész ügyfeleket, nem sorokat, így az order_items nem sokszorozhatja a nevezőt.

Kézi kontroll a normál intervallumra: a fenti szemléltető adatokkal (\bar{y}_1 = 0{,}2867), (\bar{y}_0 = 0{,}1867), (n_1 = n_0 = 150), így

[ \widehat{SE} = \sqrt{\frac{0{,}2867 \cdot 0{,}7133}{150} + \frac{0{,}1867 \cdot 0{,}8133}{150}} \approx 0{,}0472, ]

és a (0{,}1000 \pm 1{,}96 \cdot 0{,}0472) intervallum ([0{,}0074; 0{,}1926]), egyezik a kimenettel. A bootstrap intervallum itt közel azonos, mert a mintanagyság elég nagy; kis mintán a Wald-intervallum kilépése ellen a bootstrap jobb védelmet ad.

Az értelmezésben három állítást különítsünk el:

  1. Becslés: a kezelés becsült hatása a mintában 10,0 százalékpont (ha ezt a szemléltető kimenetet kapod).
  2. Bizonytalanság: a 95%-os intervallum alsó határa 0,7 százalékpontnál kezdődik, tehát a hatás iránya pozitívnak tűnik, de a nagysága bizonytalan.
  3. Döntés: a 3 százalékpontos gyakorlati küszöb mellett a „további adat” döntés a helyes, mert az intervallum lefedi a küszöb alatti és feletti tartományt is. Ez nem azt jelenti, hogy a hatás nulla: a becslés pozitív, de a döntési kritérium szigorúbb a p < 0,05 feltételnél.

A revenue_7d_minor elemzése ugyanilyen szerkezettel, de feltáró cím alatt jelenik meg; a döntést nem arra alapozzuk.

Jelentési minimum: közölni kell a randomizált, megfigyelt és elemzett egységek számát karonként, a hiányzó végpontok kezelését, a becslési célt, a pontbecslést és bizonytalanságot; az előre rögzített és az utólagos elemzést egyértelműen különítsük el.

18.4.8 Feladatok

  1. Értelmezés. Tegyük fel, hogy a laborfutásod ezt adta: diff=0.084, normal_CI=[0.012, 0.156], (n_0 = n_1 = 150). Fogalmazd meg egy mondatban a becslést, egy mondatban a bizonytalanságot, és dönts a (\theta_{\min} = 0{,}03) küszöbbel. Indokold, miért nem elég azt mondani, hogy „szignifikáns, tehát bevezetjük”.

  2. Implementálás. Írj write_report(df, out_path) függvényt, amely a fenti számításokból a report.md fájlba négy szakaszt ír: ## Becslés, ## Bizonytalanság, ## Design és korlátok, ## Döntési javaslat. A design szakaszban három, a külső érvényességet érintő korlát is szerepeljen; a döntési szakasz a (\theta_{\min}) szabályt alkalmazza. A függvény visszatérési értéke a négy szakasz szövege.

  3. Hibadiagnózis. Egy kolléga jelentése ezt írja: „A kezelést megnyitó 102 ügyfél 37%-a konvertált, a kontroll 24%-a konvertált; a kezelés 13 százalékpontot javít.” Nevezd meg a protokollsértést, és add meg a helyes ITT-nevezőt és a helyes becslési elvet. Milyen torzítást okoz a megnyitásra szűrés?

  4. Megváltozott feltétel. Cseréld a primer kimenetet revenue_7d_minor-ra, és számold ki a két kar átlagkülönbségét, a standard hibát és a 95%-os intervallumot. A kapott intervallumot miért szabad csak feltáró eredményként közölni? Milyen további design-elemet kellene rögzíteni egy következő kísérletben ahhoz, hogy a bevételi cél megerősítő legyen?

18.4.9 Megoldások és indoklás

  1. A becslés: a kezelés 8,4 százalékponttal növeli a konverziót a mintában. A bizonytalanság: a 95%-os intervallum 1,2 és 15,6 százalékpont közé esik. A döntés (\theta_{\min} = 0{,}03) mellett „további adat”: az alsó határ 0,012, ami kisebb 0,03-nál, tehát nem zárható ki, hogy a hatás kisebb a gyakorlati küszöbnél. A p < 0,05 önmagában csak a nulla hatást zárja ki; nem állítja, hogy a hatás hasznos, és nem pótolja a külső érvényességet.

  2. Egy lehetséges váz:

def write_report(df, out_path):
    # ... ugyanaz a diff, se, lo, hi számítás ...
    theta_min = 0.03
    if lo > theta_min:
        decision = "bevezetés"
    elif hi < 0:
        decision = "elutasítás"
    else:
        decision = "további adat"

    text = (
        "## Becslés\n"
        f"A kezelés becsült hatása {diff:.3f} százalékpont.\n\n"
        "## Bizonytalanság\n"
        f"A 95%-os intervallum [{lo:.3f}, {hi:.3f}] százalékpont.\n\n"
        "## Design és korlátok\n"
        "- A minta szintetikus, adott szegmens- és régióeloszlással.\n"
        "- A megfigyelési ablak fix 7 napos.\n"
        "- A kezelés egyetlen megvalósítási formáját teszteltük.\n\n"
        "## Döntési javaslat\n"
        f"A {theta_min} százalékpontos minimális gyakorlati hatás mellett: {decision}.\n"
    )
    Path(out_path).write_text(text, encoding="utf-8")
    return text

Ellenőrző invariant: a fájl négy ## szakaszt tartalmaz, a döntési szakasz pontosan egyet a három lehetséges érték közül, és a becslési szakasz számértéke egyezik a korábban kiszámolt diff értékkel (10^{-3}) tűrésen belül.

  1. A kolléga megsértette az ITT-elvet (Randomizálás és kísérleti protokoll): a kezelési kar nevezőjét a kezelés megnyitására szűrte, ami a kezelés expozíciójának utólagos feltételét jelenti. A megnyitás maga is kimenet, ezért a szűrés kiválasztási torzítást okoz: a megnyitó ügyfelek eleve aktívabbak lehetnek, így a 13 százalékpontos különbség a kiválasztás és a kezelés keveréke. A helyes nevező mind a 150 randomizált ügyfél a kezelési karban, tehát a becslés a kezelési kar összes ügyfelének átlagos konverziója mínusz a kontroll összes ügyfelének átlagos konverziója. A megnyitási arány csak mint folyamatmutató (guardrail) elemezhető, nem mint a hatásbecslés nevezője.

  2. A bevételi elemzés:

rev = df.groupby("variant")["revenue_7d_minor"]
rev_means = rev.mean()
rev_vars = rev.var(ddof=1)
rev_diff = rev_means["treatment"] - rev_means["control"]
rev_se = float(np.sqrt(
    rev_vars["treatment"] / ns["treatment"]
    + rev_vars["control"] / ns["control"]
))

A pénzegység EUR-cent; az átlagok, a különbség és a standard hiba is centben van. Az intervallum ugyanazzal a normál kvantilissel számolható, de az eloszlás ferdesége miatt bootstrap ajánlott. Feltáró a bevétel, mert a primer elemzés csak a conversion_7d volt; a bevételt utólag választottuk, ezért a becsült intervallum nem hordozza a megerősítő kísérlet garanciáit. Egy következő kísérletben előre rögzíteni kell: a bevételi ablakot (napok, pénznem, visszatérítés kezelése), a primer elemzést (átlag vagy medián, nyertességi arány), a szükséges minimális hatást centben, és a többszörös tesztelésre vonatkozó szabályt, ha a konverziót is megtartjuk másodlagos kimenetként.

18.4.10 Gyakori tévedés, visszautalás és önellenőrzés

A leggyakoribb tévedés: a statisztikai szignifikancia azonosítása a hasznossággal vagy a külső érvényességgel. Ellenpélda: két kar, (n = 50,000) ügyfél, a becsült hatás 0,5 százalékpont, a standard hiba 0,2 százalékpont. A p-érték 0,012, tehát szignifikáns, de a hatás a 3 százalékpontos gyakorlati küszöb alatt van, és a teljes intervallum is a küszöb alatt marad. A döntési szabály helyesen „elutasítás” lehet, miközben a p-érték kicsi. A nagy minta itt sem javítja a külső érvényességet: ha a kísérlet csak egy régióban futott, az 50 000 fős eredmény sem vihető át automatikusan más régióra.

Visszautalás: a standard hiba itt a Nagy számok és centrális határeloszlás alfejezetben tanult mintavételi eloszlás kétmintás változata; a GLM: bináris és számlálási cél logisztikus modellje ugyanezt a bináris kimenetet link-skálán modellezné, de a döntési jelentéshez az abszolút aránykülönbség érthetőbb; a Randomizálás és kísérleti protokoll ITT-definíciója rögzíti a nevezőt; a Dátumok, időzónák és kategóriák időtípusai pedig a 7 napos ablak konzisztens kezelését biztosítják.

Önellenőrzés a leadás előtt: a jelentésemben külön szerepel-e a becslés, a bizonytalanság, a design és a döntés? Megadtam-e az intervallum szintjét és a mintanagyságot? Megneveztem-e legalább három külső érvényességi korlátot? A döntési javaslatban szerepel-e a gyakorlati küszöb, és különbözik-e a „szignifikáns” állítástól?

18.4.11 Rövid összefoglaló

A kísérleti jelentés négy, egymástól elkülönített részből áll. A becslés a mintából számolt aránykülönbség, például 10,0 százalékpont; a bizonytalanság a standard hibából és a 95%-os konfidenciaintervallumból áll, amelynek gyakorisági értelmezését pontosan meg kell tartani. A design szakasz a külső érvényesség korlátjait nevezi meg: populáció, időablak, megvalósítás és megfigyelési hossz. A döntési javaslat a minimális gyakorlati hatáshoz köti a becslést, ezért a „további adat” éppúgy érvényes eredmény, mint a bevezetés vagy az elutasítás. A következő alkalmazásban ezt a jelentést egy teljes kísérleti becslési és érzékenységi munkamenetté bővítjük a Becslés, intervallum és érzékenység záróprojekt-feladatában.