1 도입 — 같은 부트스트랩, 다른 CI
부트스트랩 통계량 분포 \(\{\hat{\theta}^*_b\}\) 가 같아도, CI 구성 방법이 4 가지. 각 방법의 정확도와 사용 시점이 다르다.
A-BUI7-1 에서 4 유형을 짧게 소개했다. 이 글은 수학적 도출 과 역학 응용 을 자세히 다룬다.
2 Method 1 — Normal Bootstrap CI
2.1 정의
부트스트랩 표집 분포가 정규에 근사 한다고 가정. SE 만 부트스트랩으로 추정.
\[ \text{CI}_{1-\alpha} = \hat{\theta} \pm z_{1-\alpha/2} \cdot \widehat{\text{SE}}_{\text{boot}} \]
여기서 \(\widehat{\text{SE}}_{\text{boot}} = \text{SD}\{\hat{\theta}^*_b\}\).
2.2 가정
- 부트스트랩 분포가 정규
- 추정량의 비편향 (편향 무시)
2.3 한계
- 실제 부트스트랩 분포가 비대칭 이면 부정확
- 편향 무시
- 거의 사용되지 않음 (다른 방법이 더 나음)
3 Method 2 — Percentile Bootstrap CI
3.1 정의
부트스트랩 분포의 경험적 분위수 를 직접 사용.
\[ \text{CI}_{1-\alpha} = \left(\hat{\theta}^*_{(\alpha/2 \cdot B)}, \hat{\theta}^*_{(1 - \alpha/2 \cdot B)}\right) \]
즉 \(B\) 개 부트스트랩 통계량을 정렬 후, \(\alpha/2\) 와 \(1 - \alpha/2\) 위치의 값.
3.2 장점
- 단순, 직관적
- 분포 가정 X
- 비대칭 분포에 자연스러움
3.3 한계
- 편향이 있으면 부정확
- 비대칭 정도가 표본 크기에 의존 하면 부정확
3.4 Woodward 의 권장
“Percentile 은 큰 표본 에서 적절. 작은 표본에서는 BCa 권장.”
4 Method 3 — BC (Bias-Corrected) CI
4.1 동기
부트스트랩 분포의 중심 이 원 추정값과 다르면 (편향 존재), Percentile 부정확.
4.2 편향 측정
부트스트랩 분포에서 원 추정값보다 작은 비율:
\[ \hat{z}_0 = \Phi^{-1}\left(\frac{\#\{\hat{\theta}^*_b < \hat{\theta}\}}{B}\right) \]
\(\hat{z}_0 = 0\): 편향 없음 (Percentile 과 동일) \(\hat{z}_0 > 0\): 부트스트랩 분포가 원 추정의 왼쪽 으로 편향 (즉 부트스트랩 표본의 절반 이상이 원 추정값보다 작음) \(\hat{z}_0 < 0\): 부트스트랩 분포가 원 추정의 오른쪽 으로 편향
4.3 BC 분위수
조정된 분위수:
\[ \alpha_1 = \Phi(2\hat{z}_0 + z_{\alpha/2}) \] \[ \alpha_2 = \Phi(2\hat{z}_0 + z_{1-\alpha/2}) \]
CI:
\[ \text{CI}_{BC} = \left(\hat{\theta}^*_{(\alpha_1 \cdot B)}, \hat{\theta}^*_{(\alpha_2 \cdot B)}\right) \]
4.4 의미
편향 \(\hat{z}_0\) 가 0 이면 BC = Percentile. 편향이 있으면 분위수를 조정 해 보정.
부트스트랩 분포가 원 추정의 왼쪽으로 편향 (\(\hat{z}_0 > 0\)):
- Percentile 의 왼쪽 끝 (\(\alpha/2 = 2.5 \%\)) 은 너무 작은 값
- 보정으로 분위수를 오른쪽으로 이동 → CI 가 오른쪽으로 이동
이는 체계적 편향 을 보정. 추정량이 과소 추정 경향 이면 CI 도 그 경향 반영하지 않도록.
A/B 테스트 사례: 매출 lift 의 부트스트랩이 우편향 (긍정적 우연이 더 자주 발생). BC 가 이 편향을 인식하고 CI 조정.
5 Method 4 — BCa (Bias-Corrected accelerated)
5.1 동기
BC 가 편향을 보정하지만, 분포의 비대칭성 (표본 크기에 따른 변화) 도 고려해야 한다. 이를 보정한 것이 BCa.
5.2 가속도 모수
분포의 비대칭성 을 측정. Jackknife (Leave-one-out) 사용:
\[ \hat{a} = \frac{\sum_{i=1}^{n} (\bar{\theta}_{(\cdot)} - \hat{\theta}_{(i)})^3}{6 \left(\sum_{i=1}^{n} (\bar{\theta}_{(\cdot)} - \hat{\theta}_{(i)})^2\right)^{3/2}} \]
여기서:
- \(\hat{\theta}_{(i)}\): \(i\) 번째 자료를 제외 한 통계량
- \(\bar{\theta}_{(\cdot)} = \frac{1}{n} \sum \hat{\theta}_{(i)}\)
5.3 분포 비대칭성의 의미
\(\hat{a}\) 가 자료의 영향력 차이 를 측정. 이상치가 있으면 일부 \(\hat{\theta}_{(i)}\) 가 다른 값들과 매우 달라짐 → \(\hat{a}\) 큼.
5.4 BCa 분위수
\[ \alpha_1 = \Phi\left(\hat{z}_0 + \frac{\hat{z}_0 + z_{\alpha/2}}{1 - \hat{a}(\hat{z}_0 + z_{\alpha/2})}\right) \]
\[ \alpha_2 = \Phi\left(\hat{z}_0 + \frac{\hat{z}_0 + z_{1-\alpha/2}}{1 - \hat{a}(\hat{z}_0 + z_{1-\alpha/2})}\right) \]
CI:
\[ \text{CI}_{BCa} = \left(\hat{\theta}^*_{(\alpha_1 \cdot B)}, \hat{\theta}^*_{(\alpha_2 \cdot B)}\right) \]
5.5 한계 사례
- \(\hat{z}_0 = 0\), \(\hat{a} = 0\): BCa = Percentile
- \(\hat{z}_0 \neq 0\), \(\hat{a} = 0\): BCa = BC
- 일반: BCa 가 가장 정확
BCa 의 가속도 \(\hat{a}\) 는 Jackknife (1949 Quenouille) 에서 도출. Jackknife 는 부트스트랩 이전의 재추출 방법.
\(\hat{\theta}_{(i)}\) 는 한 명을 제외 한 자료의 통계량. 각 사람의 영향력 측정.
- 이상치가 있는 경우: 그 사람을 제외하면 통계량이 크게 변화 → \(\hat{a}\) 큼
- 동질적 자료: \(\hat{a}\) 작음
따라서 \(\hat{a}\) 가 자료의 영향력 분포 의 비대칭성을 정량화. BCa 가 이 비대칭을 CI 에 반영.
이 절차의 수학적 정당성 이 Efron 1987 의 Better Bootstrap Confidence Intervals 정리. 작은 표본에서 BCa 가 BC 보다 수렴이 빠름.
6 4 가지 방법의 비교
6.1 정확성 순서
일반적으로:
\[ \text{Normal} < \text{Percentile} < \text{BC} \leq \text{BCa} \]
6.2 사용 시점
| 상황 | 권장 방법 |
|---|---|
| 큰 표본, 정규 분포 | Percentile (단순) |
| 큰 표본, 비대칭 | BC 또는 BCa |
| 작은 표본 | BCa |
| 정밀 분석 (논문) | BCa |
| 빠른 탐색 | Percentile |
Woodward 의 권장: 대부분 BCa.
6.3 계산 비용
| 방법 | 추가 계산 |
|---|---|
| Normal | 0 (SE 만) |
| Percentile | 0 |
| BC | \(\hat{z}_0\) 계산 (단순) |
| BCa | \(\hat{z}_0 + \hat{a}\) (jackknife \(n\) 회) |
BCa 가 가장 비싸지만 현대 컴퓨팅에서 무시 가능.
7 4 방법의 시뮬레이션 비교
7.1 시뮬레이션 설정
대수정규 분포 (강한 우편향) 에서 \(n = 30\) 표본 추출. 표본 평균의 95 % CI 를 4 방법으로 구성. 1000 회 반복하여 coverage (CI 가 진짜 평균을 포함하는 비율) 측정.
7.2 결과 (가상)
| 방법 | Coverage (목표 95 %) | 평균 CI 폭 |
|---|---|---|
| Normal | 88 % | 1.20 |
| Percentile | 90 % | 1.18 |
| BC | 93 % | 1.25 |
| BCa | 94 % | 1.27 |
비대칭 자료에서 BCa 가 목표 coverage 에 가장 가깝.
Coverage 가 95 % 보다 작으면 CI 가 너무 좁음 → 진짜 모수를 포함 못함 → 신뢰도 부족.
Normal 과 Percentile 은 비대칭 자료에서 coverage 부족 → CI 가 부정확.
BC 와 BCa 가 보정으로 coverage 향상. 단 CI 폭도 약간 넓어짐 (정직한 표현).
이 trade-off 가 BCa 권장의 정량적 근거.
8 A/B 테스트 응용
8.1 사례 — Lift 분석
A/B 테스트의 매출 lift (= \(\hat{p}_T / \hat{p}_C - 1\)) CI 계산.
매출 자료 우편향 → Percentile 부정확. BCa 권장.
import numpy as np
from scipy.stats import bootstrap
np.random.seed(42)
n_per = 1000
control_revenue = np.random.lognormal(4, 1.0, n_per)
treatment_revenue = np.random.lognormal(4.05, 1.0, n_per)
def lift(c, t):
return t.mean() / c.mean() - 1
# 4 방법 비교 (수동 + scipy)
B = 5000
# Percentile
boot_lifts = []
for _ in range(B):
c_b = np.random.choice(control_revenue, n_per, replace=True)
t_b = np.random.choice(treatment_revenue, n_per, replace=True)
boot_lifts.append(lift(c_b, t_b))
ci_perc = np.percentile(boot_lifts, [2.5, 97.5])
# BCa (scipy)
def lift_paired(idx):
n_total = 2 * n_per
c_idx = idx[idx < n_per]
t_idx = idx[idx >= n_per] - n_per
if len(c_idx) == 0 or len(t_idx) == 0:
return 0
return lift(control_revenue[c_idx], treatment_revenue[t_idx])
# 더 단순 — scipy 의 bootstrap
def lift_func(combined):
c = combined[:n_per]
t = combined[n_per:]
return lift(c, t)
# 단순 percentile vs BCa 비교
print(f"관측 lift: {lift(control_revenue, treatment_revenue):.4f}")
print(f"\nPercentile 95 % CI: ({ci_perc[0]:.4f}, {ci_perc[1]:.4f})")
# BCa 계산 (자체 구현)
# 1) z0 (편향 보정)
obs_lift = lift(control_revenue, treatment_revenue)
prop_below = np.mean(np.array(boot_lifts) < obs_lift)
from scipy.stats import norm
z0 = norm.ppf(prop_below)
# 2) Jackknife (가속도)
jack_lifts = []
for i in range(n_per):
c_jack = np.delete(control_revenue, i)
jack_lifts.append(lift(c_jack, treatment_revenue))
for i in range(n_per):
t_jack = np.delete(treatment_revenue, i)
jack_lifts.append(lift(control_revenue, t_jack))
jack_mean = np.mean(jack_lifts)
diffs = jack_mean - np.array(jack_lifts)
a_hat = np.sum(diffs**3) / (6 * np.sum(diffs**2)**1.5)
# 3) BCa 분위수
z_alpha_low = norm.ppf(0.025)
z_alpha_high = norm.ppf(0.975)
alpha1 = norm.cdf(z0 + (z0 + z_alpha_low) / (1 - a_hat * (z0 + z_alpha_low)))
alpha2 = norm.cdf(z0 + (z0 + z_alpha_high) / (1 - a_hat * (z0 + z_alpha_high)))
ci_bca = np.percentile(boot_lifts, [alpha1*100, alpha2*100])
print(f"BCa 95 % CI: ({ci_bca[0]:.4f}, {ci_bca[1]:.4f})")
print(f"\n편향 보정 z0 = {z0:.4f}")
print(f"가속도 a = {a_hat:.4f}")이 코드가 BCa 계산의 모든 단계 를 보여준다. 실무에서는 scipy.stats.bootstrap(method='BCa') 를 사용해 자동 계산.
9 Software 도구
9.1 Python
scipy.stats.bootstrap(1.7+) — Percentile, BCa 자동arch.bootstrap— 시계열 변형bootstrapped— Spotify 의 패키지
9.2 R
boot::boot.ci()— 5 가지 방법 (norm, basic, perc, stud, bca)boot.ci(boot_obj, type=c("perc", "bca"))— 동시 비교
9.3 권장
대부분 scipy 또는 R boot 사용. 정확성과 안정성 검증.
10 Bootstrap CI 의 정확성 점검
10.1 Coverage 시뮬레이션
import numpy as np
from scipy.stats import bootstrap
np.random.seed(42)
n_simulations = 1000
n_sample = 30
true_mean = 5 # 진짜 모집단 평균
# 다양한 분포에서 Coverage 측정
def coverage_test(distribution_func, true_value, n_sim=1000):
coverage = {'percentile': 0, 'BCa': 0, 'normal': 0}
for _ in range(n_sim):
sample = distribution_func(n_sample)
# Percentile
boots = np.array([np.random.choice(sample, n_sample, replace=True).mean()
for _ in range(2000)])
ci_p = np.percentile(boots, [2.5, 97.5])
if ci_p[0] < true_value < ci_p[1]:
coverage['percentile'] += 1
# BCa
try:
res = bootstrap((sample,), np.mean, n_resamples=2000, method='BCa', random_state=0)
ci_b = (res.confidence_interval.low, res.confidence_interval.high)
if ci_b[0] < true_value < ci_b[1]:
coverage['BCa'] += 1
except:
pass
# Normal
se = boots.std(ddof=1)
ci_n = (sample.mean() - 1.96*se, sample.mean() + 1.96*se)
if ci_n[0] < true_value < ci_n[1]:
coverage['normal'] += 1
return {k: v/n_sim for k, v in coverage.items()}
# 정규 분포
print("정규 분포 (μ=5, σ=2):")
result = coverage_test(lambda n: np.random.normal(5, 2, n), 5, 200)
print(result)
# 대수정규 (우편향)
print("\n대수정규 (μ=ln(5)-0.5, σ=1):")
true_mean_lognormal = 5
result = coverage_test(lambda n: np.random.lognormal(np.log(5)-0.5, 1, n), 5, 200)
print(result)
# 지수 분포
print("\n지수 분포 (rate=0.2):")
result = coverage_test(lambda n: np.random.exponential(5, n), 5, 200)
print(result)이 시뮬레이션이 각 방법의 정확성 정량화. BCa 가 비대칭 자료에서 가장 robust.
11 Bootstrap-t 의 자세한 도출
11.1 절차
def studentized_bootstrap_ci(data, n_boot=5000, alpha=0.05):
"""Studentized bootstrap CI"""
n = len(data)
obs_mean = data.mean()
t_stars = []
for _ in range(n_boot):
sample = np.random.choice(data, n, replace=True)
if sample.std(ddof=1) > 0:
t = (sample.mean() - obs_mean) / (sample.std(ddof=1) / np.sqrt(n))
t_stars.append(t)
t_stars = np.array(t_stars)
t_low, t_high = np.percentile(t_stars, [2.5, 97.5])
obs_se = data.std(ddof=1) / np.sqrt(n)
return (obs_mean - t_high * obs_se, obs_mean - t_low * obs_se)
# 사례
data = np.random.lognormal(0, 1, 50)
ci = studentized_bootstrap_ci(data)
print(f"Studentized Bootstrap CI: ({ci[0]:.4f}, {ci[1]:.4f})")Studentized 부트스트랩이 2 차 정확. BCa 와 비슷하지만 SE 추정 필요.
12 ABC (Approximate Bootstrap Confidence)
분석적 근사 — 부트스트랩 시뮬레이션 대신 분석 공식.
장점: - 빠름 (시뮬레이션 X) - 분석적
단점: - 분포 가정 일부 사용 - 복잡한 통계량에 적용 어려움
13 Bootstrap CI 보고 형식
효과 점추정: 0.45 (단위)
95 % BCa CI: (0.32, 0.58)
Bootstrap 표본 수: B = 5000
방법: BCa (Bias-Corrected accelerated)
편향 보정 z₀: 0.12
가속도 a: 0.05
이 형식이 재현 가능성 + 정확성 정보.
14 R 패키지 비교
| 패키지 | 특징 |
|---|---|
boot |
표준, 5 가지 CI 방법 |
bootstrap |
Efron 의 원조 |
simpleboot |
단순 인터페이스 |
rsample |
tidyverse 통합 |
infer |
tidyverse + 검정 |
15 Python 패키지 비교
| 패키지 | 특징 |
|---|---|
scipy.stats.bootstrap |
표준 (1.7+) |
arch.bootstrap |
시계열 변형 |
bootstrapped |
Spotify, percentile + BCa |
joblib |
병렬화 |
16 한계와 후속
이 글까지 부트스트랩 CI 의 4 형태 를 다뤘다. 다음 글 A-WOO14-3 는 실무 이슈 (회귀, 분류, 시계열) 를 다룬다.
17 관련 주제
선행 지식
후속 주제 (Phase A)
- A-WOO14-3 실무 이슈
- A-WOO14-4 Bootstrap 가설 검정 + 한계
다른 카테고리 연결