모수 검정의 가정이 깨질 때
t-검정과 ANOVA는 모수 검정(parametric test)입니다. "데이터가 정규분포를 따른다"는 가정에 의존합니다. 그런데 실제 데이터는 이 가정을 항상 만족하지 않습니다.
다음 상황에서는 비모수 검정을 고려합니다.
- 표본이 작고(n < 20) Shapiro-Wilk 검정에서 p < 0.05
- 데이터가 분명히 비대칭(강한 왜도)이거나 심한 이상치가 있음
- 데이터가 순위(rank) 또는 리커트 척도
- 정규성 변환(log, sqrt)을 해도 가정이 충족되지 않음
비모수 검정(non-parametric test)은 정규성 가정 없이 데이터의 순위를 기반으로 작동합니다.
분석 흐름도
데이터 있음
│
├─ 두 집단 비교?
│ │
│ ├─ 독립 집단? → Shapiro-Wilk 정규성 확인
│ │ │
│ │ ├─ 정규성 OK → t.test(independent)
│ │ └─ 정규성 위반 → wilcox.test(independent)
│ │
│ └─ 대응 집단? → 차이값의 Shapiro-Wilk 확인
│ │
│ ├─ 정규성 OK → t.test(paired=TRUE)
│ └─ 정규성 위반 → wilcox.test(paired=TRUE)
│
└─ 세 집단 이상 비교?
│
├─ 정규성 + 등분산 OK → aov()
└─ 가정 위반 → kruskal.test()
Wilcoxon 순위합 검정 (독립표본)
Wilcoxon rank-sum test(Mann-Whitney U test라고도 함)는 독립표본 t-검정의 비모수 대안입니다. 두 집단의 순위 분포가 같은지 검정합니다.
data(ToothGrowth)
# 먼저 정규성 확인
oj <- ToothGrowth$len[ToothGrowth$supp == "OJ"]
vc <- ToothGrowth$len[ToothGrowth$supp == "VC"]
cat("OJ 정규성 p:", shapiro.test(oj)$p.value, "\n")
cat("VC 정규성 p:", shapiro.test(vc)$p.value, "\n")
OJ 정규성 p: 0.02275
VC 정규성 p: 0.4284
# OJ의 정규성이 의심 → Wilcoxon 검정 적용
result <- wilcox.test(len ~ supp, data = ToothGrowth)
print(result)
Wilcoxon rank sum test with continuity correction
data: len by supp
W = 558.5, p-value = 0.06449
alternative hypothesis: true location shift is not equal to 0
W = 558.5, p = .064로 유의하지 않습니다. t-검정(p = .060)과 비슷한 결론입니다.
Wilcoxon 부호 순위 검정 (대응표본)
대응표본 t-검정의 비모수 대안입니다. paired = TRUE를 추가합니다.
data(sleep)
group1 <- sleep$extra[sleep$group == 1]
group2 <- sleep$extra[sleep$group == 2]
# 차이값의 정규성 확인
diff_vals <- group2 - group1
cat("차이값 정규성 p:", shapiro.test(diff_vals)$p.value, "\n")
차이값 정규성 p: 0.9827
정규성이 만족되어 대응표본 t-검정이 적절하지만, 비교를 위해 Wilcoxon도 실행합니다.
# 비모수 대응표본 검정
wilcox_paired <- wilcox.test(group2, group1, paired = TRUE)
print(wilcox_paired)
# 비교: 대응표본 t-검정
t_paired <- t.test(group2, group1, paired = TRUE)
cat("\nt-검정 p:", round(t_paired$p.value, 4), "\n")
cat("Wilcoxon p:", round(wilcox_paired$p.value, 4), "\n")
Wilcoxon signed rank exact test
data: group2 and group1
V = 54, p-value = 0.009091
alternative hypothesis: true location shift is not equal to 0
t-검정 p: 0.0028
Wilcoxon p: 0.0091
두 검정 모두 유의합니다. t-검정이 약간 더 낮은 p-값을 줍니다. 정규성 가정이 만족될 때 t-검정이 비모수 검정보다 검정력이 조금 더 높습니다.
Kruskal-Wallis 검정 (세 집단 이상)
Kruskal-Wallis 검정은 일원분산분석의 비모수 대안입니다. 세 집단 이상의 순위 분포가 같은지 검정합니다.
data(PlantGrowth)
# 정규성 확인
by(PlantGrowth$weight, PlantGrowth$group, function(x) shapiro.test(x)$p.value)
ctrl : 0.4542
trt1 : 0.2050
trt2 : 0.5643
세 집단 모두 정규성을 만족하지만, 비교를 위해 Kruskal-Wallis도 실행합니다.
# Kruskal-Wallis 검정
kw_result <- kruskal.test(weight ~ group, data = PlantGrowth)
print(kw_result)
Kruskal-Wallis rank sum test
data: weight by group
Kruskal-Wallis chi-squared = 7.9882, df = 2, p-value = 0.01842
χ²(2) = 7.99, p = .018로 유의합니다. ANOVA(p = .016)와 매우 비슷한 결론입니다.
Kruskal-Wallis 후 사후검정
# 비모수 사후검정: pairwise Wilcoxon
pairwise.wilcox.test(PlantGrowth$weight, PlantGrowth$group,
p.adjust.method = "BH")
Pairwise comparisons using Wilcoxon rank sum exact test
data: PlantGrowth$weight and PlantGrowth$group
ctrl trt1
trt1 0.199 -
trt2 0.199 0.026
BH 보정 후 trt2 vs trt1만 유의합니다(p = .026). ANOVA + TukeyHSD 결과(p = .012)와 같은 결론입니다.
효과크기 — 순위 이분점 상관계수(r)
비모수 검정의 효과크기는 r = Z / √N으로 계산합니다.
# Wilcoxon 검정의 효과크기 r
wilcox_result <- wilcox.test(len ~ supp, data = ToothGrowth,
exact = FALSE)
# Z 값 추출: qnorm(p/2) 사용
z_val <- qnorm(wilcox_result$p.value / 2)
n_total <- nrow(ToothGrowth)
r_effect <- abs(z_val) / sqrt(n_total)
cat("Z:", round(z_val, 3), "\n")
cat("효과크기 r:", round(r_effect, 3), "\n")
cat("해석:", ifelse(r_effect >= 0.5, "큰 효과",
ifelse(r_effect >= 0.3, "중간 효과", "작은 효과")), "\n")
Z: -1.842
효과크기 r: 0.238
해석: 작은 효과
비모수 검정 효과크기 r의 해석 기준입니다.
| r 값 | 효과 크기 |
|---|---|
| 0.1 | 작음 |
| 0.3 | 중간 |
| 0.5 이상 | 큼 |
모수 vs 비모수 언제 선택하나
비모수 검정은 항상 "안전한" 선택처럼 보이지만, 정규성 가정이 만족될 때 비모수 검정을 사용하면 검정력 손실이 발생합니다. 놓칠 수 있는 효과가 생기는 셈입니다.
실용적인 기준입니다.
- n ≥ 30이면 중심극한정리에 의해 t-검정과 ANOVA가 상당히 견고합니다.
- n < 20이고 Shapiro-Wilk p < 0.05이면 비모수 검정을 사용합니다.
- n이 20~30 사이이면 Shapiro-Wilk 결과와 함께 데이터를 시각적으로 확인(히스토그램, Q-Q 플롯)합니다.
- 데이터가 순위이거나 리커트 척도이면 비모수 검정이 더 적절합니다.
# Q-Q 플롯으로 정규성 시각 확인
par(mfrow = c(1, 2))
qqnorm(oj, main = "OJ Q-Q 플롯"); qqline(oj, col = "red")
qqnorm(vc, main = "VC Q-Q 플롯"); qqline(vc, col = "red")
par(mfrow = c(1, 1))
Q-Q 플롯에서 점들이 직선에 가깝게 분포하면 정규성 가정을 만족한다고 볼 수 있습니다. 양 끝에서 많이 벗어나면 정규성 가정이 의심됩니다.