🎉 75% of content is free forever — Unlock Premium from $10/mo →
CW
Search courses…
💼 Servicesℹ️ About✉️ ContactView Pricing Plansfrom $10

Wilcoxon Signed-Rank Test — Nonparametric Paired Test

Nonparametric TestsNonparametric Tests🟢 Free Lesson

Advertisement

Wilcoxon Signed-Rank Test

Nonparametric Tests

The Nonparametric Alternative to the Paired t-Test

When your data violates normality assumptions, the Wilcoxon signed-rank test provides a robust alternative for comparing paired observations. It's essential for analyzing ordinal data, Likert scales, and small samples where normality cannot be verified.

  • Clinical Trials — Assess treatment effects on patient symptom ratings before and after intervention
  • Quality Control — Compare measurements from two instruments without assuming normal distributions
  • Survey Research — Analyze pre-post responses on non-normal ordinal scales

When normality fails, ranks still speak the truth about paired differences.


The nonparametric alternative to the paired t-test. Tests whether the median of differences equals zero, without assuming normality.

import numpy as np
from scipy import stats

np.random.seed(42)
before = np.array([85, 90, 78, 92, 88, 76, 95, 82, 87, 91, 73, 89])
after  = np.array([78, 82, 75, 88, 85, 70, 89, 79, 80, 86, 68, 84])
differences = before - after

print(f"Median difference: {np.median(differences):.2f}")

# Wilcoxon signed-rank test
stat, p = stats.wilcoxon(before, after, alternative='two-sided')
print(f"W = {stat:.2f}, p = {p:.4f}")

# Compare with paired t-test
t, p_t = stats.ttest_rel(before, after)
print(f"Paired t-test: t={t:.4f}, p={p_t:.4f}")

# When to prefer Wilcoxon
print("\nUse Wilcoxon signed-rank when:")
print("* n is small and normality of differences can't be verified")
print("* Differences have heavy tails or outliers")
print("* Data is ordinal")

How It Works

  1. Compute differences dᵢ = x₁ᵢ − x₂ᵢ
  2. Remove zero differences
  3. Rank |dᵢ| (absolute values)
  4. Assign signs from original dᵢ
  5. W = sum of positive ranks (or negative ranks)
  6. Compare W to null distribution
# Manual computation
d = before - after
d_nonzero = d[d != 0]
n = len(d_nonzero)

ranks = stats.rankdata(np.abs(d_nonzero))
W_plus = ranks[d_nonzero > 0].sum()
W_minus = ranks[d_nonzero < 0].sum()
W = min(W_plus, W_minus)

print(f"W+ = {W_plus:.1f}, W- = {W_minus:.1f}, W = {W:.1f}")
print(f"n = {n}")

Key Takeaways

Need Expert Statistics Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement