A/B 테스트를 언제 멈춰도 안전한 이유 — e-value와 e-process 실전 가이드
A/B 테스트를 운영하다 중간에 결과를 들여다본 적 있는가? 고전 통계학의 관점에서 그 순간, 1종 오류율(false positive 비율)이 더 이상 보장되지 않는다. 전통적인 가설 검정은 표본 크기를 미리 정하고 딱 한 번만 검정한다는 전제 위에 성립한다. 그러나 현실의 소프트웨어 시스템은 데이터가 실시간으로 흐르고, 의사결정은 언제라도 내려야 하며, 실험을 언제 끝낼지 사전에 알 수 없다.
이 글의 대상 독자는 p-value와 신뢰구간(confidence interval) 개념을 알고 있는 데이터 엔지니어 또는 백엔드 개발자다. p-value의 "한 번만 봐야 한다"는 제약이 실무에서 불편하게 느껴진 적 있다면, 이 글이 특히 유용할 것이다. 이 글을 읽고 나면, 실험 중간에 들여다봐도 통계적으로 안전한 A/B 테스트 파이프라인을 직접 구성할 수 있다.
e-value와 e-process는 바로 이 간극을 메우는 현대 순차 추론의 일반 이론으로, 이질적인 검정을 자유롭게 결합하면서도 어느 시점에 멈춰도 1종 오류를 보장한다. 개념의 수학적 토대부터 R·Python 실전 코드, 그리고 현장에서 흔히 빠지는 함정까지 순서대로 다룬다.
핵심 개념
e-value: "귀무가설에 베팅하면 얼마나 버나?"
e-value를 이해하는 가장 빠른 길은 베팅 비유다. 귀무가설($H_0$: 효과가 없다)이 거짓이라고 믿고 1달러를 걸었을 때, 실험 결과를 보고 나서 받게 되는 금액이 바로 $E$달러다. 이 게임이 "공정"하려면 — 즉, 귀무가설이 실제로 참일 때 기대 수익이 없어야 하려면 — e-value의 기댓값은 최대 1이어야 한다. 이것이 e-value의 수학적 정의다.
$$E \geq 0, \quad \mathbb{E}_{H_0}[E] \leq 1$$
베팅 해석(betting score): $E = 20$이라면 귀무가설에 반하는 강한 증거다. $E = 0.3$이라면 대립가설에 베팅했을 때 원금보다 손해를 봤다는 뜻으로, 귀무가설이 참이라는 증거가 아니라 대립가설의 증거가 약하다는 의미다.
p-value와의 가장 중요한 차이는 Markov 부등식을 통해 직접 1종 오류(유의수준 $\alpha$에서의 false positive 비율)를 통제한다는 점이다.
$$P_{H_0}(E \geq 1/\alpha) \leq \alpha$$
따라서 $E_t > 1/\alpha$가 되는 순간 유의수준 $\alpha$에서 귀무가설을 기각해도 된다. $\alpha = 0.05$라면 임계값은 20이다.
e-process: 시간 위에 흐르는 e-value
e-process는 e-value들의 순차 시퀀스 $(E_t)_{t \geq 0}$로, 임의의 정지 시점 $\tau$에서도 유효한 e-value가 된다.
$$\mathbb{E}_{H_0}[E_\tau] \leq 1 \quad \text{(모든 정지 시점 } \tau \text{에 대해)}$$
마팅게일 이론의 언어로 표현하면, 귀무가설 하 슈퍼마팅게일(supermartingale) — 즉, 기댓값이 감소하거나 유지되는 시계열 — 이다. 이 성질이 바로 "언제 멈춰도 안전하다"는 보장의 수학적 근거다.
순차 업데이트 규칙: 새로운 관측 $x_t$가 들어올 때마다 e-process는 다음과 같이 갱신된다.
$$E_t = E_{t-1} \cdot e_t$$
여기서 $e_t$는 $t$번째 관측에 대한 incremental e-value다. 이 곱 구조 덕분에 스트리밍 환경에서 전체 데이터를 다시 읽지 않고 온라인으로 업데이트할 수 있다.
이를 보장하는 것이 Ville의 부등식이다.
$$P!\left(\sup_{t \geq 0} E_t > \frac{1}{\alpha}\right) \leq \alpha$$
Ville의 부등식: e-process의 경로가 임계값 $1/\alpha$를 단 한 번이라도 돌파할 확률이 $\alpha$ 이하임을 보장하는 부등식. p-value 기반 연속 모니터링에서 발생하는 "다중 검정 오류(multiple testing inflation)" 문제를 구조적으로 해결한다.
이 두 가지 성질로부터 e-process는 다음을 동시에 보장한다.
- Optional stopping: 원하는 시점에 멈춰도 1종 오류 $\alpha$ 유지
- Optional continuation: 기각 못 했을 때 데이터를 더 모아 재검정 가능
mSPRT와의 관계: 특수 케이스에서 일반 이론으로
| 방법 | 핵심 가정 | 결합 가능성 | 정지 시점 자유도 |
|---|---|---|---|
| 고정 표본 t-검정 | 정규성, 고정 $n$ | 불가 | 없음 |
| SPRT | 단순 대립가설, 단일 모수 | 제한적 | 있음 |
| mSPRT | 복합 대립가설 + 특정 사전분포 | 동일 설계 내에서만 | 있음 |
| e-value / e-process | 없음 (분포 무관) | 이질적 검정 간 자유롭게 | 완전히 자유 |
mSPRT(mixture Sequential Probability Ratio Test)는 e-value의 특수 케이스다. 사전분포 $\pi$로 우도비를 적분한 mixture likelihood ratio가 e-value 조건을 만족하기 때문이다. Optimizely의 Stats Engine이 채택한 mSPRT는 이 패러다임의 선구적 사례지만, 단일 모수 가족과 특정 사전분포를 필요로 한다. e-value는 그보다 훨씬 넓은 설계 공간을 제공한다.
이질적 검정의 자유로운 결합: 곱셈 원리
e-value의 가장 강력한 성질은 독립적으로 생성된 e-value들의 곱이 유효한 e-value라는 점이다.
$$E_{\text{combined}} = E_1 \times E_2 \times \cdots \times E_k$$
여기서 "독립"이란 완전한 수학적 독립을 요구하는 것이 아니라, 각 e-value가 서로의 데이터를 공유하지 않고 독립적으로 생성된 경우를 의미한다. 이 조건이 만족될 때 다음과 같은 조합이 수학적으로 올바르다.
- 서로 다른 실험실에서 생성된 증거
- 다른 데이터 타입 (연속형 + 이진형)
- 다른 필트레이션(filtration)에서 생성된 e-process
import numpy as np
# 세 개의 독립 실험에서 얻은 e-value (각 사일로의 데이터 비공유)
e1 = 4.2 # RCT A
e2 = 3.1 # 관찰 연구 B
e3 = 2.8 # 분산 환경 사일로 C
# 결합 e-value — 유효한 e-value 보장
e_combined = e1 * e2 * e3
print(f"결합 e-value: {e_combined:.2f}") # 36.46
alpha = 0.05
threshold = 1 / alpha # 20.0
print(f"기각 여부 (α=0.05): {e_combined > threshold}") # True필트레이션(filtration): 시간에 따라 점차 확대되는 정보 집합의 수열. 서로 다른 측정 방식이나 데이터 소스가 각자의 필트레이션을 가질 때, e-process를 결합하려면 "adjust-then-combine" 프레임워크(adjuster 함수 클래스)가 필요하다(Choe 외, 2024).
핵심 삼각형
| 개념 | 역할 | 대응 고전 개념 |
|---|---|---|
| e-value | 단일 시점의 증거 척도 | p-value |
| e-process | 시간 전개되는 e-value 경로 (슈퍼마팅게일) | 검정 통계량 시계열 |
| 신뢰 시퀀스 | e-process로 구성된 anytime-valid 신뢰구간 | 신뢰구간 |
이제 개념을 실제 코드로 옮겨보자. e-value 설계에는 검정력(power) 비용이 따르지만, optional stopping과 이질적 결합이라는 이점이 이를 상쇄하는 시나리오가 많다. 실전 예시 세 가지로 각 상황을 확인한다.
실전 적용
R을 먼저 쓰는 이유: 현재 production-ready e-value 구현은 R
safestats패키지에만 존재한다. Python은 R로 다루기 어려운 시나리오(연합 학습, 스트리밍)에 사용한다.
예시 1: 온라인 A/B 테스트 연속 모니터링
전환율 개선 실험을 운영 중이다. 고전적 t-검정은 표본 크기를 미리 정해야 하지만, e-process 기반 접근에서는 매일 체크하다가 증거가 충분해지면 멈출 수 있다.
library(safestats)
# 설계 단계: 탐지하고 싶은 최소 효과 크기(deltaMin)와 유의수준 설정
# deltaMin은 반드시 실험 전 비즈니스 요구사항에서 결정해야 한다
design <- designSafeT(
deltaMin = 0.3, # 최소 의미 있는 효과 크기 (Cohen's d)
alpha = 0.05,
alternative = "greater",
testType = "twoSample"
)
# 데이터가 쌓일수록 e-value 업데이트 (반복 호출 가능)
set.seed(42)
control <- rnorm(150, mean = 0, sd = 1)
treatment <- rnorm(150, mean = 0.3, sd = 1)
result <- safeTTest(
x = treatment,
y = control,
designObj = design
)
print(result)
cat("e-value:", result$eValue, "\n")
cat("기각 여부:", result$eValue > 1/0.05, "\n")출력에서 eValue가 20을 넘으면 추가 데이터 수집 없이 즉시 결론을 내릴 수 있다. 20 미만이면 실험을 계속해도 된다 — p-value였다면 이 시점에 이미 "연속 모니터링 오류"가 발생했을 상황이다.
| 코드 구성 요소 | 역할 |
|---|---|
designSafeT() |
최소 효과 크기 기반 e-value 검정 설계 (실험 전 1회) |
safeTTest() |
축적된 데이터로 e-value 계산 (언제든 반복 호출 가능) |
result$eValue > 20 |
유의수준 0.05에서의 기각 조건 |
실험 진행 중 e-process 경로를 시각화하면 언제 증거가 충분해졌는지 직관적으로 확인할 수 있다.
import numpy as np
import matplotlib.pyplot as plt
# e-process 경로 시각화
# 업데이트 규칙: E_t = E_{t-1} * e_t (e_t: t번째 관측의 incremental e-value)
np.random.seed(42)
n = 200
data = np.random.normal(0.3, 1, n) # 처리 효과 δ=0.3 시뮬레이션
delta = 0.3 # 설계 단계에서 지정한 최소 탐지 효과
e, e_path = 1.0, []
for x in data:
e_t = np.exp(delta * x - delta**2 / 2) # Gaussian incremental e-value
e *= e_t
e_path.append(e)
fig, ax = plt.subplots(figsize=(10, 4))
ax.semilogy(e_path, color='steelblue', linewidth=1.5, label="e-value 경로")
ax.axhline(y=20, color='crimson', linestyle='--', linewidth=1.5,
label="기각 임계값 1/α = 20 (α=0.05)")
ax.set_xlabel("누적 관측 수")
ax.set_ylabel("e-value (로그 스케일)")
ax.set_title("A/B 테스트 연속 모니터링: e-process 경로")
ax.legend()
plt.tight_layout()
plt.savefig("e_process_ab_test.png", dpi=150)e-value가 로그 스케일로 우상향하다가 임계값 20을 돌파하는 시점이 "통계적으로 안전하게 실험을 종료할 수 있는 최초 시점"이다.
예시 2: 분산 학습 환경 — 데이터 공유 없는 증거 결합
연합 학습(federated learning) 또는 멀티 사일로 환경에서 각 노드가 원시 데이터를 공유하지 않고 e-value만 전송하여 중앙에서 결합한다.
from dataclasses import dataclass
from typing import List
@dataclass
class SiloResult:
silo_id: str
e_value: float
sample_size: int
def federated_e_combine(silo_results: List[SiloResult], alpha: float = 0.05) -> dict:
"""
각 사일로의 e-value를 곱산하여 결합 검정 수행.
데이터 공유 없이 1종 오류 보장 유지.
전제 조건: 각 사일로는 서로의 데이터를 공유하지 않고 독립적으로 e-value를 생성해야 한다.
"""
assert len(silo_results) > 0, "사일로 결과가 최소 1개 이상 있어야 합니다"
e_combined = 1.0
for silo in silo_results:
e_combined *= silo.e_value
threshold = 1.0 / alpha
return {
"e_combined": e_combined,
"threshold": threshold,
"reject_H0": e_combined > threshold,
"total_samples": sum(s.sample_size for s in silo_results),
}
# 세 개 병원 사일로에서 독립 계산된 e-value
hospital_results = [
SiloResult("병원-A", e_value=3.2, sample_size=80),
SiloResult("병원-B", e_value=2.7, sample_size=65),
SiloResult("병원-C", e_value=2.5, sample_size=90),
]
result = federated_e_combine(hospital_results, alpha=0.05)
print(f"결합 e-value: {result['e_combined']:.2f}") # 21.60
print(f"기각 여부: {result['reject_H0']}") # True
print(f"총 샘플 수: {result['total_samples']}") # 235결합 e-value 21.60이 임계값 20을 넘어 귀무가설을 기각한다. 개별 병원 단독으로는 기각 불가능했던 것이 — 원시 데이터 공유 없이 e-value 세 개의 곱만으로 — 가능해진 것이다.
예시 3: 스트리밍 이상 탐지
시계열 스트림에서 분포 변화(change point)를 탐지한다. e-process 경로가 임계값을 돌파하는 시점이 알람이다.
import numpy as np
def streaming_change_detection(stream: np.ndarray, alpha: float = 0.05) -> dict:
"""
SPRT 기반 e-process 이상 탐지.
Optional stopping: 임계값 돌파 시점이 감지 시간.
업데이트 규칙: E_t = E_{t-1} * exp(δ*x_t - δ²/2)
"""
threshold = 1.0 / alpha # 20.0
e = 1.0
e_path = [1.0]
alarm_time = None
# 기준 분포: N(0,1) 가정, 대립: 평균 shift δ=0.5
delta = 0.5
for t, x in enumerate(stream, start=1):
# incremental e-value: 가우시안 분포 가정
e_t = np.exp(delta * x - delta**2 / 2)
e = e * e_t
e_path.append(e)
if alarm_time is None and e > threshold:
alarm_time = t
return {
"alarm_time": alarm_time,
"final_e_value": e,
"e_path": e_path,
}
np.random.seed(0)
# 처음 200개: 정상 분포 N(0,1)
# 이후 100개: 이상 분포 N(0.5,1)
normal_stream = np.random.normal(0, 1, 200)
shift_stream = np.random.normal(0.5, 1, 100)
full_stream = np.concatenate([normal_stream, shift_stream])
result = streaming_change_detection(full_stream, alpha=0.05)
print(f"알람 발생 시점: t={result['alarm_time']}")
print(f"최종 e-value: {result['final_e_value']:.1f}")알람이 change point(t=200) 이후에 발생하면 정상적인 탐지다. 임계값 20에 도달하기까지의 지연 시간이 탐지 지연(detection delay)이며, delta 값을 크게 설정할수록 탐지는 빠르지만 정상 구간에서의 오탐률이 올라간다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| Optional stopping | 실험 중 어느 시점에 멈춰도 1종 오류 α 보장 |
| Optional continuation | 기각 못 했을 때 데이터 추가 수집 후 재검정 가능 |
| 이질적 검정 결합 | 다른 가정·필트레이션의 검정을 곱산으로 자유롭게 결합 |
| 사후 유의수준 조정 | 데이터를 본 후 α를 바꿔도 검정 유효성 유지 |
| 모델 무가정 옵션 | Universal Inference e-process는 정규성 등 강한 가정 불필요 |
| 직관적 해석 | "귀무가설 베팅으로 $E$배 수익" — 비통계 전공자에게도 설명 용이 |
| 다중 검정 통합 | FWER·FDR 제어 시 p-value보다 의존성 조건이 훨씬 약함 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 검정력 비용 | 동일 $n$에서 최적 p-value 검정보다 검정력 낮을 수 있음 | designSafeT()로 사전 설계; 효과가 클수록 격차 감소 |
| e-value 설계 복잡성 | 최적 e-value 유도에 대립가설 사전 지식 필요 | Universal Inference로 설계 부담 완화 |
| 소프트웨어 미성숙 | Python 표준 패키지 없음, R도 safestats 위주 |
R safestats 사용 또는 직접 구현 |
| 낮은 e-value 해석 | $E_t < 1$은 대립가설 증거 없음이지 귀무가설 수용이 아님 | $E_t$를 증거 강도 지표로만 보고, 귀무 수용은 별도 검정 설계 |
| 필트레이션 간 결합 복잡성 | 이질적 필트레이션 결합 시 adjuster 함수 구성이 까다로움 | Choe 외(2024) "adjust-then-combine" 프레임워크 참고 |
| 연구자 친숙도 부족 | 리뷰어·협업자 설득에 추가 커뮤니케이션 비용 | 방법론 섹션에 Ramdas & Wang(2025) 교과서 인용 |
Universal Inference: Wasserman 외(PNAS 2020)가 제안. 데이터를 반으로 나눠 한쪽으로 모수를 추정하고 나머지로 split-likelihood ratio를 계산함으로써, 정규성·지수족 가정 없이 어떤 가설에도 e-value를 생성한다.
실무에서 가장 흔한 실수
- 중간 데이터로 e-value 설계하기:
designSafeT()의deltaMin은 반드시 실험 전 비즈니스 요구사항에서 결정해야 한다. 파일럿 데이터를 보고deltaMin을 맞추면 순환 논리(data dredging)가 된다. - 동일 데이터로 e-value 중복 생성 후 곱산: 독립성이 깨져 결합 유효성이 사라진다. 사일로나 데이터 스플릿이 실제로 겹치지 않는지 먼저 확인하라.
- $E_t < 1$을 "귀무가설 증명"으로 해석: 낮은 e-value는 대립가설의 증거가 약하다는 뜻이지, 귀무가설이 참이라는 증명이 아니다. 동등성 검정이 필요하다면 별도의 e-value를 설계해야 한다.
마치며
e-value는 완벽한 대안이 아니다. 검정력 비용을 치러야 하고, Python 생태계는 아직 미성숙하며, 팀 내 설득에도 에너지가 필요하다. 그러나 A/B 테스트를 "언제 봐도 괜찮은" 파이프라인으로 바꾸고 싶다면, 지금 당장 기존 검정과 병렬로 e-value를 로깅하는 것만으로 시작할 수 있다. 전환 결정은 실제 검정력 차이를 직접 체감한 뒤로 미뤄도 충분하다.
지금 바로 시작할 수 있는 3단계:
- R
safestats패키지로 첫 번째 안전한 t-검정 실행:install.packages("safestats")→designSafeT(deltaMin = 0.5, alpha = 0.05)→safeTTest()로 현재 A/B 테스트 데이터를 재분석해 p-value와 e-value 결과를 나란히 비교한다. - Ramdas & Wang(2025) 교과서 1~3장 정독: 공식 arXiv 버전(arXiv:2410.23614)은 무료 공개다. e-value 정의, Ville 부등식, 신뢰 시퀀스까지 약 60페이지로 핵심 이론을 파악할 수 있다.
- 스트리밍 파이프라인에 e-process 모니터링 추가: 예시 3의
streaming_change_detection함수를 Kafka consumer 루프나 기존 스트림 처리 로직에 삽입하고, e-value를 기존 모니터링 지표와 병렬 로깅하여 임계값 20 돌파 시점을 추적한다.
다음 글: 신뢰 시퀀스(Confidence Sequences) 심화 — e-process로 구성하는 anytime-valid 신뢰구간과 실시간 효과 크기 추정
참고 자료
이론적 배경 (교과서/서베이)
- Hypothesis Testing with E-values | Ramdas & Wang, 2025 (arXiv:2410.23614)
- A tiny review on e-values and e-processes | Ruodu Wang, 2023
- Game-Theoretic Statistics and Safe Anytime-Valid Inference | Statistical Science, 2023
- Testing by Betting: A Strategy for Statistical Communication | Shafer, JRSS-A 2021
- E-values | Wikipedia
- The Stats Map — E-Process
R/Python 패키지 및 구현
- CRAN: safestats 패키지
- safestats vignette — Safe Flexible Hypothesis Tests
- ICML 2025 Tutorial: Game-theoretic Statistics and Sequential Anytime-Valid Inference
심화 논문 (주제별)
- Universal Inference — PNAS 2020 | Wasserman et al.
- Combining Evidence Across Filtrations | arXiv:2402.09698
- Regularized e-processes | arXiv:2410.01427
- E-values for Adaptive Clinical Trials | arXiv:2602.06379
- False Discovery Rate Control with E-values | JRSS-B, 2022
- The e-value | Nieuw Archief voor Wiskunde, 2024