Sjekk om resultatet av A/B-testen din er statistisk signifikant. Skriv inn besøkende og konversjoner for å få p-verdien, z-skåren, tillitsintervallet og relativ løft.
Du endret en knapp, en overskrift eller en kasseprosess. Versjon A er den gamle, versjon B er den nye. B ser bedre ut — den konverterte 15% av besøkende versus 10% for A. Men kan det gapet bare være flaks, på samme måte som ti myntkast kan gi syv kroner?
Denne kalkulatoren svarer nøyaktig på det. Du skriver inn hvor mange som så hver versjon og hvor mange som konverterte, og den forteller deg sannsynligheten for at forskjellen du målte er reell i stedet for tilfeldig støy. Hvis det sannsynligheten er høy nok, har du en vinner. Hvis ikke, fortsetter du testen.
Det ene tallet du må følge nøye er p-verdien: sannsynligheten for å se et gap minst like stort hvis de to versjonene faktisk var identiske. En liten p-verdi (si, under 0.05) betyr «dette ville sjelden skje ved flaks, så forskjellen er sannsynlig reell.»
Resultatet oppdateres live og inntastingene lagres i URL-en, så du kan bokmerke eller dele et resultat. Tilbakestill tømmer skjemaet; Last eksempeldata fyller inn et gjennomarbeidet eksempel.
| Besøkende | Konversjoner | Andel | |
|---|---|---|---|
| A (kontroll) | 1 000 | 100 | 10,0% |
| B (variant) | 1 000 | 150 | 15,0% |
Det er en absolutt løft på 5 prosentpoeng og en +50% relativ løft. Kalkulatoren returnerer en p-verdi på omtrent 0,0007 — under 0,05 — så ved 95% tillit er resultatet statistisk signifikant. Grovt sett, hvis de to versjonene var virkelig identiske, ville du se et gap så stort mindre enn en gang per tusen tester.
Under motoren er dette standard to-proporsjons z-test, samme test som undervises i introduksjonstatistikk og brukt av hovedstrøm A/B-verktøy.
Konversjonsrate for hver gruppe:
der er konversjoner og er besøkende.
Samlet rate, forutsatt (for nullhypotesen) at begge grupper deler en sann rate:
Standardfeil for forskjellen:
Z-skåren — hvor mange standardfeil fra hverandre de to ratene er:
P-verdien kommer fra standardnormalfordelingen . To-sidig: . En-sidig: .
Signifikant når , der (så 0,05 ved 95%).
Kalkulatoren rapporterer også et tillitsintervall for forskjellen, beregnet med den usamlede standardfeilen : det plausible området for det sanne gapet. Hvis det intervallet ekskluderer 0, er resultatet signifikant.
Ved 95% tillit, en z utover ±1,96 (de skyggelagte halene, 5% av området) regnes som signifikant.
Hvert utdrag beregner to-sidig p-verdien for eksemplet ovenfor.
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
3Hvilken utvalgsstørrelse trenger jeg? Nok til at en meningsfull løft ville være gjenkjennelig. Som minimum, sikter på minst noen få hundre konversjoner per variant; bruk en dedikert kalkulator for utvalgsstørrelse med din baseline-rate og den minste løften verdt å oppdage.
To-sidig eller en-sidig? Bruk to-sidig med mindre du har en solid, pre-forpliktet grunn til å bare bry deg om forbedring. En-sidig dobler sensitiviteten din men forbyr å reagere på B som verre.
Hvorfor viser kalkulatoren et tillitsintervall? Den viser det plausible området for den sanne forskjellen, ikke bare et ja/nei-dikt. Et bredt intervall som stradler 0 betyr «ikke nok data ennå.»
Er dette Bayesiansk? Nei — det er en frequentist z-test, den mest vidt underviste og brukte metoden. Bayesianske A/B-verktøy rapporterer «sannsynlighet B slår A» i stedet for en p-verdi; begge er gyldige, de svarer litt forskjellige spørsmål.
Oppdag flere verktøy som kan være nyttige for arbeidsflyten din