A/B 테스트 유의성 계산기
A/B 테스트 유의성 계산기는 두 버전의 방문자 수와 전환 수를 입력받아 통계적 유의성을 검증한다. 양비율 z-검정을 사용해 p-값, z-점수, 신뢰 구간, 상대 상승률을 계산하며, 마케팅 실험이나 웹사이트 개선 테스트의 결과 해석에 쓰인다.
A/B 테스트 유의성 계산기
각 변형에 대한 방문자 및 전환을 입력하여 차이가 실제인지 단순한 노이즈인지 확인합니다.
결과
통계적으로 유의미함
차이는 선택한 신뢰도 수준에서 우연 때문일 가능성이 낮습니다.
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.
문서화
1분 안에 A/B 테스트 이해하기
버튼, 헤드라인, 또는 체크아웃 흐름을 변경했습니다. 버전 A는 이전 버전, 버전 B는 새로운 버전입니다. B는 보기에는 더 좋아 보이고 - 방문자의 15%가 전환된 반면 A는 10%였습니다. 그런데 이 차이가 단순한 운일 수도 있지 않을까요? 동전을 10번 던져서 앞면이 7번 나올 수 있는 것처럼요?
이 계산기가 정확히 그 질문에 답변합니다. 각 버전을 본 사람의 수와 전환된 사람의 수를 입력하면, 측정한 차이가 실제인지 아니면 무작위 오류인지 확률을 알려줍니다. 그 확률이 충분히 높으면, 승자가 있는 것입니다. 그렇지 않으면, 테스트를 계속 진행합니다.
주의해야 할 한 가지 숫자는 p-값입니다: 두 버전이 실제로 동일했다면 이 정도 크기의 차이를 볼 수 있는 확률입니다. 작은 p-값(예: 0.05 미만)은 "이런 일이 운으로 거의 일어나지 않으므로, 차이는 아마도 실제"라는 의미입니다.
사용 방법
- 방문자 — 각 버전을 본 고유 방문자의 수입니다.
- 전환 — 그들이 관심 있는 행동을 한 수(구매, 가입, 클릭)입니다.
- 신뢰도 수준 — 승자라고 부르기 전에 얼마나 확신하고 싶은지입니다. 95%가 업계 표준입니다.
- 가설 — 양측은 "B가 A와 다른가?"를 묻습니다(더 안전함, 기본값); 단측은 "B가 A보다 나은가?"만 묻습니다(더 민감하지만, 테스트를 실행하기 전에 방향을 결정해야 합니다).
결과는 실시간으로 업데이트되고 입력은 페이지 URL에 저장되므로, 결과를 북마크하거나 공유할 수 있습니다. 재설정은 양식을 지우고, 샘플 데이터 로드는 작업된 예를 채웁니다.
작업된 예
| 방문자 | 전환 | 비율 | |
|---|---|---|---|
| A (제어) | 1,000 | 100 | 10.0% |
| B (변형) | 1,000 | 150 | 15.0% |
이는 5 포인트 절대 상승이고 +50% 상대 상승입니다. 계산기는 약 0.0007의 p-값을 반환합니다 — 0.05 미만 — 따라서 95% 신뢰도에서 결과는 통계적으로 유의미합니다. 대략적으로, 두 버전이 정말로 동일했다면, 천 번의 테스트 중 한 번 미만으로 이 정도 크기의 차이를 볼 수 있을 것입니다.
수학 (양비율 z-검정)
뒷면에서 이는 표준 양비율 z-검정이고, 입문 통계에서 가르치는 동일한 검정이며 주류 A/B 도구에서 사용됩니다.
-
각 그룹의 전환율:
여기서 는 전환이고 은 방문자입니다.
-
합산된 비율, (귀무가설에 대해) 두 그룹이 하나의 참 비율을 공유한다고 가정:
-
차이의 표준 오류:
-
z-점수 — 두 비율이 얼마나 많은 표준 오류만큼 떨어져 있는지:
-
p-값은 표준 정규 분포 에서 나옵니다. 양측: . 단측: .
-
유의미함은 일 때, 여기서 (95%에서 0.05).
계산기는 또한 신뢰 구간을 차이에 대해 보고하고, 비합산된 표준 오류 로 계산됩니다: 참 차이에 대한 합리적인 범위입니다. 그 구간이 0을 제외하면, 결과는 유의미합니다.
95% 신뢰도에서 ±1.96 표준 오류를 초과하는 z (음영 처리된 꼬리, 면적의 5%)가 유의미한 것으로 계산됩니다.
결과를 정직하게 읽기
- 통계적 유의성은 비즈니스 유의성이 아닙니다. 0.1% 상승은 통계적으로 실제일 수 있지만 배포할 가치가 없을 수 있습니다.
- 초기에 살펴보고 멈추지 마십시오. p-값을 매일 확인하고 0.05 아래로 떨어지는 순간 테스트를 중지하면 거짓 양성률이 증가합니다. 표본 크기를 미리 결정하고 테스트가 완료되도록 하십시오.
- 표본 크기 경험칙을 주시하십시오. 정규 근사는 각 그룹에 최소 ~10 전환 그리고 ~10 비전환이 있을 때 신뢰할 수 있습니다. 작은 숫자로는 결과를 방향 전환만으로 취급합니다.
- 신뢰도 ≠ B가 나을 확률. 95% 신뢰도 수준은 절차가 장기적으로 최대 5% 잘못되었다는 의미입니다 — 이것은 "B가 이길 확률 95%"이 아니라 빈도주의 진술입니다.
- 한 번의 테스트, 한 가지 메트릭. 여러 메트릭이나 변형을 한 번에 테스트하면 우연의 기회가 곱해집니다. 이를 수정(예: Bonferroni)하거나 테스트를 결정하는 단일 메트릭을 사전 등록합니다.
직접 계산해 보세요
각 스니펫은 위의 작업된 예에 대해 양측 p-값을 계산합니다.
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
3자주하는 질문
표본 크기는 얼마나 필요합니까? 의미 있는 상승이 감지될 수 있을 정도로 충분합니다. 최소한, 변형당 최소 몇 백 개의 전환을 목표로 합니다. 기준 비율과 감지할 가치가 있는 가장 작은 상승으로 전용 표본 크기 계산기를 사용합니다.
양측 또는 단측? 개선만 신경써야 한다는 확실한 사전 약속된 이유가 있지 않는 한 양측을 사용합니다. 단측은 민감도를 두 배로 높이지만 B가 더 나쁜 경우에 대응하는 것을 금지합니다.
계산기가 신뢰 구간을 표시하는 이유는 무엇입니까? 예/아니오 판정만이 아니라 참 차이의 합리적인 범위를 보여줍니다. 0을 가로지르는 넓은 구간은 "아직 충분한 데이터가 없음"을 의미합니다.
이것은 베이지안입니까? 아니요 — 이는 가장 널리 가르쳐지고 사용되는 방법인 빈도주의 z-검정입니다. 베이지안 A/B 도구는 p-값 대신 "B가 A를 이길 확률"을 보고합니다. 둘 다 유효하고 약간 다른 질문에 답합니다.