ANOVA 의 Robust 대안 — Welch, Brown-Forsythe, Kruskal-Wallis

가정 위반 시 강건한 대안의 원리·절차·트레이드오프

ANOVA F 검정의 가정 (정규성, 등분산성) 이 깨졌을 때 사용 가능한 강건 (robust) 대안을 정리한다. Welch’s F, Brown-Forsythe F, Kruskal-Wallis 비모수 검정, permutation 과 bootstrap 의 원리·계산·검정력 비교를 다룬다.

Experimentation
Fundamentals
저자

Kwangmin Kim

공개

2026년 05월 08일

1 도입 — 가정이 깨졌을 때

A-MAX3-4 에서 ANOVA F 검정이 가정에 의존함을 봤다. 그러나 실제 자료는 가정을 완벽하게 만족하지 않는다. 강건 (robust) 대안은 가정 위반 시에도 정확한 (또는 보수적) 검정을 보장한다.

이 글의 4 가지 대안:

  1. Welch’s F — 등분산 위반에 강건
  2. Brown-Forsythe F — 정규성 + 등분산 모두 약화
  3. Kruskal-Wallis — 비모수 (분포 가정 X)
  4. Permutation / Bootstrap — 모든 가정 약화

2 Welch’s F — 등분산 가정 완화

2.1 표준 F 의 한계

표준 F 통계량은 풀링된 분산 \(s_p^2 = \text{MS}_W\) 를 사용한다.

\[ F = \frac{\text{MS}_B}{\text{MS}_W} = \frac{\text{SS}_B / (J-1)}{\text{SS}_W / (n-J)} \]

이 식은 모든 그룹이 같은 분산 이라는 가정에 의존한다. 위반 시 검정 분포가 정확한 \(F_{J-1, n-J}\) 가 아니다.

2.2 Welch’s F

정의: Welch’s F (Welch 1951)

그룹별로 다른 분산을 허용하는 ANOVA 변형. 그룹 평균에 분산의 역수 로 가중치를 주어 검정 통계량을 구성한다.

\[ F^* = \frac{\sum_{j=1}^{J} w_j (\bar{Y}_j - \bar{Y}^*)^2 / (J - 1)}{1 + \frac{2(J - 2)}{J^2 - 1} \sum_j \frac{(1 - w_j / w)^2}{n_j - 1}} \]

여기서 \(w_j = n_j / s_j^2\), \(w = \sum w_j\), \(\bar{Y}^* = \sum w_j \bar{Y}_j / w\).

자유도: \(\text{df}_1 = J - 1\) (분자), \(\text{df}_2\) 는 Welch-Satterthwaite 근사로 계산.

2.3 직관

가중치 \(w_j = n_j / s_j^2\)분산이 작은 그룹 에 더 큰 영향을 준다. 이는 분산이 큰 그룹의 부정확한 평균이 검정에 과한 영향을 주지 않도록 막는 보정이다.

자유도도 그룹별 분산에 따라 조정된다. 분산이 매우 다르면 분모 자유도가 줄어들어 임계값이 커지고 검정이 보수적 이 된다.

2.4 사용 권장

R 의 oneway.test() 와 Python 의 scipy.stats.alexandergovern 또는 pingouin.welch_anova() 가 Welch’s F 를 제공한다.

직관 — 왜 Welch 가 표준이 되어야 하는가

Ruxton (2006) 은 항상 Welch 를 쓰라 고 권장한다. 이유:

  • 등분산 충족 시 Welch ≈ 표준 F (검정력 거의 동일)
  • 등분산 위반 시 Welch ≫ 표준 F (정확성 보장)
  • “등분산 검정 후 선택” 절차는 이중 검정으로 \(\alpha\) 인플레이션
  • Welch 는 지는 게임이 없다

R 의 t.test()oneway.test()기본값으로 Welch 를 사용하는 것은 이 권고의 반영이다. Python 의 scipy.stats.ttest_ind()equal_var=False 가 권장이다.

3 Brown-Forsythe F — 정규성 약화

3.1 원리

Brown-Forsythe (1974) 는 그룹 평균 대신 그룹 중앙값 을 사용한다. 이는 비대칭 자료와 이상치에 강건하다.

\[ \text{BF} = \frac{\sum n_j (\bar{Y}_j - \bar{Y})^2 / (J - 1)}{\sum_j (1 - n_j / n) s_j^2} \]

분모가 표준 F 와 다르다. 분산을 풀링하지 않고 각 그룹의 가중치 평균 으로 계산한다.

3.2 자유도

분모 자유도는 Welch-Satterthwaite 와 유사한 근사로 계산된다.

3.3 사용 시점

  • 자료가 강하게 비대칭
  • 이상치가 다수 존재
  • 표본 크기가 작음 (CLT 가 약함)

4 Kruskal-Wallis — 비모수 ANOVA

4.1 원리

정의: Kruskal-Wallis 검정

자료의 순위 (rank) 를 사용해 그룹 차이를 검정하는 비모수 절차.

  1. 모든 자료를 합쳐 순위를 매긴다 (\(1, 2, \ldots, n\)).
  2. 각 그룹의 순위 합 \(R_j\) 를 계산한다.
  3. 통계량:

\[ H = \frac{12}{n(n+1)} \sum_{j=1}^{J} \frac{R_j^2}{n_j} - 3(n+1) \]

\(H\) 는 큰 \(n\) 에서 \(\chi^2_{J-1}\) 분포에 근사한다.

4.2 가설

\[ H_0: \text{모든 그룹이 같은 분포에서 추출됨} \]

이 가설은 평균 차이가 아니라 분포 동일성 에 대한 것이다. 그러나 그룹 간 분포가 같은 형태이고 위치만 다른 경우, Kruskal-Wallis 는 위치 (중앙값) 차이의 검정으로 해석된다.

4.3 t 검정 (Mann-Whitney U) 과의 관계

\(J = 2\) 일 때 Kruskal-Wallis 는 Mann-Whitney U 검정 과 동등하다. 즉 Kruskal-Wallis 는 Mann-Whitney 의 J 그룹 일반화 이다.

4.4 검정력

자료 분포 Kruskal-Wallis 검정력 (vs F)
정규 약 95.5 % (F 가 강함)
비대칭 (지수, log-normal) 종종 더 높음 (KW 가 강함)
두꺼운 꼬리 (t 분포 자유도 작음) KW 가 강함

따라서 자료가 정규에서 멀어질수록 Kruskal-Wallis 의 상대적 우위가 커진다.

직관 — 순위 변환의 강건성

Kruskal-Wallis 가 이상치에 강건한가?

원자료에서 한 점이 1000 처럼 매우 크면, 표본 평균과 분산이 그 한 점에 지배 된다. 그러나 순위 변환에서는 그 점이 가장 큰 순위 1 개를 받을 뿐이다. 다음 큰 점이 999 이든 100 이든, 둘 다 동일한 순위 차이 1 만 가진다.

압축 이 이상치 영향을 제한한다. 동시에 분포 형태에 무관한 검정이 가능하다.

대가는 세부 정보의 손실 이다. 두 점이 1000 과 999 차이라도 1 과 2 차이로 변환되면, 자료의 척도 정보가 사라진다. 따라서 자료가 정규에 가까우면 정규 이론 검정이 더 효율적이다.

5 Permutation / Bootstrap — 모든 가정 약화

5.1 Permutation 검정 (J 그룹)

A-MAX2-1 에서 두 그룹 사례를 다뤘다. J 그룹 일반화는 다음과 같다.

  1. 자료의 그룹 라벨 을 무작위로 재배치한다.
  2. 재배치된 자료에서 검정 통계량 (예: F, MS_B) 을 계산한다.
  3. 이를 \(B\) 회 반복한다.
  4. 관측 통계량보다 극단적인 비율이 p 값.

이 절차는 어떤 통계량에도 적용 가능 하며 분포 가정이 없다.

5.2 Bootstrap

부트스트랩은 검정보다 추정 에 가까운 도구다. 각 그룹 평균과 차이의 신뢰 구간 을 비모수적으로 구성한다. 자세한 절차는 후속 글 A-BUI7-* 에서 다룬다.

6 절차 비교 표

절차 등분산 정규성 독립성 자료 척도
표준 F 가정 가정 가정 양적
Welch’s F 약화 가정 가정 양적
Brown-Forsythe F 약화 약화 가정 양적
Kruskal-Wallis 약함 불필요 가정 순위 가능
Permutation 약함 불필요 약화 자유
Bootstrap 약함 불필요 가정 자유

이 표가 어떤 대안을 언제 쓰는가 의 가이드이다.

7 검정력 비교

가정이 충족된 정규 자료에서:

절차 상대 검정력 (F = 100 %)
표준 F 100 %
Welch’s F ≈ 100 %
Brown-Forsythe 약 95 %
Kruskal-Wallis 약 95.5 %
Permutation ≈ 100 %

가정이 충족되면 표준 F 가 가장 강력하지만, robust 대안의 손실이 크지 않다 (대부분 5 % 이내).

가정이 위반된 비정규 자료에서:

절차 위반 유형 상대 검정력
표준 F 등분산 위반 \(\alpha\) 부정확
Welch’s F 등분산 위반 안정
Brown-Forsythe 강한 비대칭 안정
Kruskal-Wallis 비정규 종종 더 높음

8 결정 트리 — 어떤 절차를 선택할까

자료 진단
   ↓
독립성 위반?  Yes → 혼합 모형, GEE
   ↓ No
표본 크기 충분 (n_j > 30)?
   Yes → CLT 작동
       등분산?  Yes → 표준 F 또는 Welch (둘 다 OK)
       No  → Welch's F
   No → 표본 작음
       정규성 OK?
           Yes → 등분산 OK?  Yes → 표준 F
                          No  → Welch
           No → 비대칭 약함  → Brown-Forsythe
                강한 비대칭 → Kruskal-Wallis
                일반        → Permutation

9 신뢰 구간 — Robust 대안과의 호환

각 절차에서 효과 크기의 신뢰 구간:

절차 CI 구성
표준 F t 분포 기반 닫힌 형태
Welch’s F Welch-Satterthwaite 자유도 사용
Brown-Forsythe 근사 t
Kruskal-Wallis Hodges-Lehmann 추정량
Permutation 부트스트랩 또는 직접

이 절차들 모두 효과 크기 + CI 보고 를 지원한다.

10 자료 변환과의 비교

A-MAX3-4 에서 자료 변환 (log, sqrt 등) 도 가정 위반의 한 해법이라 했다. Robust 절차와 변환의 비교:

측면 자료 변환 Robust 절차
추론 정확도 변환된 척도에서만 정확 원 척도에서 정확
해석 변환된 단위로 모호 원 단위 유지
적용 범위 분포 형태에 의존 일반적
검정력 변환이 잘 맞으면 강함 안정적

권장: 간단한 변환 (log) 으로 가정 위반이 해결되면 변환을 우선 시도. 변환이 어렵거나 해석을 해치면 robust 절차 사용.

11 코드 예시 — 4 가지 절차 비교

import numpy as np
import pandas as pd
from scipy.stats import f_oneway, kruskal, levene
from statsmodels.stats.weightstats import ttest_ind
import scipy.stats as stats

np.random.seed(42)
n_each = 30

# 시뮬레이션 1: 등분산 + 정규
data_normal = {
    'A': np.random.normal(5.0, 1.0, n_each),
    'B': np.random.normal(5.5, 1.0, n_each),
    'C': np.random.normal(6.0, 1.0, n_each)
}

# 시뮬레이션 2: 등분산 위반
data_uneq = {
    'A': np.random.normal(5.0, 0.5, n_each),
    'B': np.random.normal(5.5, 1.0, n_each),
    'C': np.random.normal(6.0, 2.0, n_each)
}

# 시뮬레이션 3: 강한 비대칭
data_skew = {
    'A': np.random.exponential(1.0, n_each),
    'B': np.random.exponential(1.5, n_each),
    'C': np.random.exponential(2.0, n_each)
}

def compare_methods(data, label):
    print(f"\n=== {label} ===")
    groups = list(data.values())
    F, p_F = f_oneway(*groups)
    print(f"표준 F:        F = {F:.3f}, p = {p_F:.4f}")

    # Welch — pingouin 또는 수동 (statsmodels 에 직접 없음)
    # 여기서는 간이 구현
    n_j = np.array([len(g) for g in groups])
    means = np.array([g.mean() for g in groups])
    vars_ = np.array([g.var(ddof=1) for g in groups])
    w = n_j / vars_
    w_total = w.sum()
    weighted_mean = (w * means).sum() / w_total
    J = len(groups)
    F_welch_num = (w * (means - weighted_mean)**2).sum() / (J - 1)
    correction = 1 + 2*(J-2)/(J**2-1) * sum((1 - w/w_total)**2 / (n_j-1))
    F_welch = F_welch_num / correction
    df2_welch = (J**2 - 1) / (3 * sum((1 - w/w_total)**2 / (n_j-1)))
    p_welch = 1 - stats.f.cdf(F_welch, J-1, df2_welch)
    print(f"Welch's F:     F = {F_welch:.3f}, df2 = {df2_welch:.1f}, p = {p_welch:.4f}")

    # Kruskal-Wallis
    H, p_kw = kruskal(*groups)
    print(f"Kruskal-Wallis: H = {H:.3f}, p = {p_kw:.4f}")

    # Levene 진단
    stat_lev, p_lev = levene(*groups, center='median')
    print(f"Brown-Forsythe (등분산 진단): stat = {stat_lev:.3f}, p = {p_lev:.4f}")

    # Permutation 검정 (간이)
    obs_F = F
    pooled = np.concatenate(groups)
    extreme = 0
    n_perm = 5000
    for _ in range(n_perm):
        np.random.shuffle(pooled)
        perm_groups = [pooled[i*n_each:(i+1)*n_each] for i in range(J)]
        F_perm, _ = f_oneway(*perm_groups)
        if F_perm >= obs_F:
            extreme += 1
    print(f"Permutation:    p = {extreme/n_perm:.4f}")

compare_methods(data_normal, "등분산 + 정규")
compare_methods(data_uneq, "등분산 위반")
compare_methods(data_skew, "강한 비대칭")

세 시나리오에서 절차의 상대적 신뢰성 을 비교할 수 있다. 일반적으로:

  • 가정 충족 시: 모든 절차의 결론 일치
  • 가정 위반 시: 표준 F 와 robust 대안이 다른 결론 → robust 신뢰

12 Robust 절차의 한계

각 절차에도 한계가 있다.

절차 한계
Welch’s F 정규성은 여전히 가정
Brown-Forsythe 검정력이 표준 F 보다 낮음
Kruskal-Wallis 척도 정보 손실
Permutation 계산 비용

따라서 robust 절차는 대체 가 아니라 robustness check 로 사용하는 것이 권장된다. 표준 F 와 robust 대안을 모두 보고하여 결과의 강건성 을 보여주는 것이 좋다.

13 결과 보고 — 모범 형식

Mood induction 의 효과를 검정했다 (n = 30, 그룹당 10 명).
표준 ANOVA: F(2, 27) = 22.5, p < 0.001, η² = 0.625.
Welch's F: F(2, 18.0) = 22.5, p < 0.001 (등분산 가정 약화).
Brown-Forsythe: 자료가 강한 비대칭이 아니므로 미수행.
Kruskal-Wallis (robustness check): H(2) = 23.0, p < 0.001.

결론: 모든 절차가 일관된 결론. 그룹 간 차이가 강하다.
사후 비교 (Tukey HSD): Pleasant > Neutral > Unpleasant (모두 p < 0.001).

이런 다중 절차 결과 보고결과의 robustness 를 시각적으로 보여 준다.

14 Robust Methods 의 추가 변형

14.1 Trimmed Means

극단값 (양 극단 일정 비율) 제외 후 평균.

import numpy as np
from scipy.stats import trim_mean

data = [1, 2, 3, 4, 5, 6, 100]  # 이상치 100
mean = np.mean(data)  # 17.3
trim_5 = trim_mean(data, 0.10)  # 10 % trimming
trim_20 = trim_mean(data, 0.20)
print(f"평균: {mean:.2f}")
print(f"10 % trimmed: {trim_5:.2f}")
print(f"20 % trimmed: {trim_20:.2f}")

이상치에 robust. 그러나 검정력 약간 손실.

14.2 Yuen’s t-test

Trimmed means 의 t-test 변형. 이분산 + 이상치 모두 robust.

14.3 M-estimators

Maximum likelihood 의 robust 변형. Huber’s M-estimator 가 표준.

import statsmodels.robust as smrob

# Huber's M-estimator (예시)
# rlm = smrob.linear_model.RLM(...)

15 Robust ANOVA 의 시뮬레이션 비교

import numpy as np
from scipy.stats import f_oneway, kruskal, levene

np.random.seed(42)
n_sim = 1000
n_per = 30
J = 3

# 시나리오 1 - 이상 (정규 + 등분산)
type_I_normal = {'F': 0, 'KW': 0}
for _ in range(n_sim):
    groups = [np.random.normal(0, 1, n_per) for _ in range(J)]
    if f_oneway(*groups)[1] < 0.05:
        type_I_normal['F'] += 1
    if kruskal(*groups)[1] < 0.05:
        type_I_normal['KW'] += 1

# 시나리오 2 - 등분산 위반
type_I_uneq = {'F': 0, 'Welch': 0}
for _ in range(n_sim):
    groups = [np.random.normal(0, sigma, n_per) for sigma in [1, 2, 3]]
    if f_oneway(*groups)[1] < 0.05:
        type_I_uneq['F'] += 1
    # Welch (간이)
    n = sum(len(g) for g in groups)
    ws = [len(g)/g.var(ddof=1) for g in groups]
    # ...

print("이상 시나리오 (Type I):")
print(f"  F: {type_I_normal['F']/n_sim:.3f}, KW: {type_I_normal['KW']/n_sim:.3f}")
print("등분산 위반:")
print(f"  F: {type_I_uneq['F']/n_sim:.3f}")

16 A/B 테스트의 Robust 분석 모범

import numpy as np
from scipy.stats import ttest_ind, mannwhitneyu, levene

# 가상 매출 자료 (우편향)
np.random.seed(42)
control = np.random.lognormal(4, 1.0, 1000)
treatment = np.random.lognormal(4.05, 1.0, 1000)

# 1. Welch t (이분산 robust)
t_stat, p_t = ttest_ind(treatment, control, equal_var=False)
print(f"Welch t: t = {t_stat:.3f}, p = {p_t:.4f}")

# 2. Mann-Whitney (분포 robust)
u_stat, p_u = mannwhitneyu(treatment, control, alternative='two-sided')
print(f"Mann-Whitney U: U = {u_stat:.0f}, p = {p_u:.4f}")

# 3. 등분산 검정
stat, p_lev = levene(treatment, control, center='median')
print(f"Brown-Forsythe: stat = {stat:.3f}, p = {p_lev:.4f}")

# 4. Permutation
B = 5000
obs_diff = treatment.mean() - control.mean()
combined = np.concatenate([treatment, control])
perm_diffs = []
for _ in range(B):
    np.random.shuffle(combined)
    perm_diffs.append(combined[:1000].mean() - combined[1000:].mean())
p_perm = np.mean(np.abs(perm_diffs) >= np.abs(obs_diff))
print(f"Permutation: p = {p_perm:.4f}")

# 결과 일관 → robust
print("\n결과 일관성:")
print(f"  Welch p: {p_t:.4f}")
print(f"  Mann-Whitney p: {p_u:.4f}")
print(f"  Permutation p: {p_perm:.4f}")

3 가지 robust 검정의 결과 일관robustness 의 증거.

17 Ch.3 마무리

Maxwell Ch.3 의 6 단계 흐름이 끝난다.

  1. GLM 도입 (A-MAX3-1)
  2. One/Two-Group (A-MAX3-1)
  3. General Case (A-MAX3-2)
  4. F 검정 + 효과 크기 (A-MAX3-3)
  5. 가정 진단 (A-MAX3-4)
  6. Robust 대안 (이 글)

Ch.3 가 일원 ANOVA의 완전한 토대 를 제공했다. 이제 Ch.4 는 어느 그룹 사이 차이가 있는지를 묻는 대비 (contrast) 분석으로 확장한다. 이는 후속 시리즈 A-MAX4-* 에서 다룬다.

18 관련 주제

선행 지식

후속 주제 (Phase A)

  • A-MAX4-* (Individual Comparisons / Contrasts)
  • A-MAX5-* (Multiple Comparisons)
  • A-BUI7-* (Bootstrap)
  • A-WOO14-* (Permutation 일반)

다른 카테고리 연결

Subscribe

Enjoy this blog? Get notified of new posts by email: