Non-Parametric Tests
SciPy - Statistical Testing
2 min read
Published Nov 17 2025, updated Aug 17 2026
Guide Sections
Guide Comments
Non-parametric tests are alternatives to t-tests and ANOVA when:
- The data is not normally distributed
- The data is ordinal (ranks, ratings)
- There are outliers that violate assumptions
- Sample sizes are small
- You want a “distribution-free” version of a test
Mann–Whitney U Test
Independent two-group comparison. Alternative to the independent t-test.
Used when:
- Two groups are independent
- Data is not normal
- Data is ordinal or skewed
- Sample sizes are small
Example
from scipy import statsgroup1 = [12, 14, 15, 16, 18]group2 = [20, 22, 19, 23, 21]stat, p = stats.mannwhitneyu(group1, group2)print(stat, p)Interpretation
p < 0.05→ groups differ significantly- Direction: compare medians or inspect raw data
With “two-sided” alternative
stat, p = stats.mannwhitneyu(group1, group2, alternative='two-sided')Wilcoxon Signed-Rank Test
Paired / matched samples. Alternative to the paired t-test.
Used when:
- Same subjects measured twice
- Non-normal data
- Median difference instead of mean difference
Example
before = [10, 12, 9, 14, 11]after = [13, 15, 10, 17, 12]stat, p = stats.wilcoxon(before, after)print(stat, p)Interpretation
p < 0.05→ median difference is significant- Use for before/after experiments with skewed or ordinal data
Note: requires paired data and no zero-differences for the default behaviour.
Kruskal–Wallis Test
Three or more independent groups. Alternative to one-way ANOVA.
Used when:
- 3+ independent groups
- Data is not normal
- Data is ordinal
- Variances differ
Example
group_a = [5, 6, 7, 5, 6]group_b = [8, 9, 7, 8, 9]group_c = [4, 5, 3, 4, 5]stat, p = stats.kruskal(group_a, group_b, group_c)print(stat, p)Interpretation
p < 0.05→ at least one group differs- Like ANOVA, it does not tell which groups differ
Post-hoc Testing
SciPy does not provide post-hoc pairwise non-parametric tests, but you can use:
- Dunn’s Test (via
scikit-posthocs) - Pairwise Mann–Whitney with Bonferroni correction
Example (Dunn test):
pip install scikit-posthocsimport scikit_posthocs as spimport pandas as pddata = pd.DataFrame({ 'value': group_a + group_b + group_c, 'group': ['A']*5 + ['B']*5 + ['C']*5})sp.posthoc_dunn(data, val_col='value', group_col='group', p_adjust='bonferroni')Friedman Test
Three or more repeated-measures groups. Alternative to repeated-measures ANOVA.
Used when:
- Same subjects measured under 3+ conditions
- Non-normal repeated measurements
Example
condition1 = [5, 6, 7, 8]condition2 = [6, 7, 8, 9]condition3 = [7, 8, 9, 10]stat, p = stats.friedmanchisquare(condition1, condition2, condition3)print(stat, p)Interpretation
p < 0.05→ at least one repeated condition differs
Useful for experiments involving multiple tests on the same participants.
Sign Test (Not in SciPy)
The Sign Test is a simple non-parametric test for paired data.
SciPy does not include it, but you can write your own:
def sign_test(x, y): import numpy as np diff = np.array(y) - np.array(x) pos = np.sum(diff > 0) neg = np.sum(diff < 0) # Two-sided binomial test return stats.binomtest(pos, pos+neg, p=0.5)result = sign_test(before, after)print(result.statistic, result.pvalue)Use only when Wilcoxon assumptions fail (e.g., many zeros).
Choosing Non-Parametric Tests
Goal | Parametric Equivalent | Non-Parametric Version |
Compare 2 independent groups | Independent t-test | Mann–Whitney U |
Compare 2 related groups | Paired t-test | Wilcoxon |
Compare 3+ independent groups | ANOVA | Kruskal–Wallis |
Compare 3+ repeated measures | Repeated-measures ANOVA | Friedman |
Before/After with weak assumptions | Paired t-test | Sign Test |