A/B teszt szignifikancia kalkulátor
Ellenőrizze, hogy az A/B teszt eredménye statisztikailag szignifikáns-e. Adja meg a látogatókat és konverziókat, hogy megkapja a p-értéket, z-pontszámot, konfidencia intervallumot és relatív növekedést.
A/B teszt szignifikancia kalkulátor
Adja meg a látogatókat és konverziókat minden variánshoz, hogy ellenőrizze, a különbség valódi vagy csak zaj.
Eredmények
Statisztikailag szignifikáns
A különbség nem valószínű, hogy a véletlen miatt lenne a kiválasztott megbízhatósági szinten.
Chance this gap is just luck — lower is stronger.
How far apart the two rates are, in standard errors.
The likely range for the true difference.
Dokumentáció
A/B tesztelés egy perc alatt
Megváltoztattál egy gombot, egy főcímet vagy egy fizetési folyamatot. Az A verzió a régi, a B verzió az új. A B jobbnak tűnik — a látogatók 15%-a konvertálódott, az A-nak pedig 10%. De lehet, hogy ez a különbség csak szerencse, ahogy egy érme tízszeri feldobásakor kaphatunk hét fejjel?
Ez a kalkulátor pontosan ezt a kérdést válaszolja meg. Beírod, hogy hányan látták az egyes verziókat és hányan konvertálódtak, majd megmondja, hogy az általad mért különbség milyen valószínűséggel valódi és nem véletlen ingadozás. Ha ez a valószínűség elég nagy, akkor van nyertesed. Ha nem, folytatod a tesztet.
Az egyetlen szám, amit figyelemmel kell követned, a p-érték: annak az esélye, hogy ekkora vagy még nagyobb különbséget látsz, ha a két verzió valójában azonos lenne. Az alacsony p-érték (mondjuk 0,05 alatt) azt jelenti: „ez szerencsével nagyon ritkán fordulna elő, tehát a különbség valószínűleg valódi."
Hogyan kell használni
- Látogatók — hány egyedi személy látta az egyes verziókat.
- Konverziók — közülük hányan csinálták meg azt a dolgot, ami fontos (vásárlás, regisztráció, kattintás).
- Megbízhatósági szint — mennyire szeretnél biztos lenni a győztes megállapítása előtt. A 95% az iparági standard.
- Hipotézis — kétoldali azt kérdezi, hogy „a B különbözik-e az A-tól?" (biztonságosabb, alapértelmezett); egyoldali csak azt kérdezi, hogy „a B jobb-e, mint az A?" (érzékenyebb, de előre el kell döntened az irányt).
Az eredmény élőben frissül, és a bemenetek az oldal URL-jében tárolódnak, így könyvjelzőzés vagy megosztás után is visszakaphatod az eredményt. Az Alaphelyzetbe állítás töröl az alakzatot; a Mintaadatok betöltése egy kidolgozott példát tölt be.
Kidolgozott példa
| Látogatók | Konverziók | Arány | |
|---|---|---|---|
| A (kontroll) | 1 000 | 100 | 10,0% |
| B (variáns) | 1 000 | 150 | 15,0% |
Ez egy 5 százalékpontos abszolút növekedés és egy +50% relatív növekedés. A kalkulátor kb. 0,0007 p-értéket ad vissza — 0,05 alatt — tehát 95%-os megbízhatóságnál az eredmény statisztikailag szignifikáns. Nagyjából: ha a két verzió valóban azonos lenne, egy ilyen nagyságú különbséget kevesebb mint ezredik tesztenként látnál.
A matematika (kétarányos z-teszt)
A háttérben ez a standard kétarányos z-teszt, ugyanaz a teszt, amely az alapstatisztikában tanítják, és a szokásos A/B tesztelő eszközök használják.
-
Az egyes csoportok konverziós aránya:
ahol a konverziók, és a látogatók száma.
-
Összesített arány, feltételezve (a nullhipotézishez), hogy mindkét csoport egy igaz arányt oszt meg:
-
A különbség szabványos hibája:
-
A z-pontszám — hány standard hiba távolságra vannak egymástól a két arány:
-
A p-érték a standard normális eloszlásból származik. Kétoldali: . Egyoldali: .
-
Szignifikáns, amikor , ahol (szóval 0,05, 95%-os esetén).
A kalkulátor egy konfidencia intervallumot is megjelenít a különbséghez, az nem összesített szabványos hiba felhasználásával : a valódi rés hihető tartománya. Ha az intervallum kizárja a 0-t, az eredmény szignifikáns.
95%-os megbízhatóságnál a ±1.96-on túli z (az árnyékolt végek, a terület 5%-a) szignifikánsnak számít.
Az eredmény becsületes értelmezése
- A statisztikai szignifikancia nem üzleti szignifikancia. A 0,1%-os növekedés statisztikailag valódi lehet, de nem érdemes telepíteni.
- Ne jelezz korán és ne állj meg előbb. A p-érték napi ellenőrzése és azonnali leállítása, amint 0,05 alá csökken, megnöveli a hamis pozitív arányt. Döntsd el a minta méretét előre és hagyd befejezni a tesztet.
- Figyelj a minta méretének ökölszabályára. A normális közelítés megbízható, amikor mindkét csoportban legalább ~10 konverzió és ~10 nem-konverzió van. Kis számok esetén az eredményt csak iránymutatónak tekintsd.
- A megbízhatóság ≠ B jobb valószínűsége. A 95%-os megbízhatósági szint azt jelenti, hogy az eljárás a hosszú távon legfeljebb 5%-ban téved — ez egy gyakoriaszt kijelentés, nem „95% esélye, hogy B nyer."
- Egy teszt, egy metrika. Ha egyszerre több metrikát vagy variánst tesztelsz, megsokszorozod a szerencsés eset esélyét; korrigáld (pl. Bonferroni) vagy előre regisztráld az egyetlen metrikát, amely eldönti a tesztet.
Számold ki magad
Minden kódrészlet a fenti kidolgozott példa kétoldali p-értékét számítja ki.
1=2*(1-NORM.S.DIST(
2 (B2/A2 - B1/A1) /
3 SQRT(((B1+B2)/(A1+A2))*(1-(B1+B2)/(A1+A2))*(1/A1+1/A2)),
4 TRUE))
5' A1,B1 = control visitors, conversions ; A2,B2 = variation visitors, conversions
61from math import sqrt, erf
2
3def ab_pvalue(n1, x1, n2, x2, two_sided=True):
4 p1, p2 = x1 / n1, x2 / n2
5 p = (x1 + x2) / (n1 + n2)
6 se = sqrt(p * (1 - p) * (1 / n1 + 1 / n2))
7 z = (p2 - p1) / se
8 phi = lambda v: 0.5 * (1 + erf(v / sqrt(2))) # standard normal CDF
9 return 2 * (1 - phi(abs(z))) if two_sided else 1 - phi(z)
10
11print(ab_pvalue(1000, 100, 1000, 150)) # ~0.00072
121// erf via Abramowitz & Stegun 7.1.26
2function erf(x) {
3 const s = x < 0 ? -1 : 1;
4 x = Math.abs(x);
5 const t = 1 / (1 + 0.3275911 * x);
6 const y = 1 - ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t
7 - 0.284496736) * t + 0.254829592) * t * Math.exp(-x * x);
8 return s * y;
9}
10const phi = z => 0.5 * (1 + erf(z / Math.SQRT2));
11
12function abPValue(n1, x1, n2, x2, twoSided = true) {
13 const p1 = x1 / n1, p2 = x2 / n2, p = (x1 + x2) / (n1 + n2);
14 const se = Math.sqrt(p * (1 - p) * (1 / n1 + 1 / n2));
15 const z = (p2 - p1) / se;
16 return twoSided ? 2 * (1 - phi(Math.abs(z))) : 1 - phi(z);
17}
18console.log(abPValue(1000, 100, 1000, 150)); // ~0.00072
191public static double abPValue(int n1, int x1, int n2, int x2) {
2 double p1 = (double) x1 / n1, p2 = (double) x2 / n2;
3 double p = (double) (x1 + x2) / (n1 + n2);
4 double se = Math.sqrt(p * (1 - p) * (1.0 / n1 + 1.0 / n2));
5 double z = (p2 - p1) / se;
6 // Phi via the error function; erf approximated (A&S 7.1.26) separately.
7 double phi = 0.5 * (1 + erf(Math.abs(z) / Math.sqrt(2)));
8 return 2 * (1 - phi);
9}
101static double AbPValue(int n1, int x1, int n2, int x2) {
2 double p1 = (double)x1 / n1, p2 = (double)x2 / n2;
3 double p = (double)(x1 + x2) / (n1 + n2);
4 double se = Math.Sqrt(p * (1 - p) * (1.0 / n1 + 1.0 / n2));
5 double z = (p2 - p1) / se;
6 double phi = 0.5 * (1 + Erf(Math.Abs(z) / Math.Sqrt(2)));
7 return 2 * (1 - phi);
8}
91#include <cmath>
2
3double ab_pvalue(int n1, int x1, int n2, int x2) {
4 double p1 = (double)x1 / n1, p2 = (double)x2 / n2;
5 double p = (double)(x1 + x2) / (n1 + n2);
6 double se = std::sqrt(p * (1 - p) * (1.0 / n1 + 1.0 / n2));
7 double z = (p2 - p1) / se;
8 double phi = 0.5 * (1 + std::erf(std::fabs(z) / std::sqrt(2.0)));
9 return 2 * (1 - phi);
10}
111import "math"
2
3func abPValue(n1, x1, n2, x2 float64) float64 {
4 p1, p2 := x1/n1, x2/n2
5 p := (x1 + x2) / (n1 + n2)
6 se := math.Sqrt(p * (1 - p) * (1/n1 + 1/n2))
7 z := (p2 - p1) / se
8 phi := 0.5 * (1 + math.Erf(math.Abs(z)/math.Sqrt2))
9 return 2 * (1 - phi)
10}
111// erf from the `libm` crate; std has no erf.
2fn ab_pvalue(n1: f64, x1: f64, n2: f64, x2: f64) -> f64 {
3 let (p1, p2) = (x1 / n1, x2 / n2);
4 let p = (x1 + x2) / (n1 + n2);
5 let se = (p * (1.0 - p) * (1.0 / n1 + 1.0 / n2)).sqrt();
6 let z = (p2 - p1) / se;
7 let phi = 0.5 * (1.0 + libm::erf(z.abs() / 2f64.sqrt()));
8 2.0 * (1.0 - phi)
9}
101function ab_pvalue($n1, $x1, $n2, $x2) {
2 $p1 = $x1 / $n1; $p2 = $x2 / $n2;
3 $p = ($x1 + $x2) / ($n1 + $n2);
4 $se = sqrt($p * (1 - $p) * (1 / $n1 + 1 / $n2));
5 $z = ($p2 - $p1) / $se;
6 $phi = 0.5 * (1 + erf(abs($z) / sqrt(2)));
7 return 2 * (1 - $phi);
8}
91def ab_pvalue(n1, x1, n2, x2)
2 p1, p2 = x1.to_f / n1, x2.to_f / n2
3 p = (x1 + x2).to_f / (n1 + n2)
4 se = Math.sqrt(p * (1 - p) * (1.0 / n1 + 1.0 / n2))
5 z = (p2 - p1) / se
6 phi = 0.5 * (1 + Math.erf(z.abs / Math.sqrt(2)))
7 2 * (1 - phi)
8end
91# R has this built in: prop.test does the whole thing.
2prop.test(c(100, 150), c(1000, 1000), correct = FALSE)$p.value # ~0.00072
3GYIK
Mekkora minta méret szükséges? Elég nagy, hogy egy értelmes növekedés kimutatható lenne. Alapvonalként legalább pár száz konverziót célozz meg variánsként; egy dedikált minta méret kalkulátort használj az alapértékeddel és a legkisebb értelmes növekedéssel.
Kétoldali vagy egyoldali? Kétoldali, hacsak nem van erős, előre elkötelezett okod arra, hogy csak a javulást figyelembe vedd. Az egyoldali megkétszerezi az érzékenységet, de nem reagálhatsz arra, hogy B rosszabb.
Miért mutat a kalkulátor egy konfidencia intervallumot? A valódi különbség hihető tartományát mutatja, nem csak egy igen/nem ítéletet. A széles intervallum, amely a 0-t átlépi, azt jelenti: „még nem elég adat."
Ez Bayesian? Nem — ez egy frequentista z-teszt, a legszélesebben tanított és használt módszer. A Bayes-i A/B eszközök az „a B valószínűsége legyőzi az A-t" helyett egy p-értéket jeleznek; mindkettő érvényes, csak kicsit más kérdésekre válaszolnak.