본문으로 바로가기

Kruskal-Wallis 검정: 정규성 없이 여러 집단 비교하기

Kruskal-Wallis 검정에 대한 실용 가이드 — 개념, 작동 원리, ANOVA 대비 사용 시점, Python과 R에서의 실행 및 해석 방법.
업데이트됨 2026년 5월 4일  · 9분 읽다

데이터가 정규분포를 따르면 여러 집단 비교는 쉽습니다. 문제는 대부분의 실제 데이터가 그렇지 않다는 점입니다.

ANOVA를 기본 검정으로 사용하면, 데이터가 정규분포를 따른다고 가정하기 때문에 잘못된 결론에 도달할 수 있습니다. 치우친 분포나 작은 표본처럼 정규성이 깨지면 다른 접근이 필요합니다.

Kruskal-Wallis 검정이 바로 그 대안입니다. 이는 ANOVA의 비모수적 대안으로, 원시값 대신 순위에 기반해 작동하므로 정규분포를 가정하지 않습니다.

이 글에서는 개념과 수식, Python과 R에서 실행하는 방법, 그리고 결과를 해석하는 법을 다룹니다.

Kruskal-Wallis 검정이란?

Kruskal-Wallis 검정은 세 개 이상의 독립 집단을 비교하는 비모수 방법입니다. 모든 관측치를 순위로 변환하고, 원시값 대신 집단 간 순위를 비교합니다.

이를 Mann-Whitney U 검정의 확장판으로 볼 수 있습니다. 이에 대해서도 제가 글을 쓴 바 있습니다.

Mann-Whitney U는 동일한 순위 기반 비교이지만 두 집단에만 적용됩니다. Kruskal-Wallis는 이를 세 집단 이상으로 확장합니다. 여러 집단이 있고 ANOVA를 쓸 수 없다면 이 검정을 사용하면 됩니다.

원시값이 아니라 순위를 사용하므로, 데이터가 특정 분포를 따른다고 가정하지 않습니다. 실제 데이터는 한 가지 분포에 완벽히 맞지 않는 경우가 많기에 유용합니다.

Kruskal-Wallis 검정을 사용할 때

다음과 같은 상황에서 Kruskal-Wallis 검정이 잘 맞습니다:

  • 세 개 이상의 독립 집단을 비교하려는 경우
  • 서열형 또는 연속형 데이터(예: 리커트 척도 평점, 측정값)
  • 비정규 분포(왜도, 이상치, 소표본 등 ANOVA가 다루기 어려운 경우)
  • 작은 표본 크기로 정규성을 확인하기 어려운 경우

간단한 예를 보겠습니다.

세 개 반의 시험 점수를 비교한다고 가정해 보세요. 점수 분포는 치우쳐 있고 표본도 작아 ANOVA는 적합하지 않습니다. Kruskal-Wallis는 정규성을 요구하지 않으므로 사용할 수 있습니다. 최소한 한 반의 점수가 다른 반들과 달랐는지, 데이터가 뒷받침하지 않는 가정을 두지 않고 알려줍니다.

Kruskal-Wallis 검정 vs. ANOVA

두 검정 모두 집단을 비교하지만 방식이 다릅니다.

ANOVA는 집단의 평균을 비교하며, 데이터가 정규분포를 따르고 분산이 대략 유사하다고 가정합니다. 가정이 충족되면 더 나은 선택입니다. 통계적 검정력이 더 높고 해석도 쉽습니다.

Kruskal-Wallis는 집단의 분포를 순위를 이용해 비교합니다. 정규성이나 등분산을 신경 쓰지 않습니다. 더 유연하지만, 그만큼 통계적 검정력은 다소 떨어집니다.

간단 비교 표는 다음과 같습니다:

ANOVA compared to Kruskal-Wallis test

ANOVA와 Kruskal-Wallis 검정 비교

데이터가 정규분포를 따른다면 ANOVA를 사용하세요. 그렇지 않거나 확인할 수 없다면 Kruskal-Wallis를 사용하세요.

Kruskal-Wallis 검정 수식

Kruskal-Wallis 검정은 H라는 하나의 검정통계량으로 요약됩니다. 수식은 다음과 같습니다:

Kruskal-Wallis formula

Kruskal-Wallis 수식

구성요소는 다음과 같습니다:

  • N - 모든 집단의 관측치 총합

  • k - 집단의 수

  • n_i - 집단 i의 관측치 수

  • R_i - 집단 i에 할당된 순위의 합

이 수식은, 모든 집단이 동일하다면 기대되는 수준에서 각 집단의 순위 합이 얼마나 벗어나는지를 측정합니다. H가 크면 집단 간 차이가 크고, H가 작으면 차이가 크지 않다는 뜻입니다.

H를 계산한 뒤에는 자유도 k - 1인 카이제곱 분포와 비교해 p-값을 구합니다.

Kruskal-Wallis 검정의 작동 방식

Kruskal-Wallis 검정은 네 단계로 수행합니다:

  1. 모든 집단을 합칩니다: 모든 집단의 관측치를 하나의 데이터셋으로 합칩니다
  2. 모든 관측치에 순위를 매깁니다: 합친 데이터를 작은 값부터 큰 값까지 정렬하고 순위를 부여합니다. 가장 작은 값은 1, 다음은 2, 이런 식입니다. 값이 같으면 해당 순위들의 평균을 공유합니다.
  3. 순위 합을 계산합니다: 순위를 원래 집단별로 다시 나눕니다. 각 집단의 순위를 모두 더합니다. 이것이 수식의 R_i입니다
  4. 검정통계량을 계산합니다: 순위 합을 H 수식에 대입합니다. 집단이 비슷하면 순위 합이 서로 가깝고 H는 작습니다. 한 집단이 일관되게 더 높은(혹은 낮은) 순위를 받으면 H가 커집니다

이게 전부입니다!

보시다시피 이 검정은 실제 값 자체보다, 전체 속에서 값이 어느 위치에 있는지만을 봅니다.

Python에서의 Kruskal-Wallis 검정

Python의 scipy 라이브러리는 Kruskal-Wallis 검정을 위한 내장 함수를 제공합니다. 수식을 직접 구현할 필요가 없습니다. 예제를 살펴보겠습니다.

세 반의 시험 점수를 비교한다고 가정합니다. 검정은 다음과 같이 수행합니다:

from scipy import stats

# Exam scores
class_a = [78, 85, 90, 72, 88]
class_b = [65, 70, 68, 74, 60]
class_c = [88, 92, 95, 85, 91]

# Run the test
statistic, p_value = stats.kruskal(class_a, class_b, class_c)

print(f"H statistic: {statistic:.4f}")
print(f"P-value: {p_value:.4f}")

Python output

Python 출력

p-값이 0.05보다 작으므로, 최소 한 반의 점수가 다른 반들과 다르다는 의미입니다. 다만 어떤 반이 다른지는 알려주지 않습니다. 이를 알아보려면 사후 검정이 필요하며, 다음 섹션에서 설명합니다.

R에서의 Kruskal-Wallis 검정

Python과 마찬가지로 R에도 이 검정을 위한 내장 함수가 있습니다. 같은 시험 점수 사례를 사용하겠습니다.

# Exam scores
class_a <- c(78, 85, 90, 72, 88)
class_b <- c(65, 70, 68, 74, 60)
class_c <- c(88, 92, 95, 85, 91)

# Combine
scores <- c(class_a, class_b, class_c)
groups <- factor(rep(c("A", "B", "C"), each = 5))

# Run the test
kruskal.test(scores ~ groups)

R output

R 출력

출력은 Python과 동일합니다. 동일한 H 통계량과 p-값이 나옵니다. p < 0.05이면 귀무가설을 기각하고, 최소 한 집단이 다르다고 결론 내립니다.

Kruskal-Wallis 결과 해석 방법

Kruskal-Wallis 검정의 귀무가설은 모든 집단이 동일한 분포를 가진다는 것입니다. p-값이 이를 기각할지 여부를 알려줍니다. 해석은 다음과 같습니다:

  • p < 0.05: 최소 한 집단이 다른 집단과 다릅니다. 귀무가설을 기각합니다
  • p >= 0.05: 집단 간 차이가 있다고 볼 강한 근거가 없습니다. 귀무가설을 기각하지 않습니다

0.05 임계값은 관례입니다. 분야나 분석의 중요도에 따라 0.01처럼 더 엄격하거나 0.10처럼 더 느슨한 값을 사용할 수 있습니다.

이 검정은 어떤 집단이 다른지까지는 알려주지 않습니다. 유의미한 결과는 모든 집단이 같지는 않다는 뜻일 뿐입니다. 어느 쌍이 차이를 만드는지 확인하려면 사후 검정이 필요합니다.

Kruskal-Wallis 이후의 사후 검정

이 검정은 최소 한 집단이 다르다는 사실만 알려줄 뿐, 어떤 집단이 실제로 다른지 알려주지 않습니다. 세 집단에서 p < 0.05라면 A 대 B, A 대 C, B 대 C 또는 그 조합일 수 있습니다. 이러한 쌍별 비교를 위해 사후 검정을 수행해야 합니다.

Dunn 검정이 가장 흔한 선택입니다. 모든 집단 간 쌍별 비교를 수행하고, 다중 비교를 고려해 p-값을 보정합니다. 보정 없이 진행하면 거짓 양성 가능성이 높아집니다. 비교를 많이 할수록 우연히 "유의"하다는 결과를 찾을 위험이 커집니다.

Python에서의 Dunn 검정

이 작업에는 scikit_posthocs 라이브러리가 필요합니다. 없다면 pip install scikit-posthocs로 설치하세요.

그다음 계산은 간단합니다:

import scikit_posthocs as sp
import pandas as pd

# Same exam scores as before
class_a = [78, 85, 90, 72, 88]
class_b = [65, 70, 68, 74, 60]
class_c = [88, 92, 95, 85, 91]

# Combine
scores = class_a + class_b + class_c
groups = ["A"] * 5 + ["B"] * 5 + ["C"] * 5

df = pd.DataFrame({"score": scores, "group": groups})

# Run the test
result = sp.posthoc_dunn(df, val_col="score", group_col="group", p_adjust="bonferroni")
print(result)

Dunn’s test in Python

Python에서의 Dunn 검정

각 셀은 해당 쌍의 보정된 p-값을 보여줍니다. 여기서는 B 대 C(p = 0.004)만 0.05 임계값을 넘습니다. 따라서 이 두 집단은 다릅니다. A 대 B(p = 0.167)와 A 대 C(p = 0.607)는 유의하지 않으므로, A반은 다른 두 반과 통계적으로 차이가 없습니다.

R에서의 Dunn 검정

먼저 필요하다면 install.packages("dunn.test") 명령으로 라이브러리를 설치합니다:

library(dunn.test)

# Same exam scores as before
class_a <- c(78, 85, 90, 72, 88)
class_b <- c(65, 70, 68, 74, 60)
class_c <- c(88, 92, 95, 85, 91)

scores <- c(class_a, class_b, class_c)
groups <- factor(rep(c("A", "B", "C"), each = 5))

# Run the test
dunn.test(scores, groups, method = "bonferroni")

Dunn’s test in R

R에서의 Dunn 검정

예상대로 결과는 Python과 일치합니다. B 대 C만 유의하며, A 대 B와 A 대 C는 유의하지 않습니다. Kruskal-Wallis 검정에서 감지된 차이는 B반과 C반이 만든 것입니다.

Kruskal-Wallis 검정의 가정

Kruskal-Wallis 검정은 ANOVA보다 유연하지만, 실행 전에 확인해야 할 세 가지 가정이 있습니다:

  • 표본의 독립성: 한 집단의 관측치가 다른 집단의 관측치에 영향을 주지 않아야 합니다. 짝지어진 자료나 반복측정이면 적절하지 않습니다
  • 서열형 또는 연속형 데이터: 순위를 매길 수 있는 데이터가 필요합니다. 명목형 범주(색상, 라벨 등)는 순위를 매길 수 없어 사용할 수 없습니다
  • 유사한 분포 모양: 중앙값 비교로 해석하려면 집단 간 분포 모양이 대략 유사해야 합니다. 모양이 많이 다르면 분포 비교는 가능하지만 중앙값 해석은 성립하지 않습니다

첫 두 가정을 위반하면 검정 결과는 타당하지 않습니다. 세 번째 가정은 다소 유연하여, 검정 실행 가능성보다는 결과 해석 방식에 영향을 줍니다.

Kruskal-Wallis 검정을 사용하지 말아야 할 때

다음 세 가지 경우에는 다른 검정이 더 적합합니다:

  • 데이터가 짝지어졌거나 반복측정인 경우: 동일한 대상이 여러 집단에 걸쳐 나타난다면 Friedman 검정을 사용하세요. 종속 표본을 위한 비모수 대안입니다. 짝지어진 데이터에 Kruskal-Wallis를 적용하면 관측치 간 관계를 무시해 잘못된 결론에 이를 수 있습니다
  • ANOVA 가정을 충족하는 경우: 데이터가 정규분포이고 분산이 대략 유사하다면 ANOVA가 더 좋습니다. 통계적 검정력이 더 높아 실제 차이를 더 잘 탐지합니다
  • 표본 크기가 큰 경우: 큰 표본에서는 데이터가 완전한 정규성이 아니어도 모수 방법이 잘 작동하는 경향이 있습니다. 중심극한정리가 작동하며, ANOVA가 순위 기반 접근보다 더 신뢰할 수 있는 결과를 제공합니다. 집단당 수백 혹은 수천 개의 관측치가 있다면 Kruskal-Wallis는 적합하지 않습니다

결론

Kruskal-Wallis 검정은 ANOVA 같은 검정이 요구하는 정규분포를 따르지 않는 데이터에서 세 집단 이상 독립 집단을 비교할 때 사용합니다. 원시값 대신 순위에 기반하기 때문에 가능합니다.

그렇다고 ANOVA를 대체하는 것은 아닙니다. 데이터가 정규적이면 ANOVA가 통계적 검정력이 더 높아 더 적합합니다. 반면 데이터가 짝지어진 경우에는 Friedman 검정을 사용하세요. 늘 그렇듯 올바른 검정은 데이터에 달려 있습니다.

조건이 맞을 때 Kruskal-Wallis 검정은 신뢰할 수 있고 간단한 선택입니다. 검정을 실행하고 p-값을 확인한 뒤, 어느 집단이 차이를 만드는지 알아야 한다면 Dunn 검정으로 후속 분석을 진행하세요.

통계 지식이 조금 가물가물하신가요? Introduction to Statistics 과정을 수강하고 하루 만에 감을 되찾아 보세요.

Kruskal-Wallis 검정 FAQ

Kruskal-Wallis 검정은 무엇에 사용하나요?

Kruskal-Wallis 검정은 데이터가 정규분포를 따른다고 가정할 수 없을 때 세 개 이상의 독립 집단을 비교하는 데 사용됩니다. 원시값 대신 순위에 기반해 작동하는 ANOVA의 비모수적 대안입니다. 분포가 치우쳐 있거나 데이터가 서열형일 때 유용합니다.

Kruskal-Wallis 결과가 유의미하다는 것은 무엇을 뜻하나요?

유의미한 결과(일반적으로 p < 0.05)는 최소 한 집단이 다른 집단과 다르다는 의미입니다. 어떤 집단이 다른지는 알려주지 않습니다. 어느 쌍이 차이를 만드는지 알기 위해서는 Dunn 검정 같은 사후 검정을 수행해야 합니다.

Kruskal-Wallis 검정의 가정은 무엇인가요?

검정은 표본의 독립성을 요구합니다. 즉, 한 집단의 관측치가 다른 집단의 관측치에 영향을 주면 안 됩니다. 데이터는 순위를 매길 수 있는 서열형 또는 연속형이어야 합니다. 중앙값 비교로 해석하려면 집단 간 분포 모양이 유사해야 합니다.

Kruskal-Wallis 검정과 Mann-Whitney U 검정의 차이는 무엇인가요?

Mann-Whitney U 검정은 두 개의 독립 집단을 비교하고, Kruskal-Wallis 검정은 그 접근을 세 집단 이상으로 확장합니다. 둘 다 순위 데이터에 기반하며 정규성을 가정하지 않습니다. 집단이 두 개뿐이라면 Mann-Whitney U가 적합하고, Kruskal-Wallis는 다집단에 해당하는 대안입니다.

Kruskal-Wallis 이후 Dunn 검정은 언제 사용하나요?

Kruskal-Wallis 결과가 유의하고, 어떤 집단 쌍이 다른지 알아야 할 때 Dunn 검정을 사용하세요. 모든 집단 간 쌍별 비교를 수행하고 p-값을 보정해 거짓 양성 위험을 줄입니다. Python에서는 scikit_posthocs.posthoc_dunn()을, R에서는 dunn.test 패키지를 사용하면 됩니다.

주제

DataCamp로 학습하세요

courses

R로 시작하는 통계학 입문

4
128.6K
통계 기술을 향상시키고 데이터를 수집, 분석하며 정확한 결론을 도출하는 방법을 배우세요.
자세히 보기Right Arrow
강좌 시작
더 보기Right Arrow