Tae Hyun Kim (Lowell)

Design Effect

3분 읽기 #experiments#ab-testing#interference

Definition

**설계 효과(Design Effect, DEFF)**는 복잡한 표집 설계가 단순 무작위 표집에 비해 분산에 미치는 영향을 측정합니다.

클러스터 랜덤화에서: DEFF=1+(m1)×ICCDEFF = 1 + (m - 1) \times ICC

여기서:

  • mm: 클러스터당 평균 샘플 수
  • ICCICC: 클러스터 내 상관계수 (Intraclass Correlation Coefficient)

유효 샘플 사이즈: neff=nDEFFn_{eff} = \frac{n}{DEFF}

Intuitive Understanding

클러스터 랜덤화에서 같은 클러스터 내 관측치들은 서로 비슷합니다 (예: 같은 도시의 사람들).

만약 한 클러스터의 모든 사람이 정확히 같다면, 그 클러스터에서 100명을 관측해도 정보는 1명분입니다. ICC가 이 “유사성”을 측정하고, DEFF는 이로 인한 정보 손실을 정량화합니다.

Key Properties

ICC (Intraclass Correlation Coefficient)

ICC=σbetween2σbetween2+σwithin2ICC = \frac{\sigma^2_{between}}{\sigma^2_{between} + \sigma^2_{within}}

  • ICC=0ICC = 0: 클러스터 내 상관 없음 → DEFF = 1
  • ICC=1ICC = 1: 클러스터 내 완전 상관 → DEFF = m

DEFF의 영향

ICCm=10m=50m=100
0.011.091.491.99
0.051.453.455.95
0.101.905.9010.90

ICC가 0.05이고 클러스터당 100명이면, 유효 샘플이 약 1/6로 줄어듭니다.

왜 클러스터 랜덤화를 하는가?

가격 실험에서 **간섭(interference)**이 발생하면 개인 수준 랜덤화가 불가능:

  • 친구가 할인 받으면 나도 요구
  • 소셜 미디어로 가격 차이 공유
  • 재판매(arbitrage)

클러스터 랜덤화는 간섭을 줄이지만, 검정력을 희생합니다.

Example

샘플 사이즈 계산

import numpy as np

def sample_size_clustered(baseline_rate, mde_relative, icc, cluster_size,
                          alpha=0.05, power=0.80):
    """
    클러스터 랜덤화를 위한 샘플 사이즈 계산
    """
    from scipy import stats

    # 개인 수준 필요 샘플
    p1 = baseline_rate
    p2 = baseline_rate * (1 + mde_relative)

    z_alpha = stats.norm.ppf(1 - alpha/2)
    z_beta = stats.norm.ppf(power)

    n_individual = 2 * ((z_alpha + z_beta)**2 * p1 * (1-p1)) / (p2 - p1)**2

    # 설계 효과
    deff = 1 + (cluster_size - 1) * icc

    # 클러스터 수준 필요 샘플
    n_clustered = n_individual * deff

    # 필요 클러스터 수
    n_clusters = np.ceil(n_clustered / cluster_size)

    return {
        'n_individual': int(n_individual),
        'deff': deff,
        'n_clustered': int(n_clustered),
        'n_clusters_per_arm': int(n_clusters / 2),
        'total_sample': int(n_clusters * cluster_size)
    }

# 예: 도시 수준 클러스터, ICC=0.05, 도시당 1000명
result = sample_size_clustered(
    baseline_rate=0.05,
    mde_relative=0.10,
    icc=0.05,
    cluster_size=1000
)

print(f"개인 랜덤화 필요 샘플: {result['n_individual']:,}")
print(f"설계 효과: {result['deff']:.2f}")
print(f"클러스터 랜덤화 필요 샘플: {result['n_clustered']:,}")
print(f"필요 클러스터 수 (그룹당): {result['n_clusters_per_arm']}")

클러스터 랜덤화 구현

import hashlib

def cluster_randomize(cluster_id, experiment_name, treatment_prob=0.5):
    """클러스터 수준 무작위 할당"""
    hash_input = f"{cluster_id}_{experiment_name}"
    hash_value = int(hashlib.md5(hash_input.encode()).hexdigest(), 16)
    return 'treatment' if (hash_value % 100) / 100 < treatment_prob else 'control'

# 도시 수준 클러스터
cities = ['Seoul', 'Busan', 'Incheon', 'Daegu', 'Daejeon']
for city in cities:
    group = cluster_randomize(city, 'price_exp_2024')
    print(f"{city}: {group}")

ICC 추정

import statsmodels.formula.api as smf

def estimate_icc(data, outcome_col, cluster_col):
    """
    혼합 효과 모델로 ICC 추정
    """
    # 널 모델 (무작위 절편만)
    model = smf.mixedlm(
        f"{outcome_col} ~ 1",
        data,
        groups=data[cluster_col]
    )
    result = model.fit()

    # 분산 성분 추출
    var_between = result.cov_re.iloc[0, 0]  # 클러스터 간 분산
    var_within = result.scale              # 클러스터 내 분산

    icc = var_between / (var_between + var_within)

    return icc

# ICC 추정
icc = estimate_icc(data, 'purchase_amount', 'city')
print(f"추정 ICC: {icc:.4f}")

References

  • Kish, L. (1965). Survey Sampling.
  • Donner, A., & Klar, N. (2000). Design and Analysis of Cluster Randomization Trials.
  • Comprehensive Personalized Pricing Guide, Part V, §15.3

연결 그래프