OPEN HYPER STEP
← 목록으로 (math)
MATH · 44 / 45
math
CHAPTER 44 / 45
읽기 약 2
FUNCTION

A/B 테스트의 수학: p-value와 유의성


핵심 개념

귀무가설·p-value·유의수준·1·2종 오류·표본 크기 — 랜딩 페이지 A/B 테스트 설계.

본문

A/B 테스트 핵심 개념

📋 코드 (8줄)
H0 (귀무가설): A == B (효과 없음)
H1 (대립가설): A ≠ B (효과 있음)

p-value: H0이 참일 때, 관찰된 결과(또는 더 극단적)가 나올 확률
α (유의수준): 보통 0.05 — H0 기각 임계값

p < α → H0 기각, "통계적으로 유의"
p ≥ α → H0 유지, "유의하지 않음"

1종 오류 vs 2종 오류

📋 코드 (6줄)
                 H0 참            H0 거짓
H0 기각        1종 오류 (α)      정답 (Power = 1-β)
H0 유지         정답              2종 오류 (β)

α 작게 → 1종 오류 적음, but 2종 오류 증가
표본 크게 → α/β 동시 감소

Z-test for proportions (비율 비교)

PYTHON📋 코드 (31줄)
import numpy as np
from scipy import stats

# 변형 A: 1000명 중 50명 전환 (5%)
# 변형 B: 1000명 중 65명 전환 (6.5%)

n_a, x_a = 1000, 50
n_b, x_b = 1000, 65

p_a = x_a / n_a
p_b = x_b / n_b
p_pool = (x_a + x_b) / (n_a + n_b)


# Z-statistic
se = np.sqrt(p_pool * (1 - p_pool) * (1/n_a + 1/n_b))
z = (p_b - p_a) / se

# p-value (양측 검정)
p_value = 2 * (1 - stats.norm.cdf(np.abs(z)))

print(f"변형 A 전환: {p_a*100:.1f}%")
print(f"변형 B 전환: {p_b*100:.1f}%")
print(f"향상률 (lift): {(p_b - p_a) / p_a * 100:+.1f}%")
print(f"Z-score: {z:.3f}")
print(f"p-value: {p_value:.4f}")

if p_value < 0.05:
    print("✅ 통계적으로 유의 (p < 0.05) — H0 기각")
else:
    print("❌ 유의하지 않음 — 더 많은 데이터 필요")

표본 크기 계산

PYTHON📋 코드 (24줄)
# A 진짜 전환율 5%, B 진짜 전환율 6%일 때
# 1.2%p (즉 1%p) 차이를 95% 신뢰도로 감지하려면 N?

def sample_size_proportions(p1, p2, alpha=0.05, power=0.8):
    z_alpha = stats.norm.ppf(1 - alpha/2)  # 양측
    z_beta = stats.norm.ppf(power)

    p_avg = (p1 + p2) / 2
    diff = abs(p1 - p2)

    n = ((z_alpha * np.sqrt(2 * p_avg * (1 - p_avg))
          + z_beta * np.sqrt(p1*(1-p1) + p2*(1-p2))) / diff) ** 2
    return int(np.ceil(n))


# 5% vs 6% 감지
n = sample_size_proportions(0.05, 0.06)
print(f"필요 표본: {n}/변형")  # 약 9300


# 5% vs 5.5% (작은 차이) 감지
n = sample_size_proportions(0.05, 0.055)
print(f"필요 표본: {n}/변형")  # 약 37000
# → 작은 효과 감지하려면 표본이 폭발적으로 증가

실전 — A/B 테스트 시뮬레이션

PYTHON📋 코드 (40줄)
import numpy as np

np.random.seed(42)

def simulate_ab_test(true_p_a, true_p_b, n_per_variant, n_simulations=1000):
    """N번 시뮬레이션해서 H0 기각률 측정"""
    rejections = 0
    for _ in range(n_simulations):
        # 시뮬레이션
        clicks_a = np.random.binomial(n_per_variant, true_p_a)
        clicks_b = np.random.binomial(n_per_variant, true_p_b)

        # Z-test
        p_a = clicks_a / n_per_variant
        p_b = clicks_b / n_per_variant
        p_pool = (clicks_a + clicks_b) / (n_per_variant * 2)
        se = np.sqrt(p_pool * (1 - p_pool) * (2/n_per_variant))
        if se == 0:
            continue
        z = (p_b - p_a) / se
        p_value = 2 * (1 - stats.norm.cdf(np.abs(z)))

        if p_value < 0.05:
            rejections += 1

    return rejections / n_simulations


# 같은 분포 (H0 참) — 거짓 양성
false_positive = simulate_ab_test(0.05, 0.05, n_per_variant=1000)
print(f"실제 차이 없음: {false_positive*100:.1f}% 거짓 양성")  # 약 5% (α)


# 진짜 1%p 차이 — Power 측정
power = simulate_ab_test(0.05, 0.06, n_per_variant=1000)
print(f"진짜 1%p 차이: {power*100:.1f}% 검출")  # 표본 부족 시 낮음

# 표본 늘리면 Power 증가
power = simulate_ab_test(0.05, 0.06, n_per_variant=10000)
print(f"N=10000일 때: {power*100:.1f}% 검출")

흔한 함정 — Peeking Problem

PYTHON📋 코드 (40줄)
# ❌ 매일 결과 확인 + 유의하면 즉시 종료
# → 1종 오류율이 5% 이상으로 폭증

# ✅ 사전 정의된 표본 도달 시 1회만 검정


import numpy as np
from scipy import stats

np.random.seed(42)

# 같은 분포 — 본래 5%만 거짓 양성이어야 함
def peek_simulation(n_simulations=1000, max_n=2000, peek_every=100):
    """매 100명마다 검정 — 잘못된 방법"""
    rejections = 0
    for _ in range(n_simulations):
        rejected = False
        for n in range(peek_every, max_n + 1, peek_every):
            x_a = np.random.binomial(n, 0.05)
            x_b = np.random.binomial(n, 0.05)
            p_pool = (x_a + x_b) / (2 * n)
            se = np.sqrt(p_pool * (1 - p_pool) * 2/n)
            if se == 0:
                continue
            z = (x_b/n - x_a/n) / se
            p = 2 * (1 - stats.norm.cdf(np.abs(z)))
            if p < 0.05:
                rejected = True
                break
        if rejected:
            rejections += 1
    return rejections / n_simulations


false_positive = peek_simulation()
print(f"매번 확인 시 거짓 양성: {false_positive*100:.1f}%")
# 약 30% — 정상 5%의 6배

# → 사전 표본 크기 계산 + 그 시점에만 1회 검정
# 또는 Sequential testing (mSPRT, Always-Valid Inference)

다음 챕터

CH.45 "프로그래밍 수학 종합" — 6개 모듈 종합 + 다음 학습 경로.


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 A/B 테스트 설계를 검토해서
표본 크기 + 검정 방법 + 함정
방어를 가이드해줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

한국 SaaS 5개의 A/B 테스트
실전 사례 + 의사결정 패턴을 비교해줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 GA4 + 매출 데이터로 자동
A/B 테스트 분석 파이프라인을
구축하는 방법을 알려줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 그로스 팀에서
A/B 테스트 vs 베이지안 의사결정
트렌드를 솔직히 알려줘.

⭐ 이것만 기억하세요
A/B 테스트의 수학: p-value와 유의성 이 3가지만 확실히 잡으세요
1.p-value < 0.05면 H0 기각 — 단, 효과의 크기(향상률)는 별개
2.표본 크기는 효과 크기의 제곱에 반비례 — 작은 효과 감지하려면 표본 폭발
3.다음 챕터 CH.45에서 프로그래밍 수학 종합 — 6개 모듈과 다음 단계


공유하기
진행도 44 / 45