Skip to content

How to run a Kruskal-Wallis test in SciPy (with Code)

The Short Answer (TL;DR)

Pass independent groups as separate arguments to scipy.stats.kruskal to obtain a tie-corrected H statistic and an approximate p-value. Treat the result as an omnibus rank comparison, and inspect distribution shapes before interpreting it as a difference in medians.

from scipy import stats
groups = [[1, 2, 2, 3, 4, 5], [3, 4, 4, 5, 6, 7], [6, 7, 7, 8, 9, 10]]
print(stats.kruskal(*groups, nan_policy="raise"))

Detailed Implementation

This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.

python -m pip install numpy==2.5.4 scipy==1.18.1
from pathlib import Path
import numpy as np
from scipy import stats

# Independent synthetic groups on a common ordered measurement scale.
groups = [np.array(g, dtype=float) for g in [
    [1, 2, 2, 3, 4, 5],
    [3, 4, 4, 5, 6, 7],
    [6, 7, 7, 8, 9, 10],
]]
if any(g.ndim != 1 or g.size < 5 or not np.isfinite(g).all() for g in groups):
    raise ValueError("This example requires at least five finite values per group.")
pooled = np.concatenate(groups)
if np.unique(pooled).size < 2:
    raise ValueError("The pooled observations must not all be identical.")
result = stats.kruskal(*groups, nan_policy="raise")
tie_factor = stats.tiecorrect(stats.rankdata(pooled, method="average"))
report = (
    f"Group sizes: {[g.size for g in groups]}\n"
    f"Tie correction factor: {tie_factor:.6f}\n"
    f"H statistic: {result.statistic:.6f}\n"
    f"Reference chi-square df: {len(groups)-1}\n"
    f"Approximate omnibus p-value: {result.pvalue:.8g}\n"
)
print(report)
Path("kruskal-wallis-output.txt").write_text(report, encoding="utf-8")

The text report contains three sample sizes of six, a tie correction below one, the corrected H statistic and an approximate p-value with two reference degrees of freedom. Independent average-rank arithmetic reproduces the reported statistic and probability.

Which observations can be compared?

Use independent samples with a common ordering and one group label per observation. Repeated measurements from the same units need a paired or repeated-measures method. Rank methods do not remove dependence, selection bias or a poor sampling design. The synthetic example contains six observations per group; that sample size alone does not guarantee an accurate approximation for every population.

Does a small p-value identify different medians?

The omnibus comparison can indicate that some groups tend to have larger ranks. A location or median interpretation needs comparable distribution shapes; different spreads can complicate that reading. Inspect the actual observations and describe the groups before choosing an interpretation. The omnibus p-value does not identify a particular pair or show that every pair differs.

How are ties and small groups handled?

Equal pooled observations receive average ranks, and SciPy corrects H for the resulting ties. The reported p-value uses a chi-square approximation. The documentation gives at least five observations per group as a typical guideline, rather than an accuracy guarantee. Very small or heavily tied samples may need a design-appropriate alternative. All-identical pooled data leave no rank contrast, so the example rejects them.

Mathematical Context

Let N be the pooled sample size, n_j each group size and R_j its pooled rank sum. First compute H0 as 12 divided by N(N+1), multiplied by the sum of R_j squared divided by n_j, then subtract 3(N+1). If a tied value occurs t times, its contribution to the tie adjustment is t cubed minus t. The correction factor is C=1-sum(t^3-t)/(N^3-N), with the entire sum of tie contributions divided by the denominator (N^3-N). SciPy reports H=H0/C. The example independently reconstructs the average ranks and C, then verifies H. For three groups the reference distribution has two degrees of freedom, whose upper-tail probability equals exp(-H/2). Rank magnitudes have no original measurement units.

\[ H=\frac{\frac{12}{N(N+1)}\sum_{j=1}^{k}\frac{R_j^2}{n_j}-3(N+1)}{1-\frac{\sum_\ell(t_\ell^3-t_\ell)}{N^3-N}} \]

Reproducibility

Executed with Python 3.12.14; numpy 2.5.4, scipy 1.18.1. Automated checks confirm the stated output properties.

Primary documentation

Related guides

For a comparison of two independent groups, run a Mann-Whitney U test in SciPy. State whether the question concerns distributions or a location shift, and check the assumptions needed for that interpretation.