Kruskal–Wallis H Test
Maths: Statistics for machine learning
2 min read
Published Oct 22 2025, updated Aug 17 2026
Guide Sections
Guide Comments
The Kruskal–Wallis H test is a non-parametric statistical test used to determine whether there are statistically significant differences between the medians of three or more independent groups.
It’s the non-parametric alternative to a one-way ANOVA.
In simple terms:
“The Kruskal–Wallis test checks whether the distributions of three or more groups are the same — without assuming a normal distribution.”
When to Use It
- Three or more groups - Independent samples
- Ordinal or continuous data - That do not follow a normal distribution
- Same shape of distribution - The test assumes group distributions have a similar shape
When not to Use It
- Paired data - Use the Friedman test instead
- Normal data - Use ANOVA instead
Example Question
“Do customers in different regions (North, South, East, West) spend the same amount on average?”
If spending data are skewed (e.g., non-normal, outliers), the Kruskal–Wallis test is the best choice.
Hypotheses
- H₀ (Null Hypothesis) - All group medians are equal (no difference between groups)
- H₁ (Alternative Hypothesis) - At least one group median is different
How It Works
- Combine all group data together.
- Rank all data from smallest to largest (1 = smallest).
- Compute the sum of ranks (Rᵢ) for each group.
- Calculate the test statistic H:

Where:
- N = total number of observations
- Ri = sum of ranks for group i
- ni = size of group i
- H follows an approximate chi-squared (χ²) distribution with k − 1 degrees of freedom.
If H is large → group medians differ → reject H₀.
Example in Python
Let’s test if three different marketing campaigns lead to different customer spending.
import numpy as npfrom scipy.stats import kruskal# Example data (non-normal)campaign_A = np.array([45, 50, 52, 60, 61, 62, 65, 70, 72])campaign_B = np.array([40, 42, 48, 51, 55, 57, 59, 61, 63])campaign_C = np.array([52, 55, 58, 60, 63, 65, 66, 68, 70])# Perform Kruskal–Wallis Teststat, p = kruskal(campaign_A, campaign_B, campaign_C)print(f"Kruskal–Wallis H Statistic: {stat:.3f}")print(f"P-value: {p:.4f}")Interpretation:
- p < 0.05 → Reject H₀ → At least one group’s median differs.
- p ≥ 0.05 → Fail to reject H₀ → No significant difference between groups.
Output Example:
Kruskal–Wallis H Statistic: 8.274P-value: 0.0159Since p < 0.05 → there is a significant difference between at least one group’s distribution.
Visual Results:

This shows each group’s spread - if one boxplot is clearly higher/lower, that’s what drives the significant difference.
Python code
import pingouin as pgimport pandas as pdimport numpy as np# Example: Comparing performance across 3 metrics (non-normal data)np.random.seed(42)df = pd.DataFrame({ 'Metric': np.repeat(['A', 'B', 'C'], 20), 'Performance': np.concatenate([ np.random.exponential(scale=1.0, size=20), np.random.exponential(scale=1.5, size=20), np.random.exponential(scale=2.0, size=20) ])})# Run Kruskal-Wallis testresults = pg.kruskal(data=df, dv='Performance', between='Metric')print(results)Output:
Source ddof1 H p-uncKruskal Metric 2 3.649508 0.161257