컴퓨터공학 300 주제 시리즈의 016번째 글이다. 전체 지도는 여기.

한 줄 요약

추정은 표본에서 모집단의 값(평균, 비율)을 짐작하고 그 불확실성을 신뢰구간으로 표현하는 일이다. 가설 검정은 “차이가 없다” 는 가정 아래에서 지금 본 데이터가 얼마나 드문지(p-값)를 계산해, 관측된 차이가 우연인지 판단하는 절차다.

왜 필요한가

“새 버전 배포 후 p95 응답 시간이 210ms 에서 225ms 가 됐다. 성능이 나빠졌나?” 측정값은 매번 흔들린다. 15ms 차이가 진짜 회귀인지, 그냥 측정 잡음인지 구분하지 못하면 멀쩡한 배포를 롤백하거나 진짜 회귀를 놓친다.

A/B 테스트, 벤치마크 비교, 용량 추정, 장애율 추정이 모두 같은 질문이다. “표본 몇 개로 전체에 대해 무엇을, 얼마나 확신하며 말할 수 있는가?” 통계적 추정과 검정은 이 질문에 답하는 표준 언어다.

핵심 개념

모집단, 표본, 추정량

  • 모집단: 관심 대상 전체. 예: 이 서비스가 처리할 모든 요청의 응답 시간.
  • 모수: 모집단의 특성값. 예: 진짜 평균 μ. 보통 알 수 없다.
  • 표본: 실제로 측정한 일부. 예: 어제 측정한 요청 1,000 건.
  • 추정량: 표본으로 모수를 짐작하는 식. 예: 표본 평균 x̄.

표본 평균은 모집단 평균의 불편 추정량이다. 즉 E[x̄] = μ 다. 표본 분산은 n 이 아니라 n−1 로 나눠야 불편 추정량이 된다. 파이썬 statistics.variance 는 n−1, statistics.pvariance 는 n 으로 나눈다.

표준오차

표본 평균도 확률변수다. 표본을 다시 뽑으면 값이 달라진다. 그 흔들림의 크기가 표준오차다.

SE(x̄) = σ / √n      (σ 를 모르면 표본 표준편차 s 로 대신한다)

표본을 4 배 늘려야 표준오차가 절반이 된다. 측정을 조금 더 하는 것으로는 정밀도가 잘 안 오르는 이유다.

신뢰구간

중심극한정리(015번 글)에 따라 n 이 충분히 크면 x̄ 는 근사적으로 N(μ, σ²/n) 을 따른다. 그래서 μ 의 95% 신뢰구간은 근사적으로

x̄ ± 1.96 × s/√n

해석에 주의. “μ 가 이 구간에 있을 확률이 95%” 가 아니다. μ 는 고정된 값이고, 흔들리는 것은 구간이다. 정확한 뜻은 “이 절차로 구간을 만들기를 반복하면, 그중 약 95% 가 μ 를 포함한다” 다. NIST 핸드북도 신뢰구간을 이런 반복 절차의 성질로 설명한다(NIST/SEMATECH e-Handbook, What are confidence intervals?).

표본이 작으면 1.96 대신 t-분포의 값을 쓴다(t-구간). n 이 커지면 둘은 거의 같아진다.

가설 검정의 틀

  1. 귀무가설 H₀: 효과가 없다. 예: 배포 전후 평균 응답 시간이 같다.
  2. 대립가설 H₁: 효과가 있다. 예: 다르다(양측) 또는 늘었다(단측).
  3. 검정 통계량: 데이터가 H₀ 에서 얼마나 벗어났는지 재는 수. 예: (x̄₁ − x̄₂) / SE.
  4. p-값: H₀ 가 참이라고 가정할 때, 지금만큼 또는 더 극단적인 결과가 나올 확률.
  5. 판정: p-값이 미리 정한 유의수준 α(흔히 0.05)보다 작으면 H₀ 를 기각한다.

검정은 003번 글의 귀류법과 닮았다. “차이가 없다고 가정하면, 이런 데이터는 거의 나올 수 없다. 따라서 가정을 의심한다.” 다만 논리적 모순이 아니라 확률적으로 드물다는 것뿐이어서, 결론도 확률적으로 틀릴 수 있다.

두 종류의 오류

  H₀ 가 실제로 참 H₀ 가 실제로 거짓
H₀ 기각 1종 오류(위양성), 확률 α 올바른 탐지, 확률 1−β (검정력)
H₀ 유지 올바른 판단 2종 오류(위음성), 확률 β

α 를 낮추면 위양성은 줄지만 진짜 효과를 놓치기 쉬워진다. 둘을 함께 줄이는 방법은 표본을 늘리는 것뿐이다.

흔한 오해

  • p-값은 “H₀ 가 참일 확률” 이 아니다. H₀ 를 가정하고 계산한 데이터의 확률이다. 013번 글의 P(A ∣ B) 와 P(B ∣ A) 혼동과 같은 실수다.
  • 유의하다 ≠ 중요하다. 표본이 수백만 개면 0.1ms 차이도 유의하게 나온다. 효과 크기와 신뢰구간을 함께 보고 실무적으로 의미 있는 차이인지 판단한다.
  • 여러 번 검정하면 우연히 걸린다. 지표 20 개를 각각 α = 0.05 로 검정하면, 아무 효과가 없어도 적어도 하나가 유의하게 나올 확률이 1 − 0.95²⁰ ≈ 64% 다.
  • 유의하지 않다 ≠ 차이가 없다. 표본이 작으면 검정력이 낮아서 진짜 차이도 못 잡는다.

직접 해 보기

배포 전후 응답 시간을 흉내 낸 데이터로 신뢰구간을 구하고, 순열 검정(permutation test)으로 p-값을 계산한다. 순열 검정은 “두 그룹 이름표가 의미 없다면(H₀), 이름표를 무작위로 섞어도 차이가 비슷하게 나와야 한다” 는 생각을 그대로 코드로 옮긴 것이라 분포 가정이 필요 없다.

데이터는 일부러 “진짜로 6% 느려진 배포” 로 만들었다. 같은 효과를 표본 300 개와 3,000 개로 각각 검정해 본다.

import random, statistics, math
from statistics import NormalDist

random.seed(1)
Z975 = NormalDist().inv_cdf(0.975)

def sample(median, n):
    return [random.lognormvariate(math.log(median), 0.25) for _ in range(n)]

def ci95(xs):
    m, s, n = statistics.mean(xs), statistics.stdev(xs), len(xs)
    return round(m - Z975 * s / math.sqrt(n), 1), round(m + Z975 * s / math.sqrt(n), 1)

def mean(xs):
    return sum(xs) / len(xs)

def perm_test(a, b, R=2000):
    observed = mean(b) - mean(a)
    pooled, k, count = a + b, len(a), 0
    for _ in range(R):
        random.shuffle(pooled)
        if abs(mean(pooled[k:]) - mean(pooled[:k])) >= abs(observed):
            count += 1
    p = f"{count / R:.3f}" if count else f"< {1 / R}"
    return round(observed, 1), p

# 진짜로 6% 느려진 배포. 표본 크기만 바꿔 본다.
for n in (300, 3000):
    before, after = sample(200, n), sample(212, n)
    print(n, ci95(before), ci95(after), perm_test(before, after))

# 다중 검정: 효과 없는 지표 20 개를 각각 검정하면?
print(round(1 - 0.95**20, 3))

실행 결과다(난수 시드를 고정했으므로 같은 결과가 나온다. 순열 검정이라 몇 초 걸린다).

300 (200.4, 212.6) (207.7, 221.0) (7.9, '0.099')
3000 (204.1, 207.8) (217.1, 221.1) (13.2, '< 0.0005')
0.642

표본 300 개에서는 p-값이 약 0.1 이라 유의수준 5% 에서 귀무가설을 기각하지 못한다. 효과는 분명히 있는데도 그렇다. “유의하지 않다 ≠ 차이가 없다” 의 실제 예다. 신뢰구간도 크게 겹친다.

같은 효과를 표본 3,000 개로 보면 신뢰구간이 좁아져 겹치지 않고, 섞어서 만든 2,000 번의 차이 중 관측값만큼 큰 것이 하나도 없다. 검정력은 표본 크기로 산다. 마지막 줄은 효과 없는 지표 20 개를 검정할 때 적어도 하나가 우연히 유의할 확률 64% 다.

현업에서는

  • 벤치마크 비교. 성능 테스트는 여러 번 반복해서 분포를 비교한다. 한 번씩 돌려 숫자 두 개를 비교하는 것은 표본 크기 1 짜리 검정이다. 실행 순서와 워밍업 같은 체계적 차이도 통계로는 걸러지지 않으므로 실험 설계에서 막아야 한다.
  • 카나리 배포. 새 버전을 일부 트래픽에만 내보내고 기존 버전과 오류율·지연을 비교하는 카나리 분석은 본질적으로 두 표본 비교다. 트래픽이 적은 시간대에는 표본이 작아 차이를 못 잡을 수 있으니, 관찰 시간을 표본 크기로 생각해야 한다.
  • A/B 테스트에서 엿보기. 결과를 매일 들여다보다가 유의해지는 순간 멈추면 1종 오류율이 α 보다 훨씬 커진다. 표본 크기를 미리 정하거나, 순차 검정처럼 엿보기를 고려한 방법을 쓴다.
  • 기준 문서. NIST 의 공학 통계 핸드북은 가설 검정의 절차와 해석을 실무자 관점에서 정리해 두었다(NIST/SEMATECH e-Handbook, What are statistical tests?).

확인 문제

  1. 표본 100 개의 평균이 50, 표준편차가 10 이다. 모평균의 95% 신뢰구간은 대략?
  2. 표준오차를 1/3 로 줄이려면 표본을 몇 배로 늘려야 하는가?
  3. “p = 0.03 이므로 귀무가설이 참일 확률은 3% 다” 는 맞는 해석인가?
  4. 지표 10 개를 각각 α = 0.05 로 검정할 때, 모두 효과가 없어도 적어도 하나가 유의할 확률은?

풀이

  1. 50 ± 1.96 × 10/√100 = 50 ± 1.96, 즉 약 (48.0, 52.0).
  2. 9 배. 표준오차는 √n 에 반비례한다.
  3. 아니다. p-값은 귀무가설이 참이라고 가정했을 때 이만큼 극단적인 데이터가 나올 확률이다.
  4. 1 − 0.95¹⁰ ≈ 0.401. (검정들이 독립이라고 가정할 때)

더 읽을거리 (References)