The Kruskal-Wallis rank-sum test is a non-parameteric method for testing whether samples originate from the same distribution; its parametric equivalent is One-way ANOVA. This test is useful for cases where the data does not meet the assumptions for ANOVA (iid, heteroschedastic residuals, normally-distributed).

To perform the Kruskal-Wallis test for a dataset with \(N\) total points with \(g\) samples:

  1. Rank all data points from 1 to \(N\). In the case of ties, the rank should be averaged.

  2. Compute the test statistic \(H = (N-1)\Large{\frac{\sum_{i=1}^{g} n_i(\bar{r}_i. - \bar{r}^2)}{\sum_{i=1}^{g}\sum_{j=1}^{n_i}(\bar{r}_{ij} - \bar{r}^2)}}\), where

\(n_i\) is the size of sample \(i\),
\(r_{ij}\) is the rank of observation \(j\) belonging to sample \(i\),
\(\bar{r}_{i.}\) is the mean rank of all observations in sample \(i\), and
\(\bar{r} = \frac{1}{2}(N + 1)\) is average of all \(r_{ij}\).

  1. Approximate the p-value by: \(\text{Pr}(\chi_{g-1}^2 \geq H)\).

Example in R: Air Quality Data

We demonstrate the Kruskal-Wallis test using the built-in dataset “airquality”, which contains daily air quality measurements in New York from May to September 1973. We would like to know whether or not Ozone measurements vary between months. Our null hypothesis is that the Ozone measurements come from the same distribution. Alternatively, we believe that each monthly sample has a different distribution. Looking at boxplots of each sample, our intuition leads us to think that there may be some difference in the samples.

The first test that comes to mind is a one-way ANOVA. However, plotting a Q-Q plot comparing the quantiles of the Ozone data with the quantiles of a Gaussian distribution, we see that our data does not follow the assumption of normality that ANOVA requires.

data("airquality")

#par(mfrow = c(1,2))
boxplot(airquality$Ozone ~ airquality$Month,
        main = "Ozone Level by Month",
        xlab = "Month",
        ylab = "Ozone Level",
        col = rgb(0.0, 0.0, 0.9, 0.3))

qqnorm(airquality$Ozone,
     main = "Normal Q-Q Plot of Ozone Data")
qqline(airquality$Ozone, col = "red")

Thus, we perform a Kruskal-Wallis test as described above. We use the kruskal.test() function in the {stats} package to run a Kruskal-Wallis rank-sum test:

library(stats)

# an example for use of KW Test can be found here: https://stat.ethz.ch/R-manual/R-devel/library/stats/html/kruskal.test.html

kw.test <- kruskal.test(Ozone ~ Month,
             data = airquality)

kw.test
## 
##  Kruskal-Wallis rank sum test
## 
## data:  Ozone by Month
## Kruskal-Wallis chi-squared = 29.267, df = 4, p-value = 6.901e-06

Given the small p-value, we reject the null hypothesis. We coclude that the samples do not come from the same probability distribution.