CUPED
Definition
**CUPED (Controlled-experiment Using Pre-Experiment Data)**는 사전 실험 데이터를 활용하여 A/B 테스트의 분산을 줄이는 기법입니다.
여기서:
- : 실험 중 관측된 결과
- : 사전 실험 데이터 (예: 실험 전 2주간의 행동)
- : 조정 계수
Microsoft Research에서 Deng et al. (2013)이 제안했습니다.
Intuitive Understanding
고객마다 기본적인 구매 성향이 다릅니다. 어떤 고객은 원래 많이 구매하고, 어떤 고객은 적게 구매합니다.
CUPED는 “이 고객이 원래 얼마나 구매하는 편인지”를 활용하여 실험 결과의 노이즈를 줄입니다. 사전 행동으로 예측 가능한 변동을 제거하면, 처리 효과를 더 정확하게 추정할 수 있습니다.
Key Properties
분산 감소
- : 와 의 상관계수
- 상관이 높을수록 분산 감소 효과가 큼
불편성 유지
무작위 배정 하에서:
CUPED 조정 후에도 처리 효과의 불편 추정량입니다.
효율성 향상
분산이 줄면 더 적은 샘플로 같은 Statistical Power를 달성합니다:
예: 이면 유효 샘플이 33% 증가
Example
Python 구현
import numpy as np
from scipy import stats
class CUPEDEstimator:
def __init__(self, pre_period_days=14):
self.pre_period_days = pre_period_days
def fit(self, Y, X, treatment):
"""
Y: 실험 중 결과
X: 사전 실험 데이터 (공변량)
treatment: 처리 지시자 (0/1)
"""
# theta 계산 (전체 데이터)
self.theta = np.cov(Y, X)[0, 1] / np.var(X)
self.X_mean = np.mean(X)
# CUPED 조정된 결과
Y_cuped = Y - self.theta * (X - self.X_mean)
# 처리 효과 추정
Y_cuped_treatment = Y_cuped[treatment == 1]
Y_cuped_control = Y_cuped[treatment == 0]
self.effect = np.mean(Y_cuped_treatment) - np.mean(Y_cuped_control)
self.effect_se = np.sqrt(
np.var(Y_cuped_treatment) / len(Y_cuped_treatment) +
np.var(Y_cuped_control) / len(Y_cuped_control)
)
# 비교: 조정 전
self.effect_raw = np.mean(Y[treatment == 1]) - np.mean(Y[treatment == 0])
self.effect_raw_se = np.sqrt(
np.var(Y[treatment == 1]) / sum(treatment == 1) +
np.var(Y[treatment == 0]) / sum(treatment == 0)
)
# 분산 감소율
self.variance_reduction = 1 - (self.effect_se / self.effect_raw_se)**2
return self
def summary(self):
return {
'effect_cuped': self.effect,
'se_cuped': self.effect_se,
'effect_raw': self.effect_raw,
'se_raw': self.effect_raw_se,
'variance_reduction': self.variance_reduction,
'theta': self.theta
}
사용 예시
# 시뮬레이션 데이터
np.random.seed(42)
n = 10000
# 개인별 기본 성향 (미관측)
baseline = np.random.randn(n) * 10 + 50
# 사전 실험 데이터 (실험 전 2주 매출)
X_pre = baseline + np.random.randn(n) * 5
# 처리 배정
treatment = np.random.binomial(1, 0.5, n)
# 실험 중 결과 (처리 효과 = 2)
true_effect = 2
Y = baseline + true_effect * treatment + np.random.randn(n) * 5
# CUPED 적용
cuped = CUPEDEstimator()
cuped.fit(Y, X_pre, treatment)
results = cuped.summary()
print(f"진짜 효과: {true_effect}")
print(f"원시 추정치: {results['effect_raw']:.3f} ± {results['se_raw']:.3f}")
print(f"CUPED 추정치: {results['effect_cuped']:.3f} ± {results['se_cuped']:.3f}")
print(f"분산 감소: {results['variance_reduction']:.1%}")
다중 공변량 확장
from sklearn.linear_model import LinearRegression
def cuped_multiple_covariates(Y, X_covariates, treatment):
"""
여러 사전 실험 변수를 활용한 CUPED
"""
# 선형 모델로 theta 추정
model = LinearRegression()
model.fit(X_covariates, Y)
# 예측된 값 빼기
Y_pred = model.predict(X_covariates)
Y_cuped = Y - Y_pred + np.mean(Y_pred)
# 처리 효과
effect = np.mean(Y_cuped[treatment == 1]) - np.mean(Y_cuped[treatment == 0])
return effect, Y_cuped
Related Concepts
- Statistical Power - CUPED가 향상시키는 대상
- A-B Testing - CUPED가 적용되는 맥락
- Design Effect - 또 다른 유효 샘플 조정
References
- Deng, A., Xu, Y., Kohavi, R., & Walker, T. (2013). “Improving the Sensitivity of Online Controlled Experiments by Utilizing Pre-Experiment Data.”
- Comprehensive Personalized Pricing Guide, Part V, §14.3