Answer
What are the assumptions of the Wilcoxon signed-rank test?
The short answer
It assumes independent pairs, differences whose sizes can be ranked, and differences symmetric about their centre. If your null is that the conditions make no difference at all, symmetry about zero holds automatically under it, so the test is valid. Symmetry matters for interpretation: with skewed differences the test is about the pseudomedian, not the median. A symmetry test with p > .05 on 15 pairs proves little.
The short answer
The Wilcoxon signed-rank test is the rank-based alternative to the paired t test. You compute one difference per pair (for example, each person's score in condition B minus their score in condition A), rank the absolute differences, and add up the ranks that belong to the positive differences. If the conditions do not matter, positive and negative differences should get roughly equal shares of the ranks.
It does not assume normality. It does assume three things: the pairs are independent of each other, the differences are measured precisely enough that their sizes can be ranked, and the differences are symmetric about their centre. The third one is the most misunderstood, and it matters less for the validity of the test than for how you read the result.
What each assumption means
- Independent pairs. Each person (or unit) contributes one difference, and one person's difference tells you nothing about another's. The two measurements within a person are expected to be related; that is the point of pairing. If a person has several trials per condition, average them into one difference first, or use a mixed model.
- Rankable differences. The test ranks the sizes of the differences, so a difference of 6 must genuinely be larger than a difference of 4. That works for continuous measures such as angles, times or scale scores. For a single ordinal item (a 5-point rating), differences are not really comparable in size, and the sign test is the safer choice.
- Few ties and zeros. The exact p value assumes no tied absolute differences and no zero differences. With ties or zeros, software switches to a normal approximation with corrections, which is fine but should be mentioned.
- Symmetry of the differences. The distribution of the differences should be symmetric about some centre. When it is, the mean, the median and the pseudomedian (the Hodges-Lehmann estimate) coincide, and the test is a clean test of whether that centre is zero.
Why symmetry matters, and why a symmetry test cannot settle it
Formally, the null hypothesis is that the differences are symmetric about zero. In a paired design where the null is "the condition has no effect at all", the two measurements on each person are interchangeable under that null, so their difference is automatically symmetric about zero. In that case the test is valid without any extra check: its false-positive rate is what it claims to be.
Symmetry becomes important when you want to say what shifted. If the differences are skewed, the test is sensitive to the pseudomedian (the median of all pairwise averages of the differences), not the median. The simulation below shows the consequence: with skewed differences whose median is exactly zero, the signed-rank test still rejects "centre = 0" far more often than 5%, because the pseudomedian is not zero. So a significant result then means "the differences tend to be positive", not "the median difference is not zero".
Running a formal test of symmetry and treating p > .05 as proof does not help. With 15 pairs such tests have very little power, so a non-significant result mostly reflects the small sample. This is the same trap as pre-testing for normality (see Is a normality test worth running on your data?). Choosing the test based on a pre-test also changes the error rates of the whole procedure. Look at a dot plot of the differences, think about how the data arise, and decide what you want to estimate.
See it in R and Python
The code runs the test on 15 made-up paired differences, reports the Hodges-Lehmann estimate with its exact 95% confidence interval and a rank-biserial effect size, and then simulates 10,000 samples of 15 to compare the signed-rank test with the sign test when the differences are symmetric and when they are skewed.
R
set.seed(677151)
# 1. Paired design: 15 people measured under two conditions.
# d = condition B minus condition A, one difference per person
d <- c(4.2, 7.9, -1.3, 5.6, 3.1, 9.4, 2.7, -2.2, 6.8, 1.9,
4.9, 8.3, 0.6, 3.8, 5.2)
wt <- wilcox.test(d, mu = 0, conf.int = TRUE) # same as paired = TRUE on the raw columns
unname(wt$statistic) # V = sum of ranks of the positive differences
round(wt$p.value, 4)
round(c(pseudomedian = unname(wt$estimate), wt$conf.int), 2)
round(c(median = median(d), mean = mean(d), sd = sd(d)), 2)
# Matched-pairs rank-biserial correlation (effect size)
rk <- rank(abs(d))
round((sum(rk[d > 0]) - sum(rk[d < 0])) / sum(rk), 3)
# 2. Why symmetry matters: how often is H0 "centre = 0" rejected at 5%?
reject <- function(gen, reps = 10000, n = 15) {
res <- replicate(reps, {
x <- gen(n)
c(signed_rank = wilcox.test(x, mu = 0)$p.value < 0.05,
sign_test = binom.test(sum(x > 0), n)$p.value < 0.05)
})
rowMeans(res)
}
# Symmetric about 0 with heavy tails: both tests stay at or below 5%
round(reject(function(n) rt(n, df = 3)), 3)
# Skewed, but the median is exactly 0: the signed-rank test rejects too often
round(reject(function(n) rexp(n) - log(2)), 3)
# The signed-rank test targets the pseudomedian, which is not 0 here
x <- rexp(1e6) - log(2)
round(median((x[1:5e5] + x[5e5 + 1:5e5]) / 2), 3)Python
import numpy as np
from scipy import stats
rng = np.random.default_rng(677151)
# 1. Paired design: 15 people measured under two conditions.
# d = condition B minus condition A, one difference per person
d = np.array([4.2, 7.9, -1.3, 5.6, 3.1, 9.4, 2.7, -2.2, 6.8, 1.9,
4.9, 8.3, 0.6, 3.8, 5.2])
n = len(d)
rk = stats.rankdata(np.abs(d))
V = rk[d > 0].sum() # sum of ranks of the positive differences
p = stats.wilcoxon(d, method="exact").pvalue
print("V", V, "p", round(p, 4))
# Hodges-Lehmann (pseudomedian) estimate and exact 95% CI, as in R's wilcox.test
walsh = np.sort([(d[i] + d[j]) / 2 for i in range(n) for j in range(i, n)])
counts = np.array([1]) # exact null distribution of V
for k in range(1, n + 1):
counts = np.concatenate([counts, np.zeros(k)]) + np.concatenate([np.zeros(k), counts])
cdf = np.cumsum(counts) / 2**n
qu = max(int(np.argmax(cdf >= 0.025 - 1e-10)), 1)
ql = n * (n + 1) // 2 - qu
print("pseudomedian", round(np.median(walsh), 2), "CI", round(walsh[qu - 1], 2), round(walsh[ql], 2))
print("median", round(np.median(d), 2), "mean", round(d.mean(), 2), "sd", round(d.std(ddof=1), 2))
# Matched-pairs rank-biserial correlation (effect size)
print("rank-biserial", round((rk[d > 0].sum() - rk[d < 0].sum()) / rk.sum(), 3))
# 2. Why symmetry matters: how often is H0 "centre = 0" rejected at 5%?
def reject(gen, reps=10000, n=15):
sr = st = 0
for _ in range(reps):
x = gen(n)
sr += stats.wilcoxon(x, method="exact").pvalue < 0.05
st += stats.binomtest(int((x > 0).sum()), n).pvalue < 0.05
return {"signed_rank": round(sr / reps, 3), "sign_test": round(st / reps, 3)}
# Symmetric about 0 with heavy tails: both tests stay at or below 5%
print(reject(lambda n: rng.standard_t(3, n)))
# Skewed, but the median is exactly 0: the signed-rank test rejects too often
print(reject(lambda n: rng.exponential(size=n) - np.log(2)))
# The signed-rank test targets the pseudomedian, which is not 0 here
x = rng.exponential(size=1_000_000) - np.log(2)
print(round(np.median((x[:500_000] + x[500_000:]) / 2), 3))The figures below come from one seeded run of the R code. The test on the fixed data (part 1) involves no randomness, and the Python version reproduces it exactly. Python's random numbers differ from R's, so its simulated rates differ slightly (for example 7.8% instead of 8.2%), but they show the same pattern.
- The example. Thirteen of the 15 differences are positive. The signed-rank statistic is V = 114 (out of a maximum of 120), with an exact p = .0009. The Hodges-Lehmann estimate of the shift is 4.15, 95% CI [2.15, 6.05]; the sample median is 4.20 and the mean 4.06 (SD = 3.39). The rank-biserial correlation is .90.
- Symmetric differences. With heavy-tailed but symmetric differences centred on zero (a t distribution with 3 df), the signed-rank test rejected in 4.5% of samples and the sign test in 3.3%. Both behave as advertised; the sign test is a little conservative with 15 pairs.
- Skewed differences with a median of zero. Here the signed-rank test rejected in 8.2% of samples, while the sign test stayed at 3.3%. The reason is that the pseudomedian of these differences is about 0.147, not zero. The signed-rank test is doing its job, but its job is not a test of the median.
What to do in practice
- If your question is "does the condition change the outcome at all?", the signed-rank test is valid for independent pairs without a symmetry check. Report the Hodges-Lehmann estimate and its confidence interval as the size of the shift.
- If you specifically want to test or estimate the median difference and the differences look clearly skewed, use the sign test (a binomial test on the number of positive differences), accepting that it has less power.
- If the differences look roughly normal, the paired t test is also fine and gives a confidence interval for the mean difference.
- If you test several outcomes (for example several movements or tasks), adjust for multiple comparisons, for instance with the Holm method, and say so.
- Plot the differences. A simple dot plot of 15 differences tells you more about skew and outliers than any formal test at that sample size.
Not sure whether a paired test is the right tool at all? Try the test chooser. For more plain-language guides to planning and reporting analyses, see the DASS blog.
How to report a Wilcoxon signed-rank test in APA style (7th edition)
Name the test, give the statistic and the exact p value (or p < .001 when it is smaller), and add an effect size and an estimate of the shift with its confidence interval. Using the example above:
"Scores were higher in condition B than in condition A for 13 of 15 participants (Mdn difference = 4.20). A Wilcoxon signed-rank test showed that this difference was statistically significant, V = 114, p < .001, with a Hodges-Lehmann estimated shift of 4.15, 95% CI [2.15, 6.05], and a matched-pairs rank-biserial correlation of r = .90."
Some software reports the smaller rank sum (T) or a standardised z instead of V; report whichever statistic you used and name it. In the method section, state that you used the exact test (or the normal approximation, and how ties and zero differences were handled) and any correction for multiple comparisons.
Related tools and guides
- APA 7 formatter for nonparametric tests
- Check a reported p-value
- Which statistical test should I use?
- Is a normality test worth running on your data?
- What do p values and t values actually mean?
- Wilcoxon signed-rank test (Wikipedia)
- Hodges-Lehmann estimator (Wikipedia)
More answered questions
- What do p values and t values actually mean?
- What are degrees of freedom in statistics, really?
- Is there a 95% probability that your confidence interval covers the true mean?
Working with your own data?
General answers only go so far. Send us your situation and we'll reply by email within two business days.
Ask your questionWritten by AskStats with AI assistance. This is general information, not advice for your specific data or study. When the results matter, check your approach with a qualified statistician.