A/B 테스트란 무엇인가?
A/B 테스트는 두 가지 버전(A와 B)을 비교하여 어느 것이 더 나은 성과를 내는지 통계적으로 검증하는 실험 방법입니다. 웹사이트 디자인, 마케팅 캠페인, 제품 기능 등 다양한 분야에서 활용되며, 데이터 기반 의사결정의 핵심 도구입니다.
A/B 테스트의 핵심은 ‘우연히 발생한 차이’와 ‘실제 효과로 인한 차이’를 구분하는 것입니다.
t-검정을 활용한 기본 분석
t-검정이란?
t-검정은 두 그룹의 평균이 통계적으로 유의미하게 다른지 검증하는 방법입니다. A/B 테스트에서 가장 널리 사용되는 기법으로, 구현이 간단하고 해석이 직관적입니다.
import numpy as np
from scipy import stats
# A그룹과 B그룹의 전환율 데이터
group_a = np.random.binomial(1, 0.10, 1000) # 전환율 10%
group_b = np.random.binomial(1, 0.12, 1000) # 전환율 12%
# 독립 표본 t-검정 수행
t_stat, p_value = stats.ttest_ind(group_a, group_b)
print(f"t-통계량: {t_stat:.4f}")
print(f"p-value: {p_value:.4f}")
if p_value < 0.05:
print("통계적으로 유의미한 차이가 있습니다.")
else:
print("통계적으로 유의미한 차이가 없습니다.")
t-검정의 가정과 한계
| 가정 | 설명 | 위반 시 대응 |
|---|---|---|
| 정규성 | 데이터가 정규분포를 따름 | 샘플 크기가 크면(n>30) 중심극한정리로 완화 |
| 등분산성 | 두 그룹의 분산이 유사 | Welch’s t-test 사용 |
| 독립성 | 관측값이 서로 독립적 | 실험 설계 단계에서 보장 필요 |
비율 검정: 전환율 비교의 정석
전환율이나 클릭률 같은 이진 데이터를 비교할 때는 비율 검정(proportion test)이 더 적합합니다.
from statsmodels.stats.proportion import proportions_ztest
# 각 그룹의 전환 수와 총 방문자 수
conversions = np.array([120, 145]) # A그룹 120명, B그룹 145명 전환
visitors = np.array([1000, 1000]) # 각 그룹 1000명씩
# z-검정 수행
z_stat, p_value = proportions_ztest(conversions, visitors)
conversion_rate_a = conversions[0] / visitors[0]
conversion_rate_b = conversions[1] / visitors[1]
print(f"A그룹 전환율: {conversion_rate_a:.2%}")
print(f"B그룹 전환율: {conversion_rate_b:.2%}")
print(f"p-value: {p_value:.4f}")
베이지안 추론: 확률적 관점에서의 접근
빈도주의 vs 베이지안 접근법
| 구분 | 빈도주의(t-검정) | 베이지안 |
|---|---|---|
| 질문 | “차이가 0이 아닐 확률은?” | “B가 A보다 나을 확률은?” |
| 결과 | p-value, 유의성 여부 | 사후 확률 분포 |
| 해석 | 간접적, 이진 판단 | 직관적, 연속적 신뢰도 |
| 사전지식 | 사용 안 함 | 사전 분포로 반영 가능 |
PyMC를 활용한 베이지안 A/B 테스트
import pymc as pm
import arviz as az
# 관측 데이터
visitors_a, conversions_a = 1000, 120
visitors_b, conversions_b = 1000, 145
with pm.Model() as model:
# 사전 분포: 전환율에 대한 믿음 (균등 분포)
p_a = pm.Beta('p_a', alpha=1, beta=1)
p_b = pm.Beta('p_b', alpha=1, beta=1)
# 우도: 관측 데이터
obs_a = pm.Binomial('obs_a', n=visitors_a, p=p_a, observed=conversions_a)
obs_b = pm.Binomial('obs_b', n=visitors_b, p=p_b, observed=conversions_b)
# 차이 계산
delta = pm.Deterministic('delta', p_b - p_a)
# MCMC 샘플링
trace = pm.sample(2000, return_inferencedata=True)
# B가 A보다 나을 확률
prob_b_better = (trace.posterior['delta'] > 0).values.mean()
print(f"B가 A보다 나을 확률: {prob_b_better:.2%}")
베이지안 접근법은 “B가 A보다 나을 확률이 95%”처럼 비즈니스 의사결정에 직접 활용 가능한 결과를 제공합니다.
실무 적용 시 체크리스트
1. 샘플 크기 계산
실험 전에 필요한 샘플 크기를 미리 계산하여 충분한 데이터를 수집해야 합니다.
from statsmodels.stats.power import zt_ind_solve_power
# 검출하고 싶은 최소 효과 크기 (전환율 차이)
effect_size = 0.02 # 2%p 차이
baseline_rate = 0.10
# 필요한 샘플 크기 계산
required_n = zt_ind_solve_power(
effect_size=effect_size,
alpha=0.05, # 유의수준
power=0.8, # 검정력
alternative='two-sided'
)
print(f"그룹당 필요한 샘플 크기: {int(required_n)}")
2. 다중 검정 문제
여러 메트릭을 동시에 검정하면 위양성 오류가 증가합니다. Bonferroni 보정 등으로 유의수준을 조정해야 합니다.
- 단일 메트릭: α = 0.05
- 5개 메트릭 동시 검정: α = 0.05 / 5 = 0.01
3. 조기 종료의 위험
실험 중간에 결과를 확인하고 조기 종료하면 통계적 오류가 발생할 수 있습니다. Sequential testing 기법을 활용하거나, 사전에 정한 샘플 크기까지 실험을 진행해야 합니다.
도구 비교: 어떤 방법을 선택할까?
| 상황 | 추천 방법 | 이유 |
|---|---|---|
| 빠른 의사결정 필요 | t-검정, 비율검정 | 계산 빠르고 해석 간단 |
| 샘플 크기가 작음 | 베이지안 | 사전 정보 활용 가능 |
| 확률적 해석 필요 | 베이지안 | “90% 확률로 개선” 같은 직관적 해석 |
| 전환율/클릭률 비교 | 비율검정 (z-test) | 이진 데이터에 최적화 |
| 연속형 지표 (평균 체류시간 등) | t-검정 | 정규 분포 가정에 적합 |
마무리
A/B 테스트의 핵심은 올바른 통계 기법 선택과 충분한 데이터 수집입니다.
- t-검정과 비율검정은 구현이 간단하고 빠르지만, 이진적 판단만 제공합니다.
- 베이지안 추론은 직관적인 확률 해석을 제공하며, 사전 지식을 활용할 수 있습니다.
- 실무에서는 샘플 크기 계산, 다중 검정 보정, 조기 종료 방지를 반드시 고려해야 합니다.
Python의 scipy, statsmodels, pymc 라이브러리를 활용하면 이 모든 분석을 효율적으로 수행할 수 있습니다. 데이터 기반 의사결정의 첫걸음, A/B 테스트를 지금 바로 시작해보세요!
이 글이 도움이 되셨나요? ☕
Buy me a coffee
답글 남기기