1 도입 — 회귀의 두 부트스트랩
회귀 모형 \(Y = \beta_0 + \beta_1 X + \varepsilon\) 에서 부트스트랩 적용은 두 가지 형태 가 있다.
- Cases Bootstrap — 자료점 \((X_i, Y_i)\) 쌍을 함께 복원 추출
- Residual Bootstrap — 잔차 \(\varepsilon_i\) 만 부트스트랩, \(X\) 고정
이 글은 두 형태의 차이, 적용 시점, 그리고 부트스트랩 사용 결정 트리를 다룬다.
2 Cases Bootstrap (자료점 부트스트랩)
원 자료 \(\{(X_i, Y_i)\}_{i=1}^n\) 에서 복원 추출 로 \(n\) 개 쌍 을 추출하여 새 자료 생성. 이 자료에 모형 적합 → 부트스트랩 계수.
def cases_bootstrap(X, Y, n_boot=5000):
n = len(Y)
boot_coefs = []
for _ in range(n_boot):
idx = np.random.choice(n, size=n, replace=True)
X_b, Y_b = X[idx], Y[idx]
# 회귀 적합 (예: OLS)
coefs = np.linalg.lstsq(np.column_stack([np.ones(n), X_b]), Y_b, rcond=None)[0]
boot_coefs.append(coefs)
return np.array(boot_coefs)2.1 가정
- 자료점이 독립 (i.i.d.)
- \(X\) 가 무작위 (random design)
2.2 장점
- 분포 가정 X
- 이분산성·비정규성 에 강건
- 가장 일반적
2.3 사용 시점
- \(X\) 가 무작위로 표집됨 (관찰 자료)
- A/B 테스트, 사용자 행동 자료
- 잔차 분포 가정 의심 시
2.4 표준 OLS SE 와의 비교
표준 OLS:
\[ \text{SE}(\hat{\beta}_1) = \sqrt{\frac{\hat{\sigma}^2}{\sum (X_i - \bar{X})^2}} \]
가정: 잔차가 정규 + 등분산. 위반 시 SE 부정확.
Cases bootstrap: 자료에서 직접 SE 추정. 가정 약함.
A/B 테스트 자료를 떠올려 본다. 사용자가 무작위로 표집 되어 (또는 트래픽으로 자연스럽게 들어와) 각 사용자의 \((X_i, Y_i)\) 가 관측됨. 즉:
- \(X_i\): 사용자 특성 (variant, age, segment 등)
- \(Y_i\): 사용자 outcome (매출, 클릭 등)
이 쌍 자체가 무작위 표본. Cases bootstrap 은 이 표본을 재생성 하므로 자연스럽게 자료의 변동성을 반영.
대조: 실험 설계에서 \(X\) 가 고정 된 경우 (예: 각 처리 수준에서 \(n_j\) 명 측정). 이때 \(X\) 분포가 고정 이라 cases bootstrap 이 약간 부적절. Residual bootstrap 이 더 적합.
A/B 테스트는 후자 구조 — variant 가 사전 결정 + 사용자 무작위 표집. 두 형태 모두 작동하지만 cases 가 더 자연스러움.
3 Residual Bootstrap (잔차 부트스트랩)
원 모형 \(\hat{Y}_i = \hat{\beta}_0 + \hat{\beta}_1 X_i\) 적합 후, 잔차 \(\hat{\varepsilon}_i = Y_i - \hat{Y}_i\) 를 부트스트랩.
def residual_bootstrap(X, Y, n_boot=5000):
n = len(Y)
# 원 모형 적합
coefs_orig = np.linalg.lstsq(np.column_stack([np.ones(n), X]), Y, rcond=None)[0]
Y_hat = coefs_orig[0] + coefs_orig[1] * X
residuals = Y - Y_hat
boot_coefs = []
for _ in range(n_boot):
# 잔차 부트스트랩
eps_b = np.random.choice(residuals, size=n, replace=True)
Y_b = Y_hat + eps_b
coefs = np.linalg.lstsq(np.column_stack([np.ones(n), X]), Y_b, rcond=None)[0]
boot_coefs.append(coefs)
return np.array(boot_coefs)3.1 가정
- 잔차가 동일 분포 (그러나 어떤 분포든)
- 잔차가 독립
- \(X\) 가 고정 (fixed design)
3.2 장점
- 정규성 가정 X
- 등분산성 약화
- 실험 설계에 자연스러움
3.3 사용 시점
- \(X\) 가 고정 (실험 설계)
- 잔차 분포 가정 의심
4 두 형태의 비교
| 측면 | Cases | Residual |
|---|---|---|
| 자료 구조 | \(X\) 무작위 | \(X\) 고정 |
| 가정 | 독립 자료점 | 동일 분포 잔차 |
| 이분산성 | 강건 | 부분 강건 |
| 일반성 | 높음 | 중간 |
| 권장 | 대부분의 경우 | 전통 실험 설계 |
A/B 테스트에서는 Cases 권장.
5 회귀 계수의 CI
부트스트랩 계수 \(\hat{\beta}^*_1\) 의 분포에서 직접 CI:
# 위 함수로 부트스트랩 후
boot_coefs = cases_bootstrap(X, Y, n_boot=5000)
beta1_boot = boot_coefs[:, 1]
# Percentile CI
ci_perc = np.percentile(beta1_boot, [2.5, 97.5])
# BCa CI (scipy 사용)
from scipy.stats import bootstrap
def get_beta1(idx_arr):
X_b = X[idx_arr]
Y_b = Y[idx_arr]
return np.linalg.lstsq(np.column_stack([np.ones(len(idx_arr)), X_b]), Y_b, rcond=None)[0][1]
# 더 간단히 — scipy 기본 활용
def slope(x_y):
x, y = x_y[:, 0], x_y[:, 1]
return np.cov(x, y)[0, 1] / np.var(x)
# bootstrap with paired
data = np.column_stack([X, Y])
res = bootstrap((data,), slope, n_resamples=5000, method='BCa', random_state=42)
print(f"β1 95 % CI: ({res.confidence_interval.low:.3f}, {res.confidence_interval.high:.3f})")6 예측의 CI vs 계수의 CI
회귀 부트스트랩에는 두 가지 다른 CI 가 있다.
Confidence Interval for \(\hat{Y}_{x_0}\) — 평균 예측 의 CI (모형의 기대값 에 대한 불확실성).
Prediction Interval for \(Y_{x_0}\) — 개별 예측 의 PI (모형 + 잔차 변동성 모두).
PI 가 항상 더 넓다.
6.1 Bootstrap CI 절차
6.2 Bootstrap PI 절차
# 개별 예측의 PI — 잔차 변동도 포함
predictions_pi = []
for _ in range(B):
idx = np.random.choice(n, size=n, replace=True)
X_b, Y_b = X[idx], Y[idx]
coefs = np.linalg.lstsq(np.column_stack([np.ones(n), X_b]), Y_b, rcond=None)[0]
y_pred_mean = coefs[0] + coefs[1] * x0
# 잔차에서 추출
Y_b_hat = coefs[0] + coefs[1] * X_b
residual_b = np.random.choice(Y_b - Y_b_hat, size=1)[0]
predictions_pi.append(y_pred_mean + residual_b)
pi = np.percentile(predictions_pi, [2.5, 97.5])A/B 테스트 사례:
- CI: “평균 매출이 +5 % 향상한다는 것의 불확실성. 95 % 확률로 +3 % ~ +7 %.”
- PI: “개별 사용자의 매출 변화의 분포. 95 % 사용자가 -10 % ~ +20 % 변화.”
CI 는 집단 효과 의 불확실성, PI 는 개별 효과 + 잔차 변동 의 불확실성. 비즈니스 의사결정 (전체 사용자 평균 매출 변화) 은 CI 가 적절. 개별 사용자 예측은 PI 가 적절.
7 회귀 진단의 부트스트랩
7.1 잔차의 부트스트랩
7.2 모형 안정성
# 부트스트랩 자료에서 변수 선택 빈도
import statsmodels.api as sm
selected_vars_count = {}
for _ in range(B):
idx = np.random.choice(n, size=n, replace=True)
X_b = X[idx]
Y_b = Y[idx]
# Forward selection 또는 LASSO
model = sm.OLS(Y_b, sm.add_constant(X_b)).fit()
significant = model.pvalues < 0.05
for j, sig in enumerate(significant[1:]): # const 제외
if sig:
selected_vars_count[j] = selected_vars_count.get(j, 0) + 1
# 변수가 부트스트랩에서 선택된 비율
for j, count in selected_vars_count.items():
print(f" Variable {j}: 선택 빈도 = {count/B:.2%}")선택 빈도가 높으면 변수의 실재성 강함. 빈도 50 % 미만이면 불안정.
8 시계열 부트스트랩
시계열 자료 (자기상관 존재) 에서 단순 부트스트랩 부적절. Block bootstrap 사용.
길이 \(\ell\) 의 연속 블록 단위로 부트스트랩.
def block_bootstrap(data, block_size, n_boot):
n = len(data)
n_blocks = (n + block_size - 1) // block_size
boot_samples = []
for _ in range(n_boot):
sample = []
for _ in range(n_blocks):
start = np.random.randint(0, n - block_size + 1)
sample.extend(data[start:start + block_size])
boot_samples.append(np.array(sample[:n]))
return boot_samples블록 크기 권장: \(\ell \approx n^{1/3}\).
A/B 테스트에 시간 효과 가 있는 경우 (요일·시간대 패턴) block bootstrap 권장.
9 클러스터 부트스트랩
클러스터 자료 (학교, 지점, 사용자) 에서 클러스터 단위 추출.
def cluster_bootstrap(data, cluster_id, n_boot):
clusters = np.unique(cluster_id)
boot_samples = []
for _ in range(n_boot):
boot_clusters = np.random.choice(clusters, size=len(clusters), replace=True)
boot_data = []
for c in boot_clusters:
boot_data.extend(data[cluster_id == c])
boot_samples.append(np.array(boot_data))
return boot_samplesA/B 테스트의 반복 노출 사용자 자료에 적합.
10 부트스트랩 사용 결정 트리
부트스트랩 사용 결정:
↓
표본 크기 적절 (n ≥ 30)?
No → 베이즈 또는 모수 가정
Yes → ↓
자료 의존성?
시계열 → Block bootstrap
클러스터 → Cluster bootstrap
독립 → 일반 bootstrap
↓
분석 형태?
평균/비율 → 단순 부트스트랩
회귀 → Cases bootstrap (X 무작위) 또는 Residual (X 고정)
분류 (AUC) → Plug-in + BCa
분위수 → Percentile bootstrap
↓
CI 형태?
탐색 → Percentile (빠름)
표준 → BCa (정확)
정밀 → Bootstrap-t
11 A/B 테스트의 회귀 응용
11.1 시나리오 — 매출 효과 + 공변량 통제
A/B 테스트에서 처리 효과 + 사용자 속성 통제 회귀:
\[ \text{Revenue}_i = \beta_0 + \beta_1 \cdot \text{Variant}_i + \beta_2 \cdot \text{Age}_i + \beta_3 \cdot \text{Tenure}_i + \varepsilon_i \]
\(\beta_1\) 이 처치 효과. Cases bootstrap 으로 robust CI:
import numpy as np
import pandas as pd
import statsmodels.api as sm
from scipy.stats import bootstrap
# 가상 자료
np.random.seed(42)
n = 5000
df = pd.DataFrame({
'variant': np.random.choice([0, 1], n),
'age': np.random.uniform(18, 70, n),
'tenure': np.random.uniform(0, 5, n),
})
df['revenue'] = (50 +
5 * df['variant'] + # 처치 효과
0.5 * df['age'] +
2 * df['tenure'] +
np.random.normal(0, 30, n))
# 표준 OLS
X = sm.add_constant(df[['variant', 'age', 'tenure']])
model = sm.OLS(df['revenue'], X).fit()
print("표준 OLS:")
print(model.summary().tables[1])
# Cases bootstrap
B = 5000
beta_var_boot = []
for _ in range(B):
idx = np.random.choice(n, size=n, replace=True)
df_b = df.iloc[idx]
X_b = sm.add_constant(df_b[['variant', 'age', 'tenure']])
m_b = sm.OLS(df_b['revenue'], X_b).fit()
beta_var_boot.append(m_b.params['variant'])
ci_var = np.percentile(beta_var_boot, [2.5, 97.5])
print(f"\nBootstrap β_variant 95 % CI: ({ci_var[0]:.2f}, {ci_var[1]:.2f})")표준 OLS 와 부트스트랩 CI 가 일관 되면 가정이 충족된 증거. 차이 크면 robustness 확인 필요.
11.2 Heteroscedastic 자료
이분산성 (분산이 \(X\) 에 따라 변함) 에서 표준 OLS SE 부정확. Cases bootstrap 자동 보정.
# Heteroscedastic 시뮬레이션
df['revenue_hetero'] = (50 + 5 * df['variant'] +
np.random.normal(0, 10 + 30 * df['variant'], n)) # variant 1 의 분산 큼
# OLS — SE 부정확
model_hetero = sm.OLS(df['revenue_hetero'], X).fit()
print(f"\n이분산 자료 OLS β_variant SE: {model_hetero.bse['variant']:.3f}")
# Bootstrap — SE 정확
beta_hetero_boot = []
for _ in range(B):
idx = np.random.choice(n, size=n, replace=True)
df_b = df.iloc[idx]
X_b = sm.add_constant(df_b[['variant', 'age', 'tenure']])
m_b = sm.OLS(df_b['revenue_hetero'], X_b).fit()
beta_hetero_boot.append(m_b.params['variant'])
print(f"Bootstrap β_variant SE: {np.std(beta_hetero_boot, ddof=1):.3f}")부트스트랩 SE 가 진정한 변동성 반영.
12 부트스트랩의 함정 정리
- 작은 표본 — \(n < 30\) 에서 부정확
- 의존성 무시 — 시계열·클러스터에서 단순 부트스트랩 부적절
- 편향 통계량 — 복잡한 통계량은 BCa 또는 jackknife 보정
- 계산 비용 — 큰 자료에서 분량 폭증, 병렬화 필수
- Plug-in 가정 혼동 — 부트스트랩이 모든 가정을 약화시키는 것은 아님
13 Buisson Ch.7 마무리
핵심 메시지:
“부트스트랩은 모든 자료 에서 robust 한 추론 을 가능케 한다. 적용해서 잃을 게 없다.”
13.1 권장 활용
- robustness check — 전통 검정 + 부트스트랩 둘 다 보고
- 비표준 통계량 — 중앙값, 분위수, AUC, Gini 의 CI
- 작은 표본 segment — 사용자 segment 분석
- 복잡 모형 — 비선형, 혼합 모형의 모수 CI
이 4 가지가 현대 A/B 테스트 분석의 표준 도구.
14 후속 — Computer-intensive Methods (Woodward)
다음 시리즈 (A-WOO14-) 는 Woodward 의 시각에서 부트스트랩 + 순열 + 결측 처리* 를 다룬다. 더 역학적 응용 + 결측 처리 (multiple imputation) 포함.
15 관련 주제
선행 지식
후속 주제 (Phase A)
- A-WOO14-* (Computer-intensive 자세히)
다른 카테고리 연결