1 도입 — 부트스트랩 CI 의 4 가지 형태
부트스트랩으로 CI 를 구성하는 4 가지 표준 방법 이 있다.
- Normal Bootstrap — 평균 ± 1.96 × 부트스트랩 SE
- Percentile — 부트스트랩 분포의 2.5 %, 97.5 % 분위수
- BCa — Bias-Corrected accelerated (편향·비대칭 보정)
- Bootstrap-t — 부트스트랩 t 통계량 분포 사용
이 글은 각 방법의 도출, 특성, 사용 시점을 정리한다.
2 Method 1 — Normal Bootstrap
2.1 절차
부트스트랩 분포의 표준 편차 (= 부트스트랩 SE) 를 사용해 정규 CI 구성.
\[ \text{CI} = \hat{\theta} \pm z_{1-\alpha/2} \cdot \text{SE}_{\text{boot}} \]
여기서 \(\text{SE}_{\text{boot}}\) 는 \(B\) 개 부트스트랩 통계량 \(\hat{\theta}^*\) 의 표준 편차.
2.2 특징
- 가장 단순
- 통계량의 분포가 정규 인 경우만 정확
- 비대칭 분포에서 부정확
2.3 사용 시점
거의 사용되지 않음. Percentile 또는 BCa 가 일반적으로 더 정확.
3 Method 2 — Percentile Bootstrap
3.1 절차
\(B\) 개 부트스트랩 통계량의 경험적 분위수 를 직접 사용:
\[ \text{CI}_{95\%} = (\hat{\theta}^*_{(0.025 B)}, \hat{\theta}^*_{(0.975 B)}) \]
즉 \(B\) 개 통계량을 정렬하고, \(2.5 \%\) 와 \(97.5 \%\) 위치의 값을 CI 끝으로 사용.
3.2 특징
- 단순, 직관적
- 분포 가정 X
- 비대칭 자료에 자연스럽게 적응
3.3 Buisson 의 사례 결과
베이커 자료 (이상치 포함, \(n = 10\)):
- 표본 평균: 56 분
- Percentile 95 % CI: (26, 110) 분 (대략)
전통 CI \((-23, 135)\) 와 달리 음수 X. 임상적으로 의미 있음.
Percentile CI 의 해석:
“1000 개 가상 표본의 평균 분포에서, 가장 작은 2.5 % 값과 가장 큰 2.5 % 값을 제외한 95 % 영역이 CI.”
이는 원 자료가 보여줄 수 있는 평균의 범위 에 자연스럽게 대응. 자료가 음수를 만들 수 없으면 CI 도 음수가 안 나옴.
전통 CI 는 모집단이 정규 라는 가정 위에서 공식적으로 음수를 만들 수 있음. 자료의 본질을 무시.
A/B 테스트의 매출 자료처럼 비음수만 가능 한 경우 percentile CI 가 자연스러움.
3.4 Percentile 의 한계
편향 자료에서 부정확. 통계량 추정에 체계적 편향 이 있으면 percentile 도 편향됨. 이를 보정한 것이 BCa.
4 Method 3 — BCa (Bias-Corrected accelerated)
4.1 동기
부트스트랩 통계량 분포가 편향 또는 비대칭 일 때 percentile 부정확. BCa 는 두 보정 적용.
4.2 절차
두 모수 추정:
- 편향 보정 \(\hat{z}_0\):
\[ \hat{z}_0 = \Phi^{-1}\left(\frac{\#\{\hat{\theta}^* < \hat{\theta}\}}{B}\right) \]
(부트스트랩 분포에서 원 추정값보다 작은 비율의 정규 분위수)
- 가속도 \(\hat{a}\) (jackknife 기반):
\[ \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}} \]
(분포 비대칭 측정)
조정된 분위수:
\[ \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: \((\hat{\theta}^*_{(\alpha_1 B)}, \hat{\theta}^*_{(\alpha_2 B)})\).
4.3 특징
- 대부분의 경우에서 가장 정확
- 편향 + 비대칭 모두 보정
- 계산이 percentile 보다 약간 복잡
4.4 권장
R 의 boot.ci(type="bca") 또는 Python 의 scipy.stats.bootstrap(method='BCa') 가 자동 계산.
5 Method 4 — Bootstrap-t
5.1 절차
부트스트랩으로 t 통계량의 분포 를 시뮬레이션하고 분위수 사용.
\[ t^* = \frac{\hat{\theta}^* - \hat{\theta}}{\text{SE}^*} \]
\(B\) 개 \(t^*\) 의 분포에서 분위수로 CI:
\[ \text{CI} = \hat{\theta} - t^*_{1-\alpha/2} \cdot \text{SE}, \; \hat{\theta} - t^*_{\alpha/2} \cdot \text{SE} \]
5.2 특징
- 정확성: BCa 와 비슷하거나 더 좋음
- 단점: 각 부트스트랩 표본에서 SE 추정 필요. 계산 비용 두 배.
5.3 사용 시점
큰 표본에서 매우 정확한 CI 필요한 경우.
6 4 가지 방법 비교 표
| 방법 | 정확성 | 계산 비용 | 사용 시점 |
|---|---|---|---|
| Normal | 낮음 | 낮음 | 거의 사용 X |
| Percentile | 중간 | 낮음 | 빠른 추정 |
| BCa | 높음 | 중간 | 표준 권장 |
| Bootstrap-t | 매우 높음 | 높음 | 정밀 추정 필요 |
7 사용 시점 결정 트리
빠른 추정 (탐색)
↓
Percentile
표준 분석 (대부분의 경우)
↓
BCa
매우 정밀 (논문 등)
↓
Bootstrap-t 또는 BCa
8 Buisson 의 권장
“대부분의 경우 BCa 사용. Percentile 은 시각화 와 직관 을 위해 보조적으로.”
8.1 Robustness Check
여러 방법 동시 보고가 robustness 를 확인:
부트스트랩 95 % CI:
Percentile: (26, 110)
BCa: (28, 112)
Bootstrap-t: (27, 111)
→ 세 방법 결과 일관 → 강건
방법 간 큰 차이 시 자료의 특이성 (강한 비대칭, 작은 표본) 의심.
9 코드 예시 — 4 가지 CI 비교
import numpy as np
from scipy.stats import bootstrap, norm
np.random.seed(42)
# Buisson 사례
times = np.array([300, 12, 18, 25, 30, 35, 22, 28, 31, 19])
n = len(times)
B = 10000
# 1. Percentile
boot_means = np.array([
np.random.choice(times, size=n, replace=True).mean()
for _ in range(B)
])
ci_perc = np.percentile(boot_means, [2.5, 97.5])
# 2. Normal Bootstrap
mean = times.mean()
se_boot = boot_means.std(ddof=1)
ci_normal = (mean - 1.96 * se_boot, mean + 1.96 * se_boot)
# 3. BCa (scipy)
res = bootstrap((times,), np.mean, n_resamples=B, method='BCa', random_state=42)
ci_bca = res.confidence_interval
# 4. Bootstrap-t (자체 구현)
t_stars = []
for _ in range(B):
sample = np.random.choice(times, size=n, replace=True)
if sample.std(ddof=1) > 0:
t_stars.append((sample.mean() - mean) / (sample.std(ddof=1) / np.sqrt(n)))
t_stars = np.array(t_stars)
t_lower, t_upper = np.percentile(t_stars, [2.5, 97.5])
se_orig = times.std(ddof=1) / np.sqrt(n)
ci_t = (mean - t_upper * se_orig, mean - t_lower * se_orig)
# 비교
print(f"표본 평균: {mean:.2f}\n")
print(f"전통 95 % CI: ({mean - 1.96*se_orig:.2f}, {mean + 1.96*se_orig:.2f})")
print(f"Bootstrap Percentile: ({ci_perc[0]:.2f}, {ci_perc[1]:.2f})")
print(f"Bootstrap Normal: ({ci_normal[0]:.2f}, {ci_normal[1]:.2f})")
print(f"Bootstrap BCa: ({ci_bca.low:.2f}, {ci_bca.high:.2f})")
print(f"Bootstrap-t: ({ci_t[0]:.2f}, {ci_t[1]:.2f})")10 A/B 테스트의 적용
10.1 매출 분석
A/B 테스트 매출 자료가 우편향. 부트스트랩 BCa 로 그룹 평균과 차이의 CI 직접 계산.
10.2 Median 분석
매출 중앙값 비교 (이상치 robust). 전통 공식 X. 부트스트랩이 표준.
10.3 Lift 분석
상대 효과 (\(p_T / p_C - 1\)) 의 CI. 비율의 비율이라 분포 복잡. 부트스트랩이 일반.
11 4 방법의 시뮬레이션 비교
부트스트랩 CI 4 방법의 성능을 시뮬레이션 으로 비교.
11.1 시뮬레이션 설정
import numpy as np
from scipy.stats import bootstrap
np.random.seed(42)
# 진짜 모집단 (대수정규)
true_dist = lambda n: np.random.lognormal(mean=2, sigma=1, size=n)
true_mean = np.exp(2 + 0.5) # 진짜 모집단 평균
# 1000 회 반복으로 coverage 측정
n_simulations = 1000
n_sample = 30
coverage = {'normal': 0, 'percentile': 0, 'bca': 0}
ci_widths = {'normal': [], 'percentile': [], 'bca': []}
for _ in range(n_simulations):
sample = true_dist(n_sample)
B = 2000
# Bootstrap 통계량
boot_means = np.array([
np.random.choice(sample, n_sample, replace=True).mean()
for _ in range(B)
])
# Normal
se = boot_means.std(ddof=1)
ci_n = (sample.mean() - 1.96*se, sample.mean() + 1.96*se)
# Percentile
ci_p = np.percentile(boot_means, [2.5, 97.5])
# BCa (scipy)
res = bootstrap((sample,), np.mean, n_resamples=B, method='BCa', random_state=0)
ci_b = (res.confidence_interval.low, res.confidence_interval.high)
# Coverage
if ci_n[0] < true_mean < ci_n[1]:
coverage['normal'] += 1
if ci_p[0] < true_mean < ci_p[1]:
coverage['percentile'] += 1
if ci_b[0] < true_mean < ci_b[1]:
coverage['bca'] += 1
ci_widths['normal'].append(ci_n[1] - ci_n[0])
ci_widths['percentile'].append(ci_p[1] - ci_p[0])
ci_widths['bca'].append(ci_b[1] - ci_b[0])
# 결과
for method in ['normal', 'percentile', 'bca']:
print(f"{method}: coverage = {coverage[method]/n_simulations:.3f}, "
f"평균 폭 = {np.mean(ci_widths[method]):.3f}")11.2 예상 결과
| 방법 | Coverage (목표 95 %) | 평균 폭 |
|---|---|---|
| Normal | 0.88 | 좁음 |
| Percentile | 0.91 | 보통 |
| BCa | 0.94 | 보통 |
비대칭 자료에서 BCa 가 목표에 가장 가까움.
12 Bootstrap CI 의 함정
12.1 함정 1 — 작은 \(B\) 의 변동
\(B\) 가 너무 작으면 부트스트랩 분포가 불안정. 같은 자료의 두 부트스트랩 실행이 다른 CI.
해법: \(B \geq 5000\) (CI 용), \(B \geq 10000\) (정밀 분석).
12.2 함정 2 — 극단 통계량
최댓값, 최솟값, 극단 분위수에서 부트스트랩 부정확.
이유: 부트스트랩 표본의 max 가 항상 원 자료의 max (그 이하). 표집 분포 왜곡.
해법: m-out-of-n bootstrap 또는 극단값 이론.
12.3 함정 3 — 의존성 자료
시계열, 클러스터에서 단순 부트스트랩 부정확.
해법: Block bootstrap, Cluster bootstrap (다음 글들).
12.4 함정 4 — 큰 표본의 조심
매우 큰 자료에서 부트스트랩이 느림. BLB 또는 분산 컴퓨팅.
13 CI 보고 시 권장 형식
효과 점추정: 5.30 (단위)
95 % BCa CI: (3.20, 7.80)
Bootstrap 표본 수: B = 5000
방법: BCa (Bias-Corrected accelerated)
이 형식이 재현 가능 + 정확성 정보 모두.
14 다른 Bootstrap CI 방법
14.1 Bootstrap Hypothesis Testing CI
검정 통계량의 부트스트랩 분포 → CI 도출.
14.2 Studentized Bootstrap (Bootstrap-t)
각 부트스트랩 표본에서 t 통계량 계산. 분포의 분위수 사용.
def studentized_bootstrap(data, B=5000):
n = len(data)
obs_mean = data.mean()
obs_se = data.std(ddof=1) / np.sqrt(n)
t_stars = []
for _ in range(B):
sample = np.random.choice(data, n, replace=True)
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])
return (obs_mean - t_high * obs_se, obs_mean - t_low * obs_se)가장 정확하지만 각 부트스트랩 표본에서 SE 계산 필요. 비싸지만 2 차 정확.
14.3 ABC (Approximate Bootstrap Confidence)
분석적 근사 — 부트스트랩 시뮬레이션 대신 분석 공식.
# 단순화 (실제 ABC 는 더 복잡)
def abc_ci(data, alpha=0.05):
n = len(data)
mean = data.mean()
se = data.std(ddof=1) / np.sqrt(n)
z = norm.ppf(1 - alpha/2)
return (mean - z*se, mean + z*se)빠르지만 분포 가정 일부 사용.
15 후속 — Sample Size 와 임의 통계량
다음 글 A-BUI7-2 는 부트스트랩 표본 수 권고와 임의 통계량 (회귀, ROC AUC 등) 적용을 다룬다.
16 관련 주제
선행 지식
후속 주제 (Phase A)
- A-BUI7-2 Sample Size + 임의 통계량
- A-WOO14-2 Bootstrap CI 4 유형 (Woodward 시각)
다른 카테고리 연결