크루스칼-왈리스 검정 (Kruskal-Wallis Test)
아래는 **크루스칼-왈리스 검정(Kruskal-Wallis Test)**의 개념과 Python 예시를 정리한 내용입니다. 크루스칼-왈리스 검정은 세 개 이상의 독립된 집단 간 중앙값(또는 분포 위치)이 서로 다른지 비교하기 위한 비모수적 방법으로, **일원분산분석(ANOVA)**의 비모수적 대안이라고도 볼 수 있습니다.
1. 개념 정리
1.1 Kruskal-Wallis 검정이란?
- Kruskal-Wallis 검정은 독립인 개의 집단( )에 대해, 해당 집단들의 중앙값이 모두 동일한지를 검정하는 비모수적 기법입니다. kk k≥3k \ge 3
- 데이터를 **순위(rank)**로 바꾸어 일원분산분석과 유사한 아이디어로 분산 비교를 수행합니다.
- 만약 정규성(각 집단이 정규분포를 이룬다) 혹은 등분산성(분산 동일) 가정이 불확실하거나 위배되는 경우에, 일원분산분석(ANOVA) 대신 Kruskal-Wallis 검정을 적용할 수 있습니다.
1.2 가설 설정
- 귀무가설(H₀): 개의 집단(모집단)의 분포가 동일하며, 중앙값이 모두 같다. kk
- 대립가설(H₁): 적어도 한 집단의 중앙값이 다르다(분포가 다르다).
Kruskal-Wallis 검정도 순위 기반 비모수 기법이므로, 주로 “중앙값 차이가 있는지”를 본다고 해석합니다.
1.3 적용 조건
- 각 집단은 독립적이어야 함(한 개체는 오직 한 집단에만 속함).
- 측정값이 서열척도(ordinal scale) 이상이어야 함(순서를 매길 수 있어야 함).
- 집단 간에 분포 형태가 완전히 달라지지 않는다는 전제가 어느 정도 필요(순위를 통한 비교이므로, 분포 모양이 극단적으로 다른 경우 해석 주의).
- 정규성이나 등분산성 가정은 필요 없음(비모수).
2. 검정 과정(개념)
- kk개 집단의 모든 데이터를 통합하고, 값의 크기순으로 정렬한 뒤 각각에 순위(rank)를 매긴다. (동점이면 평균 순위)
- 각 집단에 속한 데이터가 차지하는 순위의 합()을 계산한다. RiR_i
- Kruskal-Wallis 통계량(H) 공식에 따라 H 값을 계산하고, 이를 통해 p-value를 구한다. H=12N(N+1)∑i=1kRi2ni − 3(N+1)H = \frac{12}{N(N+1)} \sum_{i=1}^{k} \frac{R_i^2}{n_i} ;-; 3(N+1)
- NN: 전체 표본 크기() N=n1+n2+⋯+nkN = n_1 + n_2 + \dots + n_k
- nin_i: 각 집단의 표본 크기
- RiR_i: 집단 의 순위합 ii
- 검정 결과 p-value < → 귀무가설 기각(즉, 집단 중 적어도 하나는 중앙값이 다르다). α\alpha
3. Python 실습 예시
Python에서 Kruskal-Wallis 검정은 scipy.stats의 kruskal 함수를 사용하면 됩니다.
3.1 라이브러리 임포트
import numpy as np
import pandas as pd
from scipy.stats import kruskal
3.2 예시 데이터 생성
- 예) 세 가지 교육 방법(집단 3개:
method_A,method_B,method_C)에 따른 시험 점수가 정규분포가 아니라 가정 → 비모수 검정 적용 - 각 집단 표본 크기는 15명씩
np.random.seed(42)
# method_A: 평균 70, 사분위 범위가 넓다고 가정(치우친 분포?)
method_A = np.random.gamma(shape=5, scale=2, size=15) + 60
# method_B
method_B = np.random.gamma(shape=5, scale=2, size=15) + 65
# method_C
method_C = np.random.gamma(shape=5, scale=2, size=15) + 70
# 데이터프레임 구성
df_edu = pd.DataFrame({
'score': np.concatenate([method_A, method_B, method_C]),
'group': ['A']*15 + ['B']*15 + ['C']*15
})
print(df_edu.head())
여기서는 감마분포(치우친 분포)로 데이터를 생성했으므로, 정규성 가정이 깨질 수 있다는 설정으로 Kruskal-Wallis를 사용한다 가정합니다.
3.3 Kruskal-Wallis 검정 수행
stat, p_value = kruskal(method_A, method_B, method_C)
print("[Kruskal-Wallis Test]")
print(f"H-statistic = {stat:.4f}, p-value = {p_value:.4f}")
alpha = 0.05
if p_value < alpha:
print("=> 귀무가설 기각: 세 그룹 중 적어도 한 그룹의 중앙값이 다름.")
else:
print("=> 귀무가설 채택(기각 실패): 중앙값 차이가 유의하지 않음.")
- 여기서 결과의
stat(H 값)은 Kruskal-Wallis 통계량, **p_value*는 그에 대한 유의확률
3.4 사후검정 (Post-hoc test)
Kruskal-Wallis 결과가 유의하다면(귀무가설 기각), 어느 그룹들이 차이가 나는지 추가 비교가 필요합니다.
- 비모수적 사후검정으로 Dunn’s test 또는 Conover’s test 등을 사용
- Python에서는
scikit-posthocs라이브러리의posthocs.posthoc_conover또는posthocs.posthoc_dunn등을 활용할 수 있습니다. (별도 설치 필요:pip install scikit-posthocs)
예시: Conover’s test
!pip install scikit-posthocs
import scikit_posthocs as sp
data = [method_A, method_B, method_C] # list of arrays
# 한꺼번에 묶어서 posthoc
posthoc_res = sp.posthoc_conover(data, p_adjust='bonferroni')
print(posthoc_res)
p_adjust=‘bonferroni’는 다중비교 보정을 위한 옵션 중 하나.결과 테이블에서 각 집단 쌍(A-B, B-C, A-C)에 대한 p-value가 제공됨. p-value < 0.05면 해당 두 그룹 간 유의한 차이 있다고 해석.
4. 결과 해석 및 주의사항
- p-value < 0.05 (Kruskal-Wallis)
- 적어도 한 집단의 중앙값이 다른 집단과 유의한 차이가 있다.
- 자세히 어떤 그룹끼리 다른지 보려면 사후검정(Post-hoc) 필수.
- p-value >= 0.05
- “집단 간 중앙값 차이가 통계적으로 유의하지 않음.”
- 비모수적이므로, 정규성 가정을 하지 않아도 됨.
- 다만, 각 집단의 분포 형태가 심하게 달라지면(예: 한쪽은 극단적 비대칭, 다른 한쪽은 양극단 분포 등) 단순 “중앙값” 비교로 해석하기 어려울 수 있음.
- 독립성
- Kruskal-Wallis 역시 집단 간 표본이 독립이어야 한다.
- 사후검정
- ANOVA와 마찬가지로, 전체 검정(H₀ 기각) 후에는 구체적으로 어떤 집단 사이가 다른지 확인해야 의미가 있다.
5. 요약
- Kruskal-Wallis 검정은 개의 독립 집단( )에 대한 중앙값 비교를 하는 비모수적 방법. kk k≥3k \ge 3
- *일원분산분석(ANOVA)**의 비모수 버전으로 볼 수 있으며, 정규성·등분산성 가정이 불확실할 때 유용.
- Python에서
scipy.stats.kruskal함수를 사용해 쉽게 수행 가능. 결과 해석 시 유의하면, p-value < 0.05일 때 사후검정을 통해 구체적으로 어떤 그룹 간 차이가 존재하는지 파악하는 것이 중요.
참고문헌
- Kruskal, W. H., & Wallis, W. A. (1952). Use of ranks in one-criterion variance analysis. Journal of the American Statistical Association, 47(260), 583–621.
- Hollander, M., Wolfe, D. A., & Chicken, E. (2013). Nonparametric Statistical Methods (3rd ed.). Wiley.
- Conover, W. J. (1999). Practical Nonparametric Statistics (3rd ed.). Wiley.
- scipy.stats.kruskal 문서 이상으로 Kruskal-Wallis 검정에 대한 개념과 실습 예시를 살펴보았습니다. 세 개 이상의 독립집단에서 정규성 가정이 어렵거나, 표본 크기가 작아 비모수적 접근이 필요할 때 유용하게 활용할 수 있는 대표적 기법입니다.
- 요약
Kruskal-Wallis Test 교안
1. 개요
Kruskal-Wallis test는 세 개 이상의 독립적인 집단 간 차이를 검정하는 비모수적 방법으로, 일원배치 분산분석(One-way ANOVA)의 비모수적 대안입니다.
1.1 특징
- 정규성 가정이 필요하지 않음
- 순위에 기반한 검정
- 세 개 이상의 독립 집단 비교
- 연속형 또는 순서형 종속변수
1.2 기본 가정
- 독립성
- 동일한 분포 형태
- 순서형 이상의 측정 수준
2. 통계적 가설
2.1 귀무가설(H₀)
모든 집단의 분포가 동일하다
2.2 대립가설(H₁)
적어도 한 집단의 분포가 다르다
3. 검정 통계량
3.1 H 통계량
여기서:
- N: 전체 표본 크기
- k: 집단 수
- n_i: i번째 집단의 표본 크기
- R_i: i번째 집단의 순위합
3.2 동률 보정
여기서:
- t_i: 각 동률 그룹의 관측값 수
4. 실습
4.1 Python 구현
import numpy as np
from scipy import stats
# 예시 데이터
group1 = [2.9, 3.0, 2.5, 2.6, 3.2]
group2 = [3.8, 3.7, 3.9, 3.6, 3.5]
group3 = [2.8, 3.4, 3.7, 2.9, 3.1]
# Kruskal-Wallis 검정
statistic, pvalue = stats.kruskal(group1, group2, group3)
print(f'H-statistic: {statistic:.4f}')
print(f'p-value: {pvalue:.4f}')
4.2 R 구현
# 데이터 준비
data <- data.frame(
value = c(2.9, 3.0, 2.5, 2.6, 3.2,
3.8, 3.7, 3.9, 3.6, 3.5,
2.8, 3.4, 3.7, 2.9, 3.1),
group = factor(rep(c("A","B","C"), each=5))
)
# Kruskal-Wallis 검정
kruskal.test(value ~ group, data=data)
5. 사후 검정
5.1 Dunn’s Test
from scikit_posthocs import posthoc_dunn
# 데이터 준비
data = [group1, group2, group3]
posthoc_dunn(data, p_adjust='bonferroni')
5.2 Mann-Whitney U with Bonferroni Correction
def pairwise_mannwhitney(groups, labels):
n_groups = len(groups)
results = []
for i in range(n_groups):
for j in range(i+1, n_groups):
stat, p = stats.mannwhitneyu(groups[i], groups[j])
results.append({
'comparison': f'{labels[i]} vs {labels[j]}',
'statistic': stat,
'p_value': p * (n_groups * (n_groups-1)/2) # Bonferroni
})
return results
6. 효과 크기
6.1 η² (Eta-squared)
6.2 ε² (Epsilon-squared)
def kw_effect_size(h_stat, n, k):
eta_squared = h_stat / (n - 1)
epsilon_squared = (h_stat - k + 1) / (n - k)
return eta_squared, epsilon_squared
7. 실무 적용
7.1 분석 전 확인사항
- 독립성 검증
- 이상치 확인
- 분포 형태 유사성 검토
7.2 결과 보고
def report_kw_test(groups, labels):
# 기술통계량
desc_stats = {label: {
'n': len(group),
'median': np.median(group),
'iqr': stats.iqr(group)
} for label, group in zip(labels, groups)}
# Kruskal-Wallis 검정
h_stat, p_val = stats.kruskal(*groups)
# 효과 크기
n = sum(len(g) for g in groups)
k = len(groups)
eta_sq, eps_sq = kw_effect_size(h_stat, n, k)
return {
'descriptive': desc_stats,
'test_results': {
'h_statistic': h_stat,
'p_value': p_val,
'effect_size': {
'eta_squared': eta_sq,
'epsilon_squared': eps_sq
}
}
}
8. 연습문제
8.1 기초 문제
세 가지 교수법의 효과를 비교하려 합니다. 다음 데이터에 대해 Kruskal-Wallis 검정을 수행하세요.
method_A = [75, 68, 82, 69, 71]
method_B = [85, 82, 88, 79, 83]
method_C = [79, 73, 77, 81, 76]
8.2 심화 문제
- 위 데이터에 대한 사후 검정 수행
- 효과 크기 계산 및 해석
- 시각화를 통한 결과 표현
9. 해석 가이드
9.1 p-value 해석
- p < α: 집단 간 차이 존재
- p ≥ α: 유의한 차이 없음
9.2 효과 크기 해석
- η² < 0.04: 작은 효과
- 0.04 ≤ η² < 0.11: 중간 효과
- η² ≥ 0.11: 큰 효과
참고문헌
- Kruskal, W. H., & Wallis, W. A. (1952). Use of ranks in one-criterion variance analysis. Journal of the American Statistical Association, 47(260), 583-621.
- Dunn, O. J. (1964). Multiple comparisons using rank sums. Technometrics, 6(3), 241-252.