1 도입 — Bonferroni 가 잘못된 질문에 답한다
Schulz 의 핵심 비판: “Bonferroni adjustment, however, usually addresses the wrong hypothesis.” (Schulz 2019, Ch.19)
이 글은 (a) Bonferroni 의 implicit 가설이 임상적 질문과 어긋나는 이유, (b) 보정이 적절한 의사결정 시나리오, (c) Schulz 가 권장하는 interval estimation 우선 접근을 정리한다.
2 Universal Null Hypothesis 의 문제
Bonferroni 가 implicit 검정하는 가설:
\[ H_0: \text{모든 endpoints 에서 효과 0} \quad \text{vs} \quad H_1: \text{적어도 한 endpoint 에서 효과 있음} \]
이는 전체 endpoints 의 collective 효과 여부만 검정. 개별 endpoint 의 의미를 무시.
2.1 임상적 의미와의 어긋남
임상 연구의 진짜 질문:
“각 endpoint 에서 효과의 크기와 방향 은 무엇인가?”
Universal null 은 이 질문의 부분 만 답한다. 게다가 어느 endpoint 에서 효과가 있는지는 정보 X.
Rothman 의 표현:
“Universal null hypothesis 를 검정하는 것은 현실 세계에 대한 믿음을 정지시키는 것. 경험주의의 전제를 의문시하는 것이다.” (Rothman, Schulz 인용)
2.2 Doctor 비유
20 가지 검사를 처방한 의사가 결과를 받았다. 보고:
“일부 검사가 비정상입니다.” (어느 검사인지 정보 X)
이 보고는 임상적으로 무의미. 의사는 어느 검사가 비정상 인지 알아야 한다.
Universal null 검정 결과도 같은 구조다. “적어도 하나가 유의함” 만 알려줄 뿐, 어느 endpoint 인지 정보 X.
가족 식사 비유:
- 가족 단위 만족도: “가족 모두가 만족하는가” (universal)
- 개별 만족도: “각 사람이 만족하는가, 어떤 부분에 만족하는가”
가족 단위 검정은 한 사람만 만족 못해도 전체 실패 로 처리. 개별 정보는 손실.
임상 연구도 마찬가지. 각 endpoint 가 임상적으로 의미 있다면, 전체 그룹의 검정이 아니라 개별 검정이 적절. 보정은 명시적 의사결정 기준 이 universal hypothesis 일 때만 필요.
A/B 테스트의 다중 메트릭도 같다. 클릭률·매출·체류시간 각각이 독립적인 비즈니스 의미. 각 메트릭의 효과를 독립적으로 보고하는 것이 적절. Universal 검정 (“어느 메트릭이라도 차이가 있는가”) 은 비즈니스 의사결정에 부적합.
3 보정이 적절한 시점
Schulz 의 명시적 인정:
“임상 의사결정 논쟁이 오직 1 개 이상의 primary endpoints 가 유의해야 한다는 명시적 기준에 의존하는 경우, 보정이 필요하다.”
3.1 시나리오 — FDA 신약 승인
신약 승인 결정의 일반 형태:
승인 기준: Primary endpoint 1 (사망률) 또는
Primary endpoint 2 (재입원률) 또는
Primary endpoint 3 (회복 속도) 중
적어도 1 개에서 유의한 개선
이 OR 결정 규칙에서 universal null 이 정확히 검정 대상. Bonferroni 보정 없이는 우연만으로 적어도 한 endpoint 가 유의해질 확률이 높아짐.
3.2 시나리오 — 지속적 모니터링
Sequential testing 의 interim analysis 도 같은 구조.
중단 기준: 인터림 1 또는 2 또는 3 중 어느 시점이라도 유의하면 중단
이 시간 다중성 에 alpha spending 보정 적용.
3.3 보정의 본질 — Decision rule 이 결정
Schulz 의 핵심:
“보정의 필요성은 통계가 아니라 의사결정 규칙 이 결정한다. 의사결정이 universal null 형태면 보정 필요. 개별 결정이면 보정 불필요.”
이 통찰이 기계적 보정 적용 의 함정을 회피한다.
4 학술 연구의 접근 — Interval Estimation 우선
Schulz 의 권장:
“대부분의 출판된 의학 연구에서, 효과의 interval estimation (RR + CI) 가 단순 hypothesis testing (p 값) 보다 적절. 의사결정 의도는 다중성 보정을 지양 한다.”
4.1 Interval Estimation 의 장점
- 효과 크기 점추정 보고
- 불확실성 정량화 (CI 폭)
- 임상적 의미 평가 (CI 가 MCID 포함?)
- p 값 도 자연스럽게 포함 (CI 가 0/RR=1 포함 여부)
4.2 다중성 처리
Interval estimation 에서 다중성은 각 CI 의 폭 으로 자연스럽게 표현. 보정 적용 시 동시 CI (A-MAX5-1 의 simultaneous CI) 사용.
Endpoint 1 (사망): RR = 0.75, 95 % 동시 CI [0.55, 1.02]
Endpoint 2 (재입원): RR = 0.85, 95 % 동시 CI [0.65, 1.10]
Endpoint 3 (QoL 변화): MD = +5.2, 95 % 동시 CI [+1.0, +9.4]
이 형식이 p 값 보고보다 정보적. 효과 + 불확실성 + 보정 모두 표현.
5 \(\beta\) Error 인플레이션
Bonferroni 의 부작용 중 하나는 \(\beta\) error 증가. 즉 검정력 감소.
A-MAX5-2 에서 다뤘듯이:
| \(C\) 비교 수 | Bonferroni 검정력 (단일 비교 0.80 기준) |
|---|---|
| 1 | 0.80 |
| 5 | 0.61 |
| 10 | 0.49 |
| 20 | 0.36 |
Schulz 의 우려: “Bonferroni 가 false positive 를 막으려다 true effect 도 못 잡는 결과를 만든다.” 임상 영역에서 정직한 효과 미발견 도 비용이 크다 (효과적 처치 차단).
6 분야별 접근 비교
| 분야 | 다중성 표준 |
|---|---|
| FDA 신약 승인 (Phase III) | 엄격 Bonferroni 또는 hierarchical |
| 학술 임상 연구 | Interval estimation + 사전 등록 |
| 유전체학 (GWAS) | FDR (Benjamini-Hochberg) |
| 심리학 학술 | FDR 또는 Bonferroni |
| 비즈니스 A/B 테스트 (primary) | 보정 또는 단일 metric 우선 |
| 비즈니스 A/B 테스트 (탐색) | FDR |
각 분야의 의사결정 구조 에 따라 적절한 보정이 다르다.
7 사례 — 항생제 시험 (Schulz)
7.1 자료
가상 시험: 새 항생제 vs 표준. 두 endpoints:
- 발열: RR = 0.50, 95 % CI [0.25, 0.99], \(p = 0.048\)
- 상처 감염: RR = 0.48, 95 % CI [0.24, 0.97], \(p = 0.041\)
두 endpoints 가 생물학적으로 강하게 연관 (둘 다 감염 지표).
7.2 Bonferroni 적용 결과
\(\alpha / 2 = 0.025\). 두 결과 모두 보정된 임계값 초과 → 둘 다 유의 X 결론.
7.3 Schulz 의 비판
“Bonferroni 결과는 비논리적. 두 endpoints 가 서로 보강 하는 결과인데, 보정이 둘 다 무효화 한다. 임상적으로 결과가 더 강해진 것을 통계가 약해진 것으로 만든다.”
7.4 적절한 접근
보고:
Primary endpoint (발열): RR = 0.50, 95 % CI [0.25, 0.99], p = 0.048
Secondary endpoint (상처 감염): RR = 0.48, 95 % CI [0.24, 0.97], p = 0.041
논의:
"두 endpoints 가 모두 유의한 감소를 보임. 두 결과는 *생물학적으로
강하게 연관* 되어 있어 서로 보강한다. 새 항생제의 감염 예방 효과를
강하게 시사."
이 접근이 임상적 정직성 과 통계적 정확성 의 균형을 이룬다.
8 코드 예시 — 보정 적용 vs 미적용
import numpy as np
from statsmodels.stats.multitest import multipletests
# Schulz 항생제 시험 자료
p_values = np.array([0.048, 0.041]) # 발열, 상처 감염
endpoints = ['발열', '상처 감염']
# 무보정 (개별 검정)
print("무보정:")
for ep, p in zip(endpoints, p_values):
sig = "유의" if p < 0.05 else "미유의"
print(f" {ep}: p = {p:.3f} → {sig}")
# Bonferroni 보정
reject_bonf, p_bonf, _, _ = multipletests(p_values, alpha=0.05, method='bonferroni')
print(f"\nBonferroni:")
for ep, p_orig, p_adj, rej in zip(endpoints, p_values, p_bonf, reject_bonf):
sig = "유의" if rej else "미유의"
print(f" {ep}: p_orig = {p_orig:.3f} → p_adj = {p_adj:.3f} → {sig}")
# Holm
reject_holm, p_holm, _, _ = multipletests(p_values, alpha=0.05, method='holm')
print(f"\nHolm (덜 보수적):")
for ep, p_orig, p_adj, rej in zip(endpoints, p_values, p_holm, reject_holm):
sig = "유의" if rej else "미유의"
print(f" {ep}: p_orig = {p_orig:.3f} → p_adj = {p_adj:.3f} → {sig}")
# Schulz 의 입장 — Interval estimation
print("\nInterval Estimation (Schulz 권장):")
print(" 발열: RR = 0.50, 95 % CI [0.25, 0.99]")
print(" 상처 감염: RR = 0.48, 95 % CI [0.24, 0.97]")
print(" → 두 endpoints 가 일관되게 감소 효과. 임상적 결론은 *효과 있음*.")이 코드가 보여주는 것은 보정의 결과가 결론을 뒤바꿀 수 있다. 그러나 임상적으로 어느 결과가 정확 한가? Schulz 는 interval estimation 우선 + 보정의 신중한 사용 을 권장.
9 보고 형식 — Schulz 권장
프로토콜 (사전 등록):
Primary outcome: 사망률
Secondary outcomes: 재입원률, QoL, 부작용
분석 계획: Primary 만 confirmatory (보정 X — 1 개 endpoint).
Secondary 는 exploratory (FDR 보정).
결과:
Primary:
사망률: RR = 0.75, 95 % CI [0.55, 1.02], p = 0.069
→ 임계 미달, 결정적 결론 X. CI 의 폭이 효과 가능성 시사.
Secondary (FDR 보정):
재입원: RR = 0.80, 95 % CI [0.65, 0.99], p_adj = 0.045
QoL: MD = +5.0, 95 % CI [+1.0, +9.0], p_adj = 0.020
부작용: RR = 1.20, 95 % CI [0.95, 1.50], p_adj = 0.10
결론: Primary 결과 결정적 X. Secondary 가 효과 시사.
추가 시험 필요 (확정성 부족).
이 형식이 사전 등록 + 계층화 + interval estimation + 정직한 결론 의 모범.
10 Hierarchical (Hochberg) 절차 — 임상 표준
Hochberg 또는 hierarchical testing 이 임상 multi-endpoint 시험의 표준.
10.1 Hierarchical 절차
1. Primary endpoint 1 검정 (α = 0.05)
유의 → 다음 단계
미유의 → 중단 (모든 후속 endpoints 미유의 처리)
2. Primary endpoint 2 검정 (α = 0.05)
유의 → 다음 단계
미유의 → 중단
...
이 순차 종속 검정에서 각 단계가 전체 \(\alpha\) 사용. 종속 구조가 보정 없이 \(\alpha_{EW}\) 보장.
10.2 사용 시점
- Endpoints 사이 명확한 우선순위
- 순차적 검증 가능
- 첫 endpoint 가 가장 중요
A/B 테스트 사례: 매출 → 클릭률 → 체류시간 순.
11 Hierarchical Testing — 자세히
여러 endpoints 를 우선순위 로 정렬. 각 단계가 유의해야 다음으로.
단계 1: Primary endpoint (α = 0.05)
유의 → 단계 2
미유의 → 중단
단계 2: Secondary endpoint 1 (α = 0.05)
유의 → 단계 3
미유의 → 중단
...
이 순차 종속 검정에서 각 단계가 전체 α 사용. 자동 multiplicity 통제.
11.1 정당성
확률 이론으로:
\[ P(\text{어떤 false positive}) \leq \alpha \]
가 자동 보장 (각 단계가 이전 단계 통과 필요).
11.2 Endpoints 우선순위
원칙:
Primary: 가장 중요한 outcome (1 개)
Secondary 1: 다음 중요
Secondary 2: 다음 중요
...
A/B 테스트 사례:
Primary: 매출
Secondary 1: 클릭률
Secondary 2: 체류시간
Secondary 3: 재방문율
매출이 미유의면 모든 후속도 미유의 처리.
11.3 한계
- Primary 미유의 → 후속 전부 missing 처리 → 정보 손실
- 우선순위 사후 변경 금지
- Endpoint 의 명확한 우선순위 필요 (논쟁적)
12 Gatekeeping Procedures
Hierarchical 의 일반화. 여러 family 의 endpoints 를 계층적으로 검정.
Family 1 (Primary):
- Endpoint 1A
- Endpoint 1B
→ 모두 유의해야 (또는 일부) 다음 family
Family 2 (Secondary):
- Endpoint 2A
- Endpoint 2B
...
각 family 내에서 옴니버스 또는 Bonferroni 적용. Family 간은 hierarchical.
12.1 Parallel vs Serial Gatekeeping
- Serial: Family 1 의 모든 endpoint 유의 → Family 2
- Parallel: Family 1 의 일부 (예: 1 개) 유의 → Family 2
각각의 α 통제 절차가 다름.
13 Multiplicity Correction 의 분야별 표준
13.1 임상시험 (FDA)
- Primary endpoint 1 개 우선
- 다중 primary 시 Hierarchical 또는 Bonferroni
- Secondary 는 exploratory 표시
- 명확한 사전 등록
13.2 학술 임상 연구
- 사전 등록 (clinicaltrials.gov)
- CONSORT 따름
- FDR 또는 Bonferroni
13.3 Genomics (GWAS)
- FDR 표준
- Bonferroni \(\alpha = 5 \times 10^{-8}\) (genome-wide)
- Replication cohort 로 확정
13.4 A/B 테스트
- Primary metric 우선
- Secondary metrics FDR 보정 또는 hierarchical
- Sequential testing (alpha spending)
14 Multiplicity 와 Type S Error
효과 방향 (sign) 을 잘못 결론하는 오류. 일반적인 false positive 와 다른 차원.
Multiplicity 가 Type S 에 영향:
- 많은 비교 + selective reporting → 우연히 반대 방향 효과 보고
- 신뢰 구간이 0 을 포함하지 않으면 방향 정보 신뢰 가능
- p 값만으로는 방향 정확성 평가 어려움
14.1 Gelman & Tuerlinckx (2000)
이 논문이 Type S vs Type M (magnitude) 오류 도입. 효과 과대 추정 의 위험.
14.2 함의
여러 비교 검정에서: - Type I (false positive) 통제 → 표준 - Type S (방향 오류) → 효과 크기 + CI 보고 - Type M (크기 과대) → 사전 등록 + 재현 시험
이 3 차원 오류 통제 가 현대적 통계 보고.
15 A/B 테스트의 다중성 함정 추가
import numpy as np
# 시뮬레이션 — 효과 없는 자료에서 다중 검정
np.random.seed(42)
n_per = 1000
B = 1000 # 시뮬레이션
n_metrics = 10 # 메트릭 수
false_positive_count = 0
for _ in range(B):
# 두 그룹 모두 같은 분포 (H_0 참)
control = np.random.normal(0, 1, n_per)
treatment = np.random.normal(0, 1, n_per)
# 10 개 메트릭 검정 (실제로는 같은 자료의 변환)
p_values = []
for m in range(n_metrics):
if m == 0:
metric_c, metric_t = control, treatment
else:
# 단순 변환 (실제로는 다른 메트릭)
metric_c = control + np.random.normal(0, 0.1, n_per)
metric_t = treatment + np.random.normal(0, 0.1, n_per)
from scipy.stats import ttest_ind
_, p = ttest_ind(metric_c, metric_t)
p_values.append(p)
# 적어도 한 개 유의?
if min(p_values) < 0.05:
false_positive_count += 1
print(f"무보정 false positive 비율: {false_positive_count/B:.3f}")
# 약 0.40 (= 1 - 0.95^10) 예상
# Bonferroni 보정 시
fp_bonf = 0
for _ in range(B):
control = np.random.normal(0, 1, n_per)
treatment = np.random.normal(0, 1, n_per)
p_values = []
for m in range(n_metrics):
from scipy.stats import ttest_ind
c = control + np.random.normal(0, 0.01, n_per) if m > 0 else control
t = treatment + np.random.normal(0, 0.01, n_per) if m > 0 else treatment
_, p = ttest_ind(c, t)
p_values.append(p)
if min(p_values) < 0.05/n_metrics:
fp_bonf += 1
print(f"Bonferroni false positive 비율: {fp_bonf/B:.3f}")
# 약 0.05 예상이 시뮬레이션이 다중 비교 인플레이션 + 보정의 효과 를 정량적으로 보여줌.
16 후속 — Multiple Endpoints + Composite + Multiarm 자세히
다음 글 A-SCH19-2 는 multiple endpoints, composite endpoints, multiarm trials 의 자세한 처리를 다룬다.
17 관련 주제
선행 지식
후속 주제 (Phase A)
- A-SCH19-2 Multiple Endpoints + Composite + Multiarm
다른 카테고리 연결