1 도입 — 시나리오마다 다른 절차
Bonferroni·Holm 은 일반적 보정 이라 어떤 비교에도 적용 가능하지만 비교의 특수 구조 를 활용하지 않아 보수적이다. 이 글은 Maxwell Ch.5 의 특수 구조 에 맞춘 3 가지 표준 절차를 다룬다.
| 절차 | 사용 시점 | 추론 강도 |
|---|---|---|
| Tukey HSD | 모든 쌍별 비교 | 수준 2-3 |
| Scheffé | 모든 가능한 대비 | 수준 4 |
| Dunnett | 대조군 vs 처치군들 | 수준 1 |
2 Tukey HSD
\(J\) 그룹의 모든 쌍별 평균 차이 를 동시 검정. \(\alpha_{EW} \leq \alpha\) 보장.
검정 통계량 (균형 설계):
\[ q = \frac{|\bar{Y}_i - \bar{Y}_j|}{\sqrt{\text{MS}_W / n_0}} \]
이는 Studentized range 분포 \(q_{\alpha, J, n - J}\) 를 따른다.
기각 기준: \(q > q_{\alpha, J, n-J}\).
2.1 Studentized Range 분포
\(J\) 정규 변량 \(Z_1, Z_2, \ldots, Z_J\) 의 최대값과 최소값의 차이 를 추정된 표준 오차 로 표준화한 분포.
\[ q = \frac{\max_i Z_i - \min_i Z_i}{\sqrt{S^2 / n}} \]
이 분포가 모든 쌍별 차이의 최대 절댓값 의 분포와 일치한다. Tukey 가 1949 년 도출.
2.2 동시 신뢰 구간 (균형 설계)
\[ (\bar{Y}_i - \bar{Y}_j) \pm q_{\alpha, J, n-J} \cdot \sqrt{\frac{\text{MS}_W}{n_0}} \]
Bonferroni 는 6 쌍 비교 (4 그룹) 에 \(\alpha / 6 \approx 0.0083\) 사용. 그러나 모든 쌍별 비교가 양의 상관 (같은 자료, 같은 \(\text{MS}_W\)). 이 상관을 무시하면 보수적.
Tukey HSD 는 Studentized range 분포 를 사용해 상관 구조를 정확히 반영. 임계값이 Bonferroni 보다 작아 검정력 향상.
| \(J\) | \(\binom{J}{2}\) | Tukey \(q_{0.05}\) | Bonferroni 임계값 (대략) |
|---|---|---|---|
| 3 | 3 | 약 3.5 | 약 4.0 |
| 4 | 6 | 약 3.7 | 약 4.5 |
| 5 | 10 | 약 4.0 | 약 5.0 |
Tukey 가 항상 Bonferroni 보다 검정력 우수 (모든 쌍별 비교 시).
2.3 불균형 설계의 변형
\(n_j\) 가 그룹마다 다른 경우 Tukey-Kramer 변형:
\[ q = \frac{|\bar{Y}_i - \bar{Y}_j|}{\sqrt{\frac{\text{MS}_W}{2} \left(\frac{1}{n_i} + \frac{1}{n_j}\right)}} \]
균형 설계와 거의 같은 검정력을 유지한다.
2.4 사용 시점
- 사후 모든 쌍 비교가 목표
- 균형 또는 약한 불균형 설계
- 비슷한 분산 (등분산 가정)
3 Scheffé
모든 가능한 대비 (쌍별이 아닌 임의의 합 0 계수) 의 동시 검정. \(\alpha_{EW} \leq \alpha\) 보장.
대비 \(\psi = \sum c_j \mu_j\) 의 임계값:
\[ F^* = (J - 1) \cdot F_{\alpha, J-1, n-J} \]
기각 기준: \(F = \widehat{\psi}^2 / \text{Var}(\widehat{\psi}) > F^*\), 또는 동등하게
\[ \frac{|\widehat{\psi}|}{\sqrt{\text{Var}(\widehat{\psi})}} > \sqrt{(J-1) \cdot F_{\alpha, J-1, n-J}} \]
3.1 Scheffé 의 일반성
Scheffé 는 어떤 대비도 검정 가능. 사후에 자료를 본 후 새로운 대비를 발견해도 Scheffé 임계값 적용 시 \(\alpha_{EW}\) 가 보존된다.
3.2 보수성
Scheffé 의 임계값 \(\sqrt{(J-1) F_{\alpha, J-1, n-J}}\) 은 다른 절차보다 큼. 따라서 가장 보수적.
| \(J\) | Scheffé 임계값 (\(\alpha = 0.05\), \(n = 80\)) | Tukey HSD 임계값 |
|---|---|---|
| 3 | \(\sqrt{2 \cdot F_{0.05, 2, 77}} \approx 2.49\) | \(q_{0.05, 3, 77} / \sqrt{2} \approx 2.39\) |
| 4 | \(\sqrt{3 \cdot F_{0.05, 3, 76}} \approx 2.85\) | \(q_{0.05, 4, 76} / \sqrt{2} \approx 2.65\) |
| 5 | \(\sqrt{4 \cdot F_{0.05, 4, 75}} \approx 3.16\) | \(q_{0.05, 5, 75} / \sqrt{2} \approx 2.85\) |
Scheffé 가 항상 Tukey 보다 보수적.
3.3 사용 시점
- 임의의 가능한 대비 를 사후 검정
- 데이터를 본 후 새로운 가설 발견
- “어떤 대비라도 통과시켜야 안전한” 보수적 보고
대부분의 실무에서 과한 보수성 이라 사용이 제한적이다. 사후 모든 가능 대비 검정이 정말로 목적인 경우만.
4 Dunnett
하나의 대조군 (group 1) 과 여러 처치군 (groups 2, 3, …, \(J\)) 의 차이 비교.
\(J - 1\) 개 비교: \(\mu_1 - \mu_2\), \(\mu_1 - \mu_3\), …, \(\mu_1 - \mu_J\).
\(\alpha_{EW} \leq \alpha\) 보장.
검정 통계량 (균형 설계):
\[ t_d = \frac{\bar{Y}_1 - \bar{Y}_j}{\sqrt{\text{MS}_W \cdot 2 / n_0}} \]
이는 Dunnett 분포 (수정된 Studentized maximum) 의 분위수 \(d_{\alpha, J-1, n-J}\) 와 비교.
4.1 Dunnett 의 효율성
Dunnett 은 모든 쌍 비교 가 아니라 대조군 vs 처치군 만 검정한다. 비교 수가 \(J - 1\) (Tukey 의 \(\binom{J}{2}\) 보다 적음) 이라 검정력이 더 높다.
| \(J\) | Tukey 비교 수 | Dunnett 비교 수 |
|---|---|---|
| 3 | 3 | 2 |
| 4 | 6 | 3 |
| 5 | 10 | 4 |
| 10 | 45 | 9 |
비교 수가 적을수록 임계값 작음 → 검정력 큼.
4.2 사용 시점
- 대조군이 명확 (예: 위약, 기존 디자인)
- 처치군 간 비교는 무관
- 검정력 극대화 필요
A/B 테스트의 흔한 시나리오: A (대조군) vs B, C, D (신규 변형들).
다중 비교 시나리오?
↓
1 대조군 vs 여러 처치군?
Yes → Dunnett (가장 효율적)
No → ↓
모든 쌍별 비교?
Yes → Tukey HSD (균형) 또는 Tukey-Kramer (불균형)
No → ↓
복합 대비 (한 그룹 vs 평균, 두 그룹 vs 두 그룹) ?
Yes → Bonferroni 또는 Holm (소수 비교) / Scheffé (다수)
No → ↓
임의의 가능한 대비 (사후 발견)?
Yes → Scheffé (보수적이지만 안전)
이 트리가 비교 구조에 가장 적합한 절차 선택의 가이드이다. 잘못된 절차 선택은 검정력 손실 또는 \(\alpha\) 인플레이션을 만든다.
5 검정력 비교
같은 효과 크기, 같은 표본 크기에서 절차별 검정력 비교 (4 그룹 사례):
| 절차 | 비교 유형 | 상대 검정력 |
|---|---|---|
| 무보정 (Per-comparison) | 임의 | 100 % (기준) |
| Dunnett (대조군 vs 처치군) | 3 비교 | 약 90 % |
| Tukey HSD (모든 쌍) | 6 비교 | 약 75 % |
| Bonferroni (6 비교) | 임의 | 약 65 % |
| Scheffé (모든 대비) | 무한 | 약 55 % |
검정력 손실은 비교 구조 와 절차의 적합도 에 따라 다르다. 적합한 절차 선택이 검정력 보존의 핵심.
6 실무 사례
6.1 사례 1 — 임상시험 Phase III
3 용량 (저, 중, 고) + 위약 비교. 위약이 명확한 대조군.
권장: Dunnett. 검정력 극대화 + 명확한 의사결정 (어느 용량이 위약보다 우수한가).
6.2 사례 2 — UI 디자인 다중 변형
대조군 (현재 디자인) + 신규 디자인 A, B, C 의 클릭률 비교.
권장: Dunnett. A/B 테스트의 표준 시나리오.
6.3 사례 3 — 사후 발견 결과
ANOVA 후 자료를 보다가 “그룹 1, 2 vs 그룹 3 의 평균” 같은 사후 가설 발견.
권장: Scheffé. 사후 발견에 안전.
6.4 사례 4 — 수업 비교
5 가지 교습법 (강의, 토론, 자율, 혼합 1, 혼합 2) 의 학습 효과. 모든 쌍 비교가 관심.
권장: Tukey HSD (모든 10 쌍 비교).
7 코드 예시 — 3 절차 비교
import numpy as np
import pandas as pd
from scipy.stats import f, studentized_range
import statsmodels.api as sm
from statsmodels.formula.api import ols
from statsmodels.stats.multicomp import pairwise_tukeyhsd
np.random.seed(42)
n_each = 20
J = 4
group_control = np.random.normal(120, 10, n_each)
group_drug_a = np.random.normal(116, 10, n_each)
group_drug_b = np.random.normal(118, 10, n_each)
group_combined = np.random.normal(110, 10, n_each)
groups = ['control']*n_each + ['drug_a']*n_each + ['drug_b']*n_each + ['combined']*n_each
all_data = np.concatenate([group_control, group_drug_a, group_drug_b, group_combined])
df = pd.DataFrame({'bp': all_data, 'treatment': groups})
# 옴니버스 ANOVA
model = ols('bp ~ C(treatment)', data=df).fit()
anova_table = sm.stats.anova_lm(model)
ms_w = anova_table['mean_sq'].iloc[1]
df_w = int(anova_table['df'].iloc[1])
print("ANOVA F 검정:")
print(anova_table)
# 1. Tukey HSD (모든 쌍별)
print("\n--- Tukey HSD (모든 쌍 비교) ---")
tukey = pairwise_tukeyhsd(df['bp'], df['treatment'], alpha=0.05)
print(tukey)
# 2. Scheffé (자체 구현)
print("\n--- Scheffé (모든 가능한 대비) ---")
F_crit = f.ppf(0.95, J - 1, df_w)
scheffe_critical = np.sqrt((J - 1) * F_crit)
print(f"Scheffé 임계값: √((J-1)·F) = {scheffe_critical:.3f}")
# 임의의 대비 (예: control vs drug_a)
group_means = df.groupby('treatment')['bp'].mean()
c = {'control': 1, 'drug_a': -1, 'drug_b': 0, 'combined': 0}
psi = sum(c[g] * group_means[g] for g in c)
se_psi = np.sqrt(ms_w * sum(c[g]**2 / n_each for g in c))
t_psi = psi / se_psi
print(f"control vs drug_a: ψ = {psi:.2f}, t = {t_psi:.3f}, |t| > {scheffe_critical:.3f}? {abs(t_psi) > scheffe_critical}")
# 3. Dunnett (control 이 대조군)
print("\n--- Dunnett (control vs 각 처치군) ---")
# scipy 또는 statsmodels 에는 Dunnett 직접 구현 없음. statsmodels.stats.multicomp 의 별도 함수 사용
# 대안: pingouin.pairwise_ttests with one_vs_rest
import scipy.stats as stats
# 자체 구현 — Dunnett 임계값 사용 (정확히는 Dunnett 분포가 필요하나, 여기서는 Bonferroni 근사)
print("(Dunnett 분포는 별도 구현 필요. 여기서는 Bonferroni 근사)")
treatments = ['drug_a', 'drug_b', 'combined']
control_mean = group_means['control']
for tx in treatments:
diff = control_mean - group_means[tx]
se = np.sqrt(ms_w * (1/n_each + 1/n_each))
t_dunnett = diff / se
p_two = 2 * (1 - stats.t.cdf(abs(t_dunnett), df_w))
p_bonf_approx = min(p_two * 3, 1) # 3 비교 Bonferroni 근사
print(f" control vs {tx}: t = {t_dunnett:.3f}, p (Bonf 근사) = {p_bonf_approx:.4f}")이 코드는 3 절차의 결과 를 비교한다. 각 절차의 기각/유의 수 가 다를 수 있다.
8 Hochberg, Hommel — 추가 변형
Bonferroni·Holm 의 계열에서 양의 상관 비교 에서 더 강한 검정력을 보이는 변형.
| 절차 | 강점 |
|---|---|
| Bonferroni | 가장 단순, 가장 보수적 |
| Holm (step-down) | Bonferroni 강화, 음의 상관 안전 |
| Hochberg (step-up) | 양의 상관에서 강함 |
| Hommel | Hochberg 와 비슷, 약간 더 강함 |
실무에서 비교 사이 상관 구조 를 알면 Hochberg 또는 Hommel 이 가장 강력. 모르면 Holm 으로 안전 선택.
9 Tukey HSD 의 자세한 도출
9.1 Studentized Range 분포
\(J\) 정규 변량 \(Z_1, Z_2, \ldots, Z_J\) (평균 0, 분산 \(\sigma^2\), 독립) 와 추정된 분산 \(S^2\) (자유도 \(\nu\)).
\[ q = \frac{\max_i Z_i - \min_i Z_i}{S} \]
이 통계량의 분포가 Studentized range \(q_{J, \nu}\).
9.2 Tukey HSD 의 도출
ANOVA 후 모든 쌍별 비교 (\(\binom{J}{2}\) 개) 의 검정.
핵심 통찰: 최대 차이 가 임계값을 통과하면 모든 작은 차이 도 자동 통제.
따라서 모든 쌍별 비교 의 임계값 = \(q_{\alpha, J, n-J}\).
9.3 검정 통계량
\[ q_{ij} = \frac{|\bar{Y}_i - \bar{Y}_j|}{\sqrt{\text{MS}_W / n_0}} \]
(균형 설계). 기각 기준: \(q_{ij} > q_{\alpha, J, n-J}\).
9.4 Tukey-Kramer (불균형)
\[ q_{ij} = \frac{|\bar{Y}_i - \bar{Y}_j|}{\sqrt{\frac{\text{MS}_W}{2}\left(\frac{1}{n_i} + \frac{1}{n_j}\right)}} \]
균형 사례와 거의 동일한 검정력.
9.5 Tukey HSD 의 강점
import numpy as np
from scipy.stats import studentized_range, f as f_dist
# 4 그룹 비교
J = 4
n_per = 25
df_w = J * (n_per - 1)
# Tukey HSD 임계값
q_tukey = studentized_range.ppf(0.95, J, df_w)
print(f"Tukey q (J=4, df={df_w}): {q_tukey:.3f}")
# Bonferroni 임계값 비교 (6 비교)
from scipy.stats import t as t_dist
n_comp = 6
t_bonf = t_dist.ppf(1 - 0.025/n_comp, df_w)
# Studentized range 와 비교 — q = √2 · t (대략)
q_bonf_equiv = np.sqrt(2) * t_bonf
print(f"Bonferroni 등가 q: {q_bonf_equiv:.3f}")
# 비율
print(f"Tukey 가 Bonferroni 보다 {(q_bonf_equiv/q_tukey - 1)*100:.1f} % 좁음")Tukey 가 상관 구조 활용 으로 약 5~15 % 더 좁은 임계값 = 검정력 향상.
10 Scheffé 절차의 자세한 도출
10.1 F 분포 기반 임계값
임의의 대비 \(\psi\) 의 검정 통계량:
\[ F = \frac{\widehat{\psi}^2}{\sum (c_j^2/n_j) \cdot \text{MS}_W} \]
기각 기준: \(F > (J-1) \cdot F_{\alpha, J-1, n-J}\).
또는 동등하게:
\[ \frac{|\widehat{\psi}|}{\sqrt{\text{Var}(\widehat{\psi})}} > \sqrt{(J-1) \cdot F_{\alpha, J-1, n-J}} \]
10.2 임의의 대비
Scheffé 의 일반성: 사전에 정의되지 않은 어떤 대비 도 검정 가능.
10.3 Scheffé 와 ANOVA F 의 관계
ANOVA 옴니버스 F 가 유의 ↔︎ 적어도 한 Scheffé 대비가 유의.
이 동치성 이 Scheffé 의 정당성. 옴니버스 정보를 모든 대비로 분배.
11 Dunnett 절차의 자세한 도출
11.1 Dunnett’s t 분포
11.2 Dunnett vs Bonferroni 비교
| \(J\) | \(J - 1\) 비교 | Dunnett 임계값 | Bonferroni 임계값 |
|---|---|---|---|
| 3 | 2 | 약 2.25 | 약 2.39 |
| 4 | 3 | 약 2.40 | 약 2.63 |
| 5 | 4 | 약 2.51 | 약 2.79 |
| 10 | 9 | 약 2.80 | 약 3.30 |
Dunnett 이 약 5~15 % 더 효율 (상관 구조 활용).
12 절차 비교 — 동일 시나리오
import numpy as np
import pandas as pd
import statsmodels.api as sm
from statsmodels.formula.api import ols
from statsmodels.stats.multicomp import pairwise_tukeyhsd
np.random.seed(42)
n_per = 25
J = 4
# 4 그룹 자료
data = []
for j in range(J):
data.extend(np.random.normal(loc=10 + j*0.5, scale=3, size=n_per))
groups = np.repeat(['A', 'B', 'C', 'D'], n_per)
df = pd.DataFrame({'value': data, 'group': groups})
# 1. ANOVA F
model = ols('value ~ C(group)', data=df).fit()
print("ANOVA F 검정:")
print(sm.stats.anova_lm(model, typ=2))
# 2. Tukey HSD
print("\n--- Tukey HSD ---")
tukey = pairwise_tukeyhsd(df['value'], df['group'], alpha=0.05)
print(tukey)
# 3. Scheffé (모든 가능한 대비)
ms_w = sm.stats.anova_lm(model)['mean_sq'].iloc[1]
df_w = int(sm.stats.anova_lm(model)['df'].iloc[1])
F_crit = f_dist.ppf(0.95, J-1, df_w)
scheffe_threshold = np.sqrt((J-1) * F_crit)
print(f"\n--- Scheffé ---")
print(f"임계값: {scheffe_threshold:.3f}")
# 4. Bonferroni (모든 쌍)
n_comp = 6
alpha_bonf = 0.05 / n_comp
print(f"\n--- Bonferroni ---")
print(f"단일 비교 α: {alpha_bonf:.4f}")
# 5. Dunnett (대조군 'A' vs 처치군)
print(f"\n--- Dunnett (자체 구현) ---")
control = df[df['group']=='A']['value']
for tx in ['B', 'C', 'D']:
treatment = df[df['group']==tx]['value']
diff = treatment.mean() - control.mean()
se = np.sqrt(ms_w * (1/n_per + 1/n_per))
t_stat = diff / se
print(f" A vs {tx}: t = {t_stat:.3f}, diff = {diff:.3f}")이 코드가 5 가지 절차 비교. 각각의 결과 일관 또는 차이 확인.
13 절차 선택의 비즈니스 가이드
A/B 테스트 시나리오?
1 metric, 2 variants
→ 단순 t 검정 (보정 X)
1 metric, 3+ variants (multi-arm)
대조군 명확? Yes → Dunnett
No → Tukey HSD
2+ metrics, 2 variants
Primary 우선? Yes → Primary 보정 X, Secondary FDR
No → Bonferroni 또는 Holm
Many segments + many metrics
→ FDR 또는 hierarchical
이 가이드가 비즈니스 결정 도구.
14 후속 — FDR
다음 글 A-MAX5-4 는 FDR (False Discovery Rate) 를 다룬다. FDR 은 \(\alpha_{EW}\) 와 다른 통제 대상이며, 많은 가설 에서 효율적이다.
15 관련 주제
선행 지식
후속 주제 (Phase A)
- A-MAX5-4 FDR + 실무 조정
다른 카테고리 연결