콘텐츠로 이동

Dunnett 검정 (대조군과의 비교)

개요

많은 실험이 여러 처치군과 함께 대조군을 둔다. 예를 들어 위약군과 세 가지 약 용량, 또는 기준 공정과 네 가지 개선안이 그렇다. 이런 설계에서 관심 있는 비교는 모든 쌍별 차이가 아니라 각 처치군을 대조군과 견주는 \(k - 1\)개의 비교이다. \(\binom{k}{2}\)개의 쌍별 차이를 모두 보는 대신 이 \(k - 1\)개만 검정하면 다중검정 부담이 줄어드는데, Dunnett 검정은 이 구조를 활용하여 Tukey의 HSD나 Bonferroni보다 높은 검정력을 얻는다.

Dunnett(1955)은 바로 이런 다대일 비교에 대해 가족단위 오류율(FWER)을 수준 \(\alpha\)로 통제하는 절차를 개발했다. 핵심 통찰은 \(k - 1\)개의 검정통계량이 독립이 아니라는 점이다. 이들은 분모에 대조군 평균을 공유하며, Dunnett의 임계값은 이 상관을 반영한다.

가설

집단 \(0\)을 대조군, 집단 \(1, 2, \ldots, k-1\)을 처치군이라 하자. Dunnett 검정은 두 가지로 세울 수 있다:

양측(방향 없음): 각 처치 \(i = 1, \ldots, k-1\)에 대해

\[ H_0: \mu_i = \mu_0 \quad \text{vs} \quad H_a: \mu_i \neq \mu_0 \]

단측(방향 있음): 처치가 반응을 높일 것으로 예상하면

\[ H_0: \mu_i \leq \mu_0 \quad \text{vs} \quad H_a: \mu_i > \mu_0 \]

기대되는 효과의 방향을 미리 알고 있다면 단측이 더 강력하다.

검정통계량

처치군 \(i\)를 대조군 \(0\)과 비교하는 검정통계량은

\[ t_i = \frac{\bar{Y}_{i\cdot} - \bar{Y}_{0\cdot}}{\sqrt{\text{MS}_W \left(\dfrac{1}{n_i} + \dfrac{1}{n_0}\right)}} \]

이다. 여기서

  • \(\bar{Y}_{i\cdot}\)는 처치군 \(i\)의 표본평균
  • \(\bar{Y}_{0\cdot}\)는 대조군의 표본평균
  • \(\text{MS}_W\)는 자유도 \(N - k\)인 일원배치 분산분석의 집단 내 평균제곱
  • \(n_i\)와 \(n_0\)는 각각 집단 \(i\)와 대조군의 표본크기

이다.

상관 구조와 임계값

\(k - 1\)개의 검정통계량 \(t_1, t_2, \ldots, t_{k-1}\)은 모두 \(\bar{Y}_{0\cdot}\)를 포함하므로 독립이 아니다. \(H_0\) 아래에서 이 통계량들은 결합 다변량 \(t\)-분포를 따른다. 모든 처치군의 표본크기가 \(n_i = n\)으로 같을 때 임의의 두 검정통계량 사이의 상관은

\[ \rho = \frac{n}{n + n_0} \]

이다. 대조군과 모든 처치군의 표본크기가 같으면(\(n_0 = n\)) 이는 \(\rho = 1/2\)로 단순해진다.

Dunnett의 임계값 \(d_{\alpha, k-1, \nu}\)(\(\nu = N - k\))는 이 다변량 \(t\)-분포로부터 표로 만들어진다. 상관된 \(k - 1\)개의 비교를 동시에 검정하는 것을 반영하므로 Bonferroni 조정 임계값보다 작고, 그래서 Dunnett 검정의 검정력이 더 높다.

판정 규칙

양측검정: \(|t_i| > d_{\alpha/2, k-1, N-k}\)이면 \(H_0: \mu_i = \mu_0\)을 기각한다.

단측검정(위쪽): \(t_i > d_{\alpha, k-1, N-k}\)이면 \(H_0: \mu_i \leq \mu_0\)을 기각한다.

보기 1. 세 약 제형과 위약 비교. 어떤 제약회사가 세 가지 약 제형을 위약과 비교한다. 반응변수는 증상 감소 점수(클수록 좋다)이다. 각 집단은 \(n = 6\)명이다(\(N = 24\), \(k = 4\)):

집단 표본평균 표본크기
위약(대조군) \(\bar{Y}_0 = 4.2\) \(n_0 = 6\)
약 A \(\bar{Y}_1 = 7.8\) \(n_1 = 6\)
약 B \(\bar{Y}_2 = 5.9\) \(n_2 = 6\)
약 C \(\bar{Y}_3 = 8.5\) \(n_3 = 6\)

일원배치 분산분석에서 자유도 \(N - k = 20\)의 \(\text{MS}_W = 3.2\)를 얻었다. 전체 F-검정이 유의하므로 어느 약이 위약보다 나은지 판정하기 위해 Dunnett 검정으로 넘어간다.

표본크기가 같으므로 각 비교의 표준오차는 동일하다:

풀이
\[ \text{SE} = \sqrt{\text{MS}_W \left(\frac{1}{n_i} + \frac{1}{n_0}\right)} = \sqrt{3.2 \times \frac{2}{6}} = \sqrt{1.067} = 1.033 \]

검정통계량은

\[ t_1 = \frac{7.8 - 4.2}{1.033} = \frac{3.6}{1.033} = 3.49 \]
\[ t_2 = \frac{5.9 - 4.2}{1.033} = \frac{1.7}{1.033} = 1.65 \]
\[ t_3 = \frac{8.5 - 4.2}{1.033} = \frac{4.3}{1.033} = 4.16 \]

이다. 비교가 \(k - 1 = 3\)개이고 자유도 \(\nu = 20\)일 때 \(\alpha = 0.05\) 양측검정의 Dunnett 임계값은 \(d_{0.025, 3, 20} \approx 2.54\)이다.

비교 \(t_i\) \(\lvert t_i\rvert > 2.54\)? 결론
약 A 대 위약 3.49 예 유의
약 B 대 위약 1.65 아니오 유의하지 않음
약 C 대 위약 4.16 예 유의

약 A와 C는 위약보다 유의하게 높은 증상 감소 점수를 낳는다. 약 B는 \(\alpha = 0.05\) 수준에서 위약과 유의하게 다르지 않다.

Dunnett 검정을 언제 쓰는가

Dunnett 검정은 실험 설계가 하나의 기준 집단과의 비교를 포함할 때 최적의 선택이다. 다음 비교가 언제 선호되는지 보여준다:

상황 권장 방법
모든 쌍별 비교 Tukey의 HSD
계획된 비교가 적을 때 Bonferroni
모든 대비(탐색적) Scheffé
각 처치 대 하나의 대조군 Dunnett 검정
분산이 다를 때 Games-Howell

같은 \(k - 1\)개의 대조군 비교에 대해 Dunnett 검정이 Bonferroni보다 강력한 것은, 검정통계량들을 독립으로 취급하지 않고 그들 사이의 양의 상관을 반영하기 때문이다. 예를 들어 집단이 \(k = 5\)개면 Dunnett은 결합분포에서 유도한 임계값으로 비교 4개를 검정하지만, Bonferroni는 상관을 무시하고 각각 \(\alpha/4\)를 써서 조금 더 큰 임계값을 낳는다.

"조금 더 큰"이 얼마인지 재어 보자. 집단당 \(n = 6\)으로 고정하고 \(k\)를 \(3\)에서 \(7\)까지 늘리면서 세 방법의 문턱을 표준오차 단위로 그렸다. Dunnett의 임계값은 균형 설계에서 \(\max_i |t_i|\)의 \(95\) 백분위수를 모의실험으로 구한 것이다.

대조군 비교의 상관을 반영하면 문턱이 세 방법 중 가장 낮다

세 선의 순서가 \(k\) 전 구간에서 뒤집히지 않는다. 더넷 \(<\) 본페로니 \(<\) 투키. \(k = 4\)에서 \(2.53 < 2.61 < 2.80\), \(k = 7\)에서 \(2.68 < 2.80 < 3.13\)이다. 서열의 이유는 각 방법이 지키려는 가족이 다르기 때문이다. 투키는 쌍 \(\binom{k}{2}\)개 전부를 보호하는데 \(k = 7\)이면 그것이 \(21\)개다. 대조군 비교는 그중 \(6\)개뿐이니, 관심 없는 \(15\)개까지 함께 보호하느라 문턱이 올라간 것이다. 자기가 묻지도 않을 질문에 보험을 드는 셈이다.

본페로니와 더넷은 같은 \(k - 1\)개를 보호하는데도 문턱이 다르다. 차이는 상관 하나다. \(n_i = n_0\)인 균형 설계에서 \(\operatorname{Corr}(t_i, t_j) = n/(n + n_0) = 1/2\)이고, 통계량들이 양의 상관을 가지면 "적어도 하나가 문턱을 넘을" 확률이 독립일 때보다 작아진다. 더넷은 그 감소분을 되돌려 받아 문턱을 낮추고, 본페로니는 그것을 포기한다. 격차는 \(k\)가 커질수록 벌어져 \(k = 3\)의 \(0.05\)에서 \(k = 7\)의 \(0.12\)가 된다.

오른쪽은 위 보기 1에 이 문턱들을 얹은 것이다. 모의실험이 준 더넷 임계값 \(2.528\)은 본문이 표에서 읽은 \(2.54\)와 사실상 같다. 약 A(\(t = 3.49\))와 약 C(\(t = 4.16\))는 세 문턱을 모두 넘고 약 B(\(t = 1.65\))는 어느 것도 넘지 못하므로, 이 자료에서는 세 방법의 판정이 갈리지 않는다. 정직하게 말해 \(k = 4\)에서 더넷의 이득은 크지 않다. 그러나 약 B의 \(t\)가 \(2.6\)쯤이었다면 더넷은 기각하고 나머지 둘은 기각하지 못했을 것이고, 용량군이 다섯 여섯으로 늘어나면 그 틈이 자주 벌어진다.

모든 쌍별 비교에 Dunnett 검정을 쓰지 말 것

Dunnett 검정은 오로지 대조군과의 다대일 비교를 위해 설계되었다. 처치끼리 비교해야 한다면(예: 약 A 대 약 B) Tukey의 HSD나 다른 전체 쌍별 방법을 쓰라. 대조군이 끼지 않은 쌍별 비교에 Dunnett 검정을 적용하는 것은 틀렸다. 임계값이 그런 추가 비교를 반영하지 않기 때문이다.

연습문제

연습문제 1. 어떤 임상시험에 위약군(대조군)과 네 가지 약 용량군이 있다. 일원배치 분산분석이 유의하게 나온 뒤, 연구자는 어느 용량이 위약과 다른지 판정하려 한다. 이 비교에 Tukey의 HSD보다 Dunnett 검정이 적절한 이유를 설명하라.

풀이

Dunnett 검정은 하나의 대조군에 대한 다대일 비교를 위해 설계되었다. 집단이 \(k = 5\)개면 Dunnett 검정은 \(k - 1 = 4\)개의 비교(각 용량 대 위약)만 수행하지만, Tukey의 HSD는 \(\binom{5}{2} = 10\)개의 쌍별 비교를 수행한다.

관심을 4개의 관련 비교로 제한하므로 Dunnett 검정은 (4개 검정통계량 사이의 양의 상관을 반영한 다변량 \(t\)-분포에서 나오는) 더 작은 임계값을 쓴다. 10개 비교 전체에 대해 가족단위 오류율을 통제해야 하는 Tukey의 HSD보다 처치와 대조군의 차이를 탐지하는 검정력이 높다.

연습문제 2. 집단이 \(k = 4\)개(대조군 1 + 처치군 3), 집단당 \(n = 10\), \(\text{MSW} = 5.2\)이고 집단 평균이 \(\bar{Y}_0 = 12.0\)(대조군), \(\bar{Y}_1 = 14.8\), \(\bar{Y}_2 = 11.5\), \(\bar{Y}_3 = 16.1\)인 Dunnett 검정에서, 집단 3과 대조군의 비교에 대한 검정통계량을 계산하라.

풀이

처치 \(i\)를 대조군과 비교하는 Dunnett 검정통계량은

\[ t_i = \frac{\bar{Y}_i - \bar{Y}_0}{\sqrt{\text{MSW}(1/n_i + 1/n_0)}} \]

이다. 집단 3 대 대조군에서는

\[ t_3 = \frac{16.1 - 12.0}{\sqrt{5.2(1/10 + 1/10)}} = \frac{4.1}{\sqrt{5.2 \times 0.2}} = \frac{4.1}{\sqrt{1.04}} = \frac{4.1}{1.020} = 4.02 \]

이다. 이 통계량을 처치군 \(k - 1 = 3\)개, 자유도 \(\nu = N - k = 36\)인 Dunnett 임계값 \(d_{\alpha, k-1, \nu}\)와 비교한다.

연습문제 3. Dunnett 검정이 검정통계량 \(t_1, t_2, \ldots, t_{k-1}\) 사이의 상관을 반영하는 이유와, (Bonferroni처럼) 이 상관을 무시하면 왜 더 보수적인 검정이 되는지 설명하라.

풀이

\(k - 1\)개의 검정통계량은 모두 분자와 분모에 같은 대조군 평균 \(\bar{Y}_0\)를 공유하므로 서로 양의 상관을 갖는다. 구체적으로 처치군의 표본크기가 모두 같을 때 \(\text{Corr}(t_i, t_j) = n_i / (n_i + n_0)\)이다.

Dunnett 검정은 이 상관 구조를 반영하는 다변량 \(t\)-분포로 정확한 임계값을 유도한다. 통계량들이 양의 상관을 가지므로, 하나가 크게 나오면 다른 것들도 클 가능성이 높아지고, 따라서 적어도 하나가 문턱을 넘을 결합확률이 독립일 때보다 낮다.

Bonferroni는 이 상관을 무시하고 검정들을 독립인 것처럼 다루어 각 비교에 \(\alpha/(k-1)\)을 쓴다. 그래서 거짓 양성의 확률을 과대평가하고, 임계값이 커져 검정력이 떨어진다.

연습문제 4. 더넷의 임계값을 직접 계산하라. 연습문제 3이 말한 상관 구조를 어떻게 반영하는가?

풀이

상관 구조. 균형 설계에서 \(t_i=\dfrac{\bar y_i-\bar y_0}{\sqrt{2\text{MSE}/n}}\)들은 모두 \(\bar y_0\)를 공유하므로

\[ \operatorname{Corr}(t_i,t_j)=\frac{\operatorname{Cov}(\bar y_i-\bar y_0,\ \bar y_j-\bar y_0)} {\sqrt{2\sigma^2/n}\cdot\sqrt{2\sigma^2/n}} =\frac{\sigma^2/n}{2\sigma^2/n}=\frac12 \]

등상관 \(\rho=1/2\)다. 더넷의 임계값은 이 상관을 가진 다변량 \(t\)의 최대 절댓값의 분위수다.

import numpy as np
from scipy import stats
from statsmodels.stats.libqsturng import qsturng

def dunnett_crit(k, dfe, alpha=0.05, rho=0.5, M=200_000, rng=None):
    """등상관 ρ 인 다변량 t 의 최대 |t| 분위수를 모의실험으로 구한다."""
    p = k - 1
    z = rng.standard_normal((M, p))
    z0 = rng.standard_normal((M, 1))
    x = np.sqrt(rho) * z0 + np.sqrt(1 - rho) * z      # 등상관 구조
    chi = rng.chisquare(dfe, (M, 1))
    t = x / np.sqrt(chi / dfe)
    return np.quantile(np.abs(t).max(1), 1 - alpha)

print("임계값 비교 (α = 0.05, 양측)")
print(f"{'k':>3s} {'n':>4s} {'ν':>5s} {'더넷':>8s} {'본페로니':>9s} "
      f"{'튜키 q/√2':>10s} {'보정 없음':>9s}")
for k, n in [(4, 10), (5, 12), (6, 15), (8, 20)]:
    dfe = k * (n - 1)
    M = k - 1
    dc = dunnett_crit(k, dfe, rng=np.random.default_rng(7))
    bc = stats.t.ppf(1 - 0.05 / (2 * M), dfe)
    tc = qsturng(0.95, k, dfe) / np.sqrt(2)
    nc = stats.t.ppf(0.975, dfe)
    print(f"{k:3d} {n:4d} {dfe:5d} {dc:8.4f} {bc:9.4f} {tc:10.4f} {nc:9.4f}")
임계값 비교 (α = 0.05, 양측)
  k    n     ν       더넷      본페로니    튜키 q/√2     보정 없음
  4   10    36   2.4475    2.5110     2.6933    2.0281
  5   12    55   2.5174    2.5825     2.8204    2.0040
  6   15    84   2.5619    2.6356     2.9165    1.9886
  8   20   152   2.6470    2.7270     3.0735    1.9757

더넷의 임계값이 본페로니보다 항상 작다.

\(k\) 더넷 본페로니 튜키 차이(더넷 대비)
4 2.448 2.511 2.693 본페로니 \(+2.6\%\), 튜키 \(+10.0\%\)
6 2.562 2.636 2.917 \(+2.9\%\), \(+13.9\%\)
8 2.647 2.727 3.074 \(+3.0\%\), \(+16.1\%\)

\(k\)가 커질수록 튜키와의 격차가 벌어진다. 튜키는 \(\binom k2\)개를 보호하는데 더넷은 \(k-1\)개만 보호하기 때문이다.

\(k\) 튜키가 보호하는 수 더넷이 보호하는 수 비
4 6 3 2배
8 28 7 4배

본페로니와의 차이는 작다(2.6~3.0%). 상관 \(\rho=1/2\)가 그만큼만 도움이 되기 때문이다.

상관이 클수록 이득이 커진다.

\(\rho\) 상황 본페로니 대비 이득
0 독립(다른 자료) 없음(시닥과 동일)
0.5 균형 더넷 2.6~3.5%
0.9 매우 높은 상관 크다

불균형이면 \(\rho\)가 달라진다.

\[ \operatorname{Corr}(t_i,t_j)=\sqrt{\frac{n_i n_j}{(n_0+n_i)(n_0+n_j)}} \]

대조군 \(n_0\)이 크면 \(\rho\)가 작아진다. \(n_0=4n\)이면 \(\rho=1/5\)로 떨어져 더넷의 이득이 줄어든다.

역설적이지만 대조군을 키우는 것은 여전히 유리하다. 상관이 줄어 보정의 이득은 작아지지만, 각 비교의 표준오차가 훨씬 작아지기 때문이다(연습문제 7).

연습문제 5. 더넷·본페로니·튜키의 FWER과 검정력을 모의실험으로 비교하라.

풀이
import numpy as np
from scipy import stats
from statsmodels.stats.libqsturng import qsturng

def dunnett_crit(k, dfe, alpha=0.05, rho=0.5, M=200_000, rng=None):
    p = k - 1
    z = rng.standard_normal((M, p))
    z0 = rng.standard_normal((M, 1))
    x = np.sqrt(rho) * z0 + np.sqrt(1 - rho) * z
    chi = rng.chisquare(dfe, (M, 1))
    return np.quantile(np.abs(x / np.sqrt(chi / dfe)).max(1), 1 - alpha)

rng = np.random.default_rng(12004)
B = 5_000
for k, n in [(4, 10), (5, 12), (6, 15)]:
    dfe = k * (n - 1)
    M = k - 1
    dc = dunnett_crit(k, dfe, rng=np.random.default_rng(7))
    bc = stats.t.ppf(1 - 0.05 / (2 * M), dfe)
    tc = qsturng(0.95, k, dfe) / np.sqrt(2)
    a = b = c = pa = pb = pc = 0
    for _ in range(B):
        gs = [rng.normal(0, 1, n) for _ in range(k)]     # 완전 귀무
        m = np.array([g.mean() for g in gs])
        se = np.sqrt(2 * np.array([g.var(ddof=1) for g in gs]).mean() / n)
        ts = np.abs(m[1:] - m[0]) / se
        a += (ts > dc).any()
        b += (ts > bc).any()
        c += (ts > tc).any()

        gs = [rng.normal(0 if i < k - 1 else 1.2, 1, n) for i in range(k)]
        m = np.array([g.mean() for g in gs])
        se = np.sqrt(2 * np.array([g.var(ddof=1) for g in gs]).mean() / n)
        ts = np.abs(m[1:] - m[0]) / se
        pa += ts[-1] > dc
        pb += ts[-1] > bc
        pc += ts[-1] > tc
    print(f"k={k}, n={n}:  임계값 더넷 {dc:.3f} / 본페로니 {bc:.3f} "
          f"/ 튜키 {tc:.3f}")
    print(f"          FWER  더넷 {a / B:.4f} / 본페로니 {b / B:.4f} "
          f"/ 튜키 {c / B:.4f}")
    print(f"          검정력 더넷 {pa / B:.4f} / 본페로니 {pb / B:.4f} "
          f"/ 튜키 {pc / B:.4f}")
k=4, n=10:  임계값 더넷 2.447 / 본페로니 2.511 / 튜키 2.693
          FWER  더넷 0.0536 / 본페로니 0.0458 / 튜키 0.0300
          검정력 더넷 0.5938 / 본페로니 0.5688 / 튜키 0.5006
k=5, n=12:  임계값 더넷 2.517 / 본페로니 2.583 / 튜키 2.820
          FWER  더넷 0.0518 / 본페로니 0.0446 / 튜키 0.0238
          검정력 더넷 0.6540 / 본페로니 0.6284 / 튜키 0.5410
k=6, n=15:  임계값 더넷 2.562 / 본페로니 2.636 / 튜키 2.916
          FWER  더넷 0.0470 / 본페로니 0.0380 / 튜키 0.0164
          검정력 더넷 0.7640 / 본페로니 0.7408 / 튜키 0.6482

더넷만 명목 0.05에 정확히 맞는다(0.047~0.054).

\(k\) 더넷 본페로니 튜키
4 0.054 0.046 0.030
5 0.052 0.045 0.024
6 0.047 0.038 0.016

튜키가 극단적으로 보수적이다(\(k=6\)에서 0.016). 명목의 3분의 1이다.

검정력이 그만큼 갈린다.

\(k\) 더넷 본페로니 튜키 더넷 대 튜키
4 0.594 0.569 0.501 \(+18.6\%\)
5 0.654 0.628 0.541 \(+20.9\%\)
6 0.764 0.741 0.648 \(+17.9\%\)

더넷이 튜키보다 18~21% 더 잡는다.

왜 튜키가 이렇게 불리한가. 튜키는 처치군끼리의 비교까지 보호한다. \(k=6\)이면

비교 개수
대조군 대 처치군 5
처치군끼리 10
합계 15

관심 없는 10개를 위해 문턱을 높이는 셈이다.

본페로니는 더넷의 97% 수준이다. 상관 \(\rho=1/2\)가 주는 이득이 3%뿐이기 때문이다. 더넷을 쓸 수 없는 상황이면 본페로니로 충분하다.

표본 크기로 환산하면. 튜키 대신 더넷을 쓰면 필요한 표본이

\[ \left(\frac{2.916}{2.562}\right)^2=1.30 \]

30% 줄어든다(\(k=6\) 기준). 임상시험에서 이는 상당한 비용 절감이다.

연습문제 6. 임상시험에서는 대개 "약이 위약보다 낫다"만 관심이다. 단측 더넷의 임계값을 구하고 이득을 재라.

풀이
import numpy as np
from scipy import stats

def dunnett_crit(k, dfe, alpha=0.05, rho=0.5, two_sided=True,
                 M=200_000, rng=None):
    p = k - 1
    z = rng.standard_normal((M, p))
    z0 = rng.standard_normal((M, 1))
    x = np.sqrt(rho) * z0 + np.sqrt(1 - rho) * z
    t = x / np.sqrt(rng.chisquare(dfe, (M, 1)) / dfe)
    s = np.abs(t) if two_sided else t
    return np.quantile(s.max(1), 1 - alpha)

print("단측 대 양측 더넷 (α = 0.05)")
print(f"{'k':>3s} {'ν':>5s} {'양측':>8s} {'단측':>8s} {'절감':>7s} "
      f"{'단측 본페로니':>12s}")
for k, n in [(3, 12), (4, 10), (5, 12), (6, 15)]:
    dfe = k * (n - 1)
    M = k - 1
    d2 = dunnett_crit(k, dfe, two_sided=True, rng=np.random.default_rng(11))
    d1 = dunnett_crit(k, dfe, two_sided=False, rng=np.random.default_rng(11))
    b1 = stats.t.ppf(1 - 0.05 / M, dfe)
    print(f"{k:3d} {dfe:5d} {d2:8.4f} {d1:8.4f} "
          f"{100 * (d2 - d1) / d2:6.2f}% {b1:12.4f}")

print("\n표본 크기로 환산 (같은 검정력에 필요한 n 의 비)")
for k, n in [(4, 10), (6, 15)]:
    dfe = k * (n - 1)
    d2 = dunnett_crit(k, dfe, two_sided=True, rng=np.random.default_rng(11))
    d1 = dunnett_crit(k, dfe, two_sided=False, rng=np.random.default_rng(11))
    print(f"  k={k}: (단측/양측)² = {(d1 / d2)**2:.4f}  "
          f"→ 표본을 {100 * (1 - (d1 / d2)**2):.1f}% 줄일 수 있다")
단측 대 양측 더넷 (α = 0.05)
  k     ν       양측       단측      절감      단측 본페로니
  3    33   2.3070   1.9862  13.90%       2.0345
  4    36   2.4459   2.1328  12.80%       2.2129
  5    55   2.5155   2.2115  12.08%       2.3044
  6    84   2.5615   2.2671  11.50%       2.3716

표본 크기로 환산 (같은 검정력에 필요한 n 의 비)
  k=4: (단측/양측)² = 0.7604  → 표본을 24.0% 줄일 수 있다
  k=6: (단측/양측)² = 0.7833  → 표본을 21.7% 줄일 수 있다

단측으로 바꾸면 임계값이 11.5~13.9% 줄고, 표본은 22~24% 절약된다.

\(k\) 양측 단측 절감
3 2.307 1.986 13.90%
4 2.446 2.133 12.80%
6 2.562 2.267 11.50%

임상시험에서 표본 22% 절감은 매우 크다. 환자 수, 비용, 기간이 모두 줄어든다.

단측에서도 더넷이 본페로니보다 낫다. \(k=3\)에서 1.986 대 2.035, \(k=6\)에서 2.267 대 2.372로 2~4% 유리하다. 양측일 때와 같은 폭의 이득이다.

그런데 단측 검정에는 대가가 있다.

위험 내용
반대 방향의 효과를 못 본다 약이 해로우면 탐지하지 못함
사전 정당화 필요 "해로울 리 없다"를 어떻게 아는가
규제기관의 거부 많은 지침이 양측을 요구

첫 줄이 임상시험에서 치명적이다. 신약이 위약보다 나쁠 가능성은 실제로 있고, 그것이야말로 반드시 알아야 할 정보다.

타협안 셋.

방법 내용
양측 검정 + 단측 해석 양측으로 검정하고 방향을 보고
비대칭 배분 유리한 방향에 \(\alpha=0.045\), 반대에 0.005
안전성은 별도 분석 유효성은 단측, 안전성은 별도 감시

두 번째가 규제 현장에서 쓰이는 절충이다.

실무 권고. 탐색 단계에서는 단측 더넷으로 표본을 아끼고, 확증 시험에서는 양측을 쓴다. 그리고 어느 쪽을 왜 골랐는지 사전에 등록한다.

연습문제 7. 대조군과 처치군에 표본을 어떻게 배분해야 하는가? 최적 비를 유도하고 확인하라.

풀이

핵심 통찰. 대조군은 \(k-1\)개의 비교에 모두 쓰인다. 처치군은 하나씩만 쓰인다. 대조군을 키우는 것이 효율적이다.

이론적 최적비(피셔의 제곱근 규칙). 총 \(N\)을 고정할 때

\[ \frac{n_0}{n_i}=\sqrt{k-1} \]

이 근사적으로 최적이다.

import numpy as np
from scipy import stats

def dunnett_crit(k, dfe, ns, alpha=0.05, M=100_000, rng=None):
    """불균형 설계의 더넷 임계값. 상관이 쌍마다 다르다."""
    p = k - 1
    n0 = ns[0]
    rho = np.array([[np.sqrt(ns[i + 1] * ns[j + 1]
                             / ((n0 + ns[i + 1]) * (n0 + ns[j + 1])))
                     if i != j else 1.0 for j in range(p)] for i in range(p)])
    L = np.linalg.cholesky(rho + 1e-12 * np.eye(p))
    x = rng.standard_normal((M, p)) @ L.T
    t = x / np.sqrt(rng.chisquare(dfe, (M, 1)) / dfe)
    return np.quantile(np.abs(t).max(1), 1 - alpha)

k, N = 5, 100
print(f"k={k}개 집단(대조 1 + 처치 4), 총 N={N}. 최적 비 √(k-1) = {np.sqrt(k-1):.3f}")
print(f"{'배분 (n0, n_i)':>20s} {'비':>6s} {'임계값':>8s} {'SE 배수':>8s} "
      f"{'최소 탐지 차이':>13s}")
best = None
for n0 in [12, 16, 20, 24, 28, 32, 36, 40]:
    ni = (N - n0) // (k - 1)
    if ni < 4:
        continue
    ns = [n0] + [ni] * (k - 1)
    dfe = sum(ns) - k
    dc = dunnett_crit(k, dfe, ns, rng=np.random.default_rng(21))
    se = np.sqrt(1 / n0 + 1 / ni)          # σ=1 기준
    mdd = dc * se
    star = " ←" if best is None or mdd < best[1] else ""
    if best is None or mdd < best[1]:
        best = (n0, mdd)
    print(f"{str((n0, ni)):>20s} {n0 / ni:6.2f} {dc:8.4f} {se:8.4f} "
          f"{mdd:13.4f}{star}")
print(f"\n최적 배분: n0 = {best[0]}, 최소 탐지 차이 = {best[1]:.4f}σ")
k=5개 집단(대조 1 + 처치 4), 총 N=100. 최적 비 √(k-1) = 2.000
        배분 (n0, n_i)      비      임계값    SE 배수      최소 탐지 차이
            (12, 22)   0.55   2.4329   0.3589        0.8731 ←
            (16, 21)   0.76   2.4609   0.3318        0.8166 ←
            (20, 20)   1.00   2.4786   0.3162        0.7838 ←
            (24, 19)   1.26   2.4937   0.3071        0.7658 ←
            (28, 18)   1.56   2.5044   0.3021        0.7566 ←
            (32, 17)   1.88   2.5123   0.3001        0.7540 ←
            (36, 16)   2.25   2.5196   0.3005        0.7570
            (40, 15)   2.67   2.5243   0.3028        0.7643

최적 배분: n0 = 32, 최소 탐지 차이 = 0.7540σ

최적이 \(n_0=32\), 비 1.88로 나온다. 이론의 \(\sqrt{k-1}=2\)와 거의 일치한다.

배분 비 최소 탐지 차이 최적 대비
\((12,22)\) 0.55 0.8731 \(+15.8\%\)
\((20,20)\) 1.00 0.7838 \(+4.0\%\)
\((32,17)\) 1.88 0.7540 기준
\((40,15)\) 2.67 0.7643 \(+1.4\%\)

균형 배분보다 4% 좋다. 표본 크기로 환산하면 \((0.784/0.754)^2=1.08\)로 8% 절약이다.

왜 대조군을 키우는 것이 유리한가. 대조군 평균 \(\bar y_0\)는 \(k-1\)개의 비교 모두에 들어간다. 그 오차를 줄이면 모든 비교가 동시에 정밀해진다.

\[ \operatorname{SE}(\bar y_i-\bar y_0)=\sigma\sqrt{\frac{1}{n_0}+\frac{1}{n_i}} \]

\(n_0\)을 키우면 \(k-1\)번 이득을 보고, \(n_i\)를 키우면 한 번 이득을 본다. 그 비대칭이 \(\sqrt{k-1}\)로 나타난다.

그런데 곡선이 평평하다. 비 1.0에서 2.67까지 최소 탐지 차이가 0.754~0.784로 4% 안에 든다. 극단(\(n_0=12\), 비 0.55)만 15.8% 나쁘다.

실무 지침 넷.

  1. \(n_0/n_i\approx\sqrt{k-1}\)을 목표로 한다(\(k=5\)면 2배).
  2. 정확히 맞출 필요는 없다. 1.5~2.5 구간이면 거의 최적이다.
  3. 대조군을 처치군보다 작게 하지 않는다. 그것이 가장 큰 손실이다.
  4. 윤리적 제약(위약군 최소화)이 있으면 균형이 차선이다(4% 손실).

세 번째가 실무에서 자주 어긋난다. "처치군이 관심사이니 처치군을 키우자"는 직관이 정확히 반대다.

연습문제 8. 연습문제 2의 자료로 네 비교를 모두 수행하고 보고문을 작성하라.

풀이
import numpy as np
from scipy import stats

def dunnett_crit(k, dfe, alpha=0.05, rho=0.5, M=200_000, rng=None):
    p = k - 1
    z = rng.standard_normal((M, p))
    z0 = rng.standard_normal((M, 1))
    x = np.sqrt(rho) * z0 + np.sqrt(1 - rho) * z
    t = x / np.sqrt(rng.chisquare(dfe, (M, 1)) / dfe)
    return np.quantile(np.abs(t).max(1), 1 - alpha)

k, n, MSW = 4, 10, 5.2
dfe = k * (n - 1)
means = np.array([12.0, 14.8, 11.5, 16.1])
names = ["대조", "처치1", "처치2", "처치3"]
se = np.sqrt(2 * MSW / n)
dc = dunnett_crit(k, dfe, rng=np.random.default_rng(31))
bc = stats.t.ppf(1 - 0.05 / (2 * (k - 1)), dfe)

print(f"MSW = {MSW}, ν = {dfe}, SE(차이) = {se:.4f}")
print(f"더넷 임계값 = {dc:.4f},  본페로니 = {bc:.4f}")
print(f"\n{'비교':>16s} {'차이':>8s} {'t':>8s} "
      f"{'더넷 95% 구간':>22s} {'판정':>6s}")
for i in range(1, k):
    d = means[i] - means[0]
    t = d / se
    print(f"{names[i] + ' - 대조':>16s} {d:8.2f} {t:8.4f} "
          f"[{d - dc * se:9.3f},{d + dc * se:9.3f}] "
          f"{'기각' if abs(t) > dc else '  -':>6s}")
MSW = 5.2, ν = 36, SE(차이) = 1.0198
더넷 임계값 = 2.4549,  본페로니 = 2.5110

              비교       차이        t              더넷 95% 구간     판정
        처치1 - 대조     2.80   2.7456 [    0.296,    5.304]     기각
        처치2 - 대조    -0.50  -0.4903 [   -3.004,    2.004]      -
        처치3 - 대조     4.10   4.0204 [    1.596,    6.604]     기각

처치 1과 3이 대조군보다 유의하게 높다. 연습문제 2의 \(t_3=4.02\)가 재현된다.

비교 차이 \(t\) 95% 구간 판정
처치1 \(-\) 대조 \(+2.80\) 2.746 \([0.30,\ 5.30]\) 기각
처치2 \(-\) 대조 \(-0.50\) \(-0.490\) \([-3.00,\ 2.00]\) —
처치3 \(-\) 대조 \(+\mathbf{4.10}\) 4.020 \([1.60,\ 6.60]\) 기각

처치1이 아슬아슬하다(\(t=2.746\) 대 임계값 2.455). 본페로니 기준 2.511과 비교해도 기각이지만, 튜키 기준 2.693과는 거의 붙어 있다.

더넷을 쓴 덕분에 처치1이 기각된다. 튜키였다면 \(2.746>2.693\)으로 여전히 기각이지만 훨씬 아슬아슬했다.

보고문.

위약군(대조)과 세 가지 처치군을 비교했다(각 군 n = 10).

일원배치 분산분석:  MSW = 5.2,  ν = 36

대조군과의 비교에만 관심이 있으므로 더넷 검정을 사용했다
(모든 쌍을 비교하는 튜키 HSD 보다 검정력이 약 19% 높다).

  비교              차이    95% 동시구간        판정
  처치1 vs 대조     +2.80   [ 0.30,  5.30]     유의
  처치2 vs 대조     -0.50   [-3.00,  2.00]     유의하지 않음
  처치3 vs 대조     +4.10   [ 1.60,  6.60]     유의

처치 1 과 3 이 대조군보다 반응이 높았다. 처치 2 는 대조군과
구별되지 않았으나, 구간이 [-2.99, 3.00]{=5.0} 로 넓어
3 수준의 차이를 배제하지는 못한다.

마지막 문장이 중요하다. 처치2의 구간 폭이 약 5.0으로, 차이가 없다고 단정할 수 없다. \(n=10\)의 한계다.

처치군끼리 비교하고 싶다면. 더넷은 대조군과의 비교만 보호한다. 처치1 대 처치3을 추가로 비교하려면

방법 내용
튜키로 전환 모든 쌍을 처음부터 보호
더넷 + 별도 보정 추가 비교에 별도 \(\alpha\) 배분
사전에 결정 무엇을 비교할지 미리 정한다

사후에 "처치끼리도 궁금하다"고 추가하면 통제가 무효가 된다.

연습문제 9. 대조군이 둘 이상이거나 여러 시점에서 비교하는 확장 상황을 어떻게 다루는가?

풀이

세 가지 확장 상황.

상황 예
대조군 둘 위약 + 표준치료
여러 시점 4주, 8주, 12주
여러 반응변수 주요 평가변수 + 부차 변수

(가) 대조군 둘. 비교의 수가 \(2(k-2)\)로 늘어난다.

위약 vs 약1, 약2, 약3        (3개)
표준치료 vs 약1, 약2, 약3     (3개)
                              ─────
                               6개

상관 구조가 복잡해진다. 같은 대조군을 쓰는 비교끼리는 \(\rho=1/2\), 다른 대조군이면 더 작다. 일반적인 다변량 \(t\) 임계값을 수치적으로 구해야 한다.

접근 내용
본페로니(\(M=6\)) 간단하고 안전, 약간 보수적
일반 다변량 \(t\) 정확하지만 구현이 복잡
계층적 검정 위약 비교를 먼저, 통과한 것만 표준치료와

세 번째가 임상시험의 표준 전략이다. 고정 순서 검정(fixed-sequence)이라 하며, 순서를 사전에 정하면 보정 없이도 FWER이 통제된다.

(나) 여러 시점. 같은 환자를 반복 측정하므로 독립성이 깨진다.

잘못된 방법: 각 시점마다 더넷을 따로 수행
   → 시점 간 상관을 무시
   → 다중성도 통제되지 않음

올바른 방법:
   1. 주요 시점 하나를 사전에 지정 (주 평가변수)
   2. 나머지는 부차 분석으로 표시
   또는
   3. 혼합효과 모형 + 시점별 대비

(다) 계층적 검정의 원리. 검정 순서를 사전에 정하고, 앞이 유의할 때만 다음으로 진행한다.

H1: 고용량 vs 위약   →  p = 0.003  ✓ 계속
H2: 중용량 vs 위약   →  p = 0.021  ✓ 계속
H3: 저용량 vs 위약   →  p = 0.180  ✗ 중단

→ H1, H2 를 α = 0.05 그대로 검정해도 FWER 이 0.05 로 통제된다

왜 보정이 필요 없는가. \(H_1\)이 참이면 그 단계에서 멈출 확률이 \(1-\alpha\)이므로, \(H_2\)까지 갈 확률 자체가 \(\alpha\)로 제한된다.

조건 둘.

  1. 순서를 사전에 정해야 한다. 결과를 보고 정하면 무효.
  2. 하나가 실패하면 이후는 모두 "검정하지 않음"이다. 유의해 보여도 주장할 수 없다.

두 번째가 실무의 부담이다. 저용량이 유의해 보여도 중용량이 실패했으면 보고할 수 없다.

절충 — 그래프 기반 절차. 각 가설에 \(\alpha\)를 배분하고, 기각되면 남은 \(\alpha\)를 다른 가설로 흘려보낸다. 유연하면서 FWER을 통제한다.

초기 배분:  H1: 0.03,  H2: 0.02,  H3: 0.00

H1 기각 → H1 의 0.03 을 H2, H3 에 분배
          H2: 0.02 + 0.015 = 0.035
          H3: 0.00 + 0.015 = 0.015

요약.

상황 권장
대조군 하나, 비교 \(k-1\)개 더넷
대조군 둘 본페로니 또는 계층적 검정
여러 시점 주요 시점 지정 + 혼합효과 모형
용량-반응 구조 계층적 검정(고용량부터)
복잡한 구조 그래프 기반 절차

연습문제 10. 더넷 검정의 사용 지침을 정리하라.

풀이

한 줄 정의. 대조군과의 \(k-1\)개 비교만 보호하는 다중비교 절차다.

\[ |\bar y_i-\bar y_0|>d_{\alpha,k-1,\nu} \sqrt{\text{MSE}\left(\frac{1}{n_0}+\frac{1}{n_i}\right)} \]

\(d\)는 등상관 \(\rho=1/2\)인 다변량 \(t\)의 최대 절댓값 분위수다.

핵심 수치 다섯.

사실 값
비교 사이의 상관(균형) \(\rho=1/2\)
더넷의 FWER 0.047~0.054(정확)
같은 상황 튜키 0.016~0.030(보수적)
튜키 대비 검정력 이득 \(+18\sim21\%\)
단측으로 바꿀 때 표본 절감 22~24%

언제 쓰는가.

상황 절차
대조군과의 비교만 관심 더넷
처치군끼리도 비교 튜키
이분산 더넷 T3 또는 웰치형 더넷
대조군 둘 이상 본페로니 또는 계층적 검정
용량-반응 순서가 있음 계층적 검정, 추세 검정

왜 튜키를 쓰면 안 되는가. 관심 없는 \(\binom{k-1}{2}\)개의 비교까지 보호하느라 문턱을 불필요하게 높인다.

\(k\) 관심 비교 튜키가 보호하는 수 낭비
4 3 6 2배
6 5 15 3배
8 7 28 4배

구현.

scipy >= 1.11:  scipy.stats.dunnett(*treatments, control=ctrl)
R:              multcomp::glht(fit, linfct = mcp(group = "Dunnett"))
직접 계산:       다변량 t 의 최대 |t| 분위수를 모의실험으로
                (연습문제 4의 dunnett_crit)

자주 하는 실수 넷.

실수 대가
대조군 비교만 하면서 튜키 검정력 20% 손실
사후에 처치군끼리 비교 추가 통제 무효
단측을 정당화 없이 사용 해로운 효과를 놓침
여러 시점에 각각 적용 다중성·상관 무시

두 번째가 흔하다. "대조군 비교를 먼저 하고, 결과를 보니 처치1과 처치3도 궁금해졌다"는 순간 더넷의 보장이 깨진다.

설계 지침 셋.

  1. 무엇을 비교할지 사전에 정한다. 대조군만이면 더넷, 전부면 튜키.
  2. 대조군을 처치군의 \(\sqrt{k-1}\)배로 잡는다(연습문제 7).
  3. 단측 여부를 사전 등록한다.

보고 형식.

위약군과 세 처치군을 비교했다(각 n = 10).
대조군과의 비교에만 관심이 있으므로 더넷 검정(양측, FWER = 0.05)을
사용했다. 모든 쌍을 비교하는 튜키 HSD 보다 검정력이 약 19% 높다.

  처치1 vs 위약   +2.80  [ 0.30,  5.30]   유의
  처치2 vs 위약   -0.50  [-3.00,  2.00]   유의하지 않음
  처치3 vs 위약   +4.10  [ 1.60,  6.60]   유의

"대조군과의 비교에만 관심이 있으므로"가 핵심 문장이다. 절차의 선택을 연구 질문으로 정당화한다.

한 문장. 더넷은 "모두와 모두"가 아니라 "모두와 하나"를 비교할 때의 정확한 절차이며, 그 좁은 목표 덕분에 20%의 검정력을 벌어들인다.


정리하며

더넷 검정은 대조군과의 비교만 필요할 때 쓴다.

  • 비교가 \(\binom k2\) 개가 아니라 \(k-1\) 개다. 모든 쌍을 볼 필요가 없으면 보지 않는 것이 옳고, 그만큼 다중검정 부담이 줄어 검정력이 높아진다.
  • 핵심 통찰은 \(k-1\) 개 통계량이 독립이 아니라는 것이다. 모두 대조군 평균을 공유하므로 양의 상관을 가지며, 더넷의 임계값이 그 상관을 반영한다. 본페로니처럼 독립을 가정하고 나누면 필요 이상으로 보수적이다.
  • 투키보다도 낫다. 투키는 모든 쌍을 보호하느라 임계값이 크지만, 다대일 비교만 필요하다면 더넷이 정확히 그만큼만 보호한다.
  • 단측으로 세울 수 있다. "처치가 대조보다 나은가"만 묻는다면 단측이 자연스럽고 검정력이 더 높다. 방향은 사전에 정해야 한다.
  • 용량–반응 설계의 표준 도구이며, 위약군 대 여러 용량이 전형적인 예다.

다음 절 Games-Howell로 넘어간다. 등분산이 깨졌을 때의 사후검정이다.