Calcolatore di significatività del test A/B
Verifica se il risultato del tuo test A/B è statisticamente significativo. Inserisci visitatori e conversioni per ottenere il p-value, lo z-score, l'intervallo di confidenza e l'incremento relativo.
Calcolatore di significatività del test A/B
Inserisci visitatori e conversioni per ogni variante per verificare se la differenza è reale o solo rumore.
Risultati
Statisticamente significativo
È improbabile che la differenza sia dovuta al caso al livello di confidenza scelto.
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.
Documentazione
Test A/B in un minuto
Hai modificato un pulsante, un titolo o un flusso di checkout. La versione A è la vecchia, la versione B è la nuova. B sembra migliore — ha convertito il 15% dei visitatori rispetto al 10% per A. Ma potrebbe essere solo fortuna, come lanciare una moneta dieci volte e ottenere sette teste?
Questo calcolatore risponde esattamente a questa domanda. Inserisci quante persone hanno visto ogni versione e quante hanno convertito, e ti dice la probabilità che la differenza misurata sia reale piuttosto che rumore casuale. Se quella probabilità è abbastanza alta, hai un vincitore. Se no, continui il test.
Il numero da guardare è il p-value: la probabilità di vedere una differenza almeno così grande se le due versioni fossero effettivamente identiche. Un piccolo p-value (ad esempio, sotto 0,05) significa "questo raramente accadrebbe per fortuna, quindi la differenza è probabilmente reale."
Come usarlo
- Visitatori — quante persone uniche hanno visto ogni versione.
- Conversioni — quante di loro hanno fatto quello che ti interessa (acquistato, iscritto, cliccato).
- Livello di confidenza — quanto vuoi essere sicuro prima di dichiarare un vincitore. Il 95% è lo standard dell'industria.
- Ipotesi — bidirezionale chiede "B è diverso da A?" (più sicuro, il default); unidirezionale chiede solo "B è migliore di A?" (più sensibile, ma devi decidere la direzione prima di eseguire il test).
Il risultato si aggiorna in tempo reale e gli input sono memorizzati nell'URL della pagina, quindi puoi aggiungere un segnalibro o condividere un risultato. Azzera cancella il modulo; Carica dati di esempio riempie un esempio elaborato.
Un esempio elaborato
| Visitatori | Conversioni | Tasso | |
|---|---|---|---|
| A (controllo) | 1.000 | 100 | 10,0% |
| B (variazione) | 1.000 | 150 | 15,0% |
Si tratta di un incremento assoluto di 5 punti percentuali e un incremento relativo di +50%. Il calcolatore restituisce un p-value di circa 0,0007 — sotto 0,05 — quindi con una confidenza del 95% il risultato è statisticamente significativo. Approssimativamente, se le due versioni fossero veramente identiche, vedresti una differenza così grande meno di una volta ogni mille test.
La matematica (test z a due proporzioni)
Dietro le quinte si tratta del test z a due proporzioni standard, lo stesso test insegnato nelle statistiche introduttive e utilizzato dai principali strumenti A/B.
-
Tasso di conversione di ogni gruppo:
dove è conversioni e è visitatori.
-
Tasso aggregato, supponendo (per l'ipotesi nulla) che entrambi i gruppi condividano un unico tasso vero:
-
Errore standard della differenza:
-
Lo z-score — quanti errori standard separano i due tassi:
-
Il p-value proviene dalla distribuzione normale standard . Bidirezionale: . Unidirezionale: .
-
Significativo quando , dove (quindi 0,05 al 95%).
Il calcolatore riporta anche un intervallo di confidenza per la differenza, calcolato con l'errore standard non aggregato : l'intervallo plausibile per il vero divario. Se tale intervallo esclude 0, il risultato è significativo.
Con una confidenza del 95%, uno z oltre ±1,96 (le code ombreggiate, il 5% dell'area) conta come significativo.
Leggere il risultato onestamente
- La significatività statistica non è significatività commerciale. Un incremento dello 0,1% può essere statisticamente reale ma non vale la pena di implementarlo.
- Non sbirciare e fermarsi presto. Controllare il p-value ogni giorno e fermarsi nel momento in cui scende sotto 0,05 gonfia il tasso di falsi positivi. Decidi la dimensione del campione in anticipo e lascia finire il test.
- Guarda la regola pratica della dimensione del campione. L'approssimazione normale è affidabile quando ogni gruppo ha almeno ~10 conversioni e ~10 non-conversioni. Con numeri piccolissimi, tratta il risultato solo come direzionale.
- Confidenza ≠ probabilità che B sia migliore. Un livello di confidenza del 95% significa che la procedura è sbagliata al massimo il 5% delle volte a lungo termine — è un'affermazione frequentista, non "95% di probabilità che B vinca."
- Un test, una metrica. Testare molte metriche o varianti contemporaneamente moltiplica la possibilità di un errore casuale; correggi (ad es. Bonferroni) o pre-registra la singola metrica che decide il test.
Calcolalo tu stesso
Ogni frammento calcola il p-value bidirezionale per l'esempio elaborato sopra.
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
3FAQ
Quale dimensione di campione mi serve? Abbastanza che un incremento significativo sia rilevabile. Come minimo, punta ad almeno poche centinaia di conversioni per variante; usa un calcolatore dedicato della dimensione del campione con il tuo tasso di base e il più piccolo incremento che vale la pena rilevare.
Bidirezionale o unidirezionale? Usa bidirezionale a meno che tu non abbia una ragione fissa e pre-impegnata per preoccuparti solo del miglioramento. Unidirezionale raddoppia la tua sensibilità ma vieta di reagire a B che è peggiore.
Perché il calcolatore mostra un intervallo di confidenza? Mostra l'intervallo plausibile della vera differenza, non solo un verdetto sì/no. Un intervallo ampio che comprende lo 0 significa "non ancora abbastanza dati."
È bayesiano? No — è un test z frequentista, il metodo più insegnato e utilizzato. Gli strumenti A/B bayesiani riportano "probabilità che B batte A" invece di un p-value; entrambi sono validi, rispondono a domande leggermente diverse.