Written and maintained by CASRAI Editorial Board
Last updated
In R, both Wilcoxon tests live in one function, wilcox.test() in the stats package, and a single argument decides which one you get. That convenience hides three defaults that cause most of the trouble people run into: the statistic R prints is not the one SPSS or a journal template expects, R switches from the exact test to a normal approximation on its own and only tells you in a warning, and the confidence interval it can produce does not estimate a difference in medians — R’s own documentation calls that “a common misconception.”
The two tests, and the one argument that separates them
The signature is:
wilcox.test(x, y = NULL,
alternative = c("two.sided", "less", "greater"),
mu = 0, paired = FALSE, exact = NULL, correct = TRUE,
conf.int = FALSE, conf.level = 0.95,
tol.root = 1e-4, digits.rank = Inf, ...)
With paired = FALSE (the default) and two samples, you get the Wilcoxon rank-sum test — equivalent to the Mann–Whitney U test. With paired = TRUE, or with a single vector x, you get the Wilcoxon signed-rank test. There is no separate mannwhitney() function to look for; R treats the two names as the same procedure.
# Two independent groups — rank-sum / Mann-Whitney
wilcox.test(value ~ group, data = df)
wilcox.test(x, y) # same thing, vectors
# Paired / one-sample — signed-rank
wilcox.test(before, after, paired = TRUE)
wilcox.test(differences) # equivalent, if you pre-computed them
Two mechanical traps in the formula interface. The grouping variable must resolve to exactly two levels, so a factor carrying an unused third level from a subset — a level with zero rows still counts — will stop the call; droplevels() on the subsetted data frame clears it. And paired = TRUE pairs by position, not by any ID column: x[1] is matched to y[1] and so on, so if the two vectors were pulled from separately sorted or separately filtered frames, R will happily test the wrong pairs and report a perfectly clean p-value. Reshape from a wide frame where the pairing is structural, rather than assembling two vectors and trusting the order.
What W and V actually are
This is the single most common reporting error, because R does not print the statistic other packages print.
For the two-sample test, R labels the statistic W, and it is the Mann–Whitney U statistic. R computes the rank sum of the first sample and subtracts its minimum possible value, m(m+1)/2, for a first sample of size m. The documentation gives the equivalent combinatorial definition: R’s value “can also be computed as the number of all pairs (x[i], y[j]) for which y[j] is not greater than x[i], the most common definition of the Mann-Whitney test.” So R’s W is U — despite the letter. Note that it is U for the sample you passed first; swap the arguments and you get the complementary value, mn − U.
For the paired/one-sample test, R labels the statistic V, and it is the sum of the ranks of the absolute differences that were positive.
What this means in practice: a journal asking for “U” wants R’s W; a journal or a supervisor asking for the W of the classical Wilcoxon rank-sum formulation wants the raw rank sum, which is R’s W plus m(m+1)/2. And R does not print a Z score at all, whereas SPSS reports U and Z together. If you need Z — and you do, if you want the conventional r effect size — you have to get it from the coin package rather than from base R. Analysts crossing between packages should also note that Stata’s ranksum command reports z rather than U, so all three environments print a different number for the same test.
The exact/approximate switch happens without you asking
The exact argument defaults to NULL, which means “decide for me.” The documentation states the rule: “By default (if exact is not specified), an exact p-value is computed if the samples contain less than 50 finite values and there are no ties.”
Both clauses matter, and the second one is where real data lands. Ties are close to guaranteed in the kinds of data people reach for a Wilcoxon test for — Likert items, ordinal scores, rounded lab values, anything with a floor at zero. The moment a tie appears, R abandons the exact permutation distribution, falls back to the normal approximation, and tells you only through a warning:
Warning message:
In wilcox.test.default(x, y) : cannot compute exact p-value with ties
The paired test has a second version of this. The signed-rank test has nothing to do with pairs whose difference is exactly zero, so those pairs are discarded — which also blocks the exact calculation and produces cannot compute exact p-value with zeroes. Both warnings are frequently silenced by adding exact = FALSE, which suppresses the message without changing anything about the computation. That is a reasonable thing to do once you know that you are reporting an approximate p-value; it is not a fix, and it should not be the reflex.
If you genuinely need an exact p-value in the presence of ties, base R cannot give you one, but two packages can. The coin package’s wilcox_test() performs exact inference using the conditional (permutation) distribution given the observed ranks, via an implementation of the Streitberg–Röhmel shift algorithm; exactRankTests offers wilcox.exact() for the same purpose. Alternatively, sidestep the ranking question entirely with a permutation test on the raw values.
# Exact p-value even with ties
library(coin)
wilcox_test(value ~ factor(group), data = df, distribution = "exact")
Note the factor(): coin requires the grouping variable to be a factor and will not silently coerce a character or numeric column.
One caution in the other direction. The help page carries an explicit warning that wilcox.test “can use large amounts of memory and stack (and even crash R if the stack limit is exceeded) if exact = TRUE and one sample is large.” Forcing exact = TRUE on a big sample to be safe is not the conservative choice it appears to be.
Spurious ties from floating point
A subtler problem: values that are mathematically distinct can differ only in the last bits after a computation, and R will treat them as tied. The digits.rank argument exists for exactly this. The documentation advises that “for stability reasons, it may be advisable to use rounded data or to set digits.rank = 7, say, such that determination of ties does not depend on very small numeric differences.” If your ties warning appears on data you believed had no exact repeats, this is usually why.
You are not testing medians, and the CI is not a difference in medians
Two separate claims here, both routinely garbled.
First, the null hypothesis. R states it as “the distributions of x and y differ by a location shift of mu.” That is a location-shift null, and it assumes the two distributions have the same shape and spread. When shapes differ — unequal variances, one group skewed and the other not — a significant rank-sum result tells you the groups are stochastically different, not that their medians differ. It can reject when the medians are identical. This is the point people most often carry away wrong, and it is worth reading up on the full set of assumptions the Mann–Whitney test actually makes before writing a median claim into a results section. The parallel issue for the paired test — symmetry of the differences, not normality — is covered in the signed-rank assumptions guide.
Second, the confidence interval. conf.int is FALSE by default, so most people never request one and report a bare p-value with no estimate of magnitude at all. Turn it on:
wilcox.test(value ~ group, data = df, conf.int = TRUE)
Now read what you get carefully. R’s documentation is unusually blunt about it: “in the two-sample case the estimator for the difference in location parameters does not estimate the difference in medians (a common misconception) but rather the median of the difference between a sample from x and a sample from y.” That quantity is the Hodges–Lehmann estimator — the median of all pairwise differences between the groups. In the one-sample and paired case the target is the pseudomedian of the differences, again not the median of the differences. The two coincide when the location-shift model holds, and can diverge when it does not.
When exact p-values are available, R produces an exact interval by the Bauer (1972) algorithm and uses the Hodges–Lehmann estimator. Otherwise the interval and point estimate rest on normal approximations, and per the documentation these “are continuity-corrected for the interval but not the estimate” — so a point estimate can sit fractionally off-centre in its own interval. That is expected behaviour, not a bug. The correct = TRUE default applies the continuity correction to the normal approximation of the p-value.
Effect size
The commonest convention is the rank-biserial correlation or the effect size r. The rstatix package computes r as Z/√N, taking Z from coin::wilcox_test() for independent samples and coin::wilcoxsign_test() for paired ones. For the paired case, N is the number of pairs — equivalently the number of difference scores — not the total number of observations, because the paired test reduces to a one-sample test on the differences. Halving that denominator by mistake inflates r substantially.
library(rstatix)
df %>% wilcox_effsize(value ~ group)
df %>% wilcox_effsize(value ~ time, paired = TRUE)
rstatix documents the usual interpretation bands for r: 0.10 to < 0.30 small, 0.30 to < 0.50 moderate, ≥ 0.50 large. Treat these as conventions rather than as anything derived from your measurement context — they are the standard Cohen-style thresholds, and what counts as a meaningful shift in your outcome is a domain judgement, not a statistical one.
The zero-handling discrepancy nobody mentions
If you run a paired test in base R and again in coin, and your data contains pairs with zero difference, you can get two different p-values from the same data. This is not a bug in either package; they use different published conventions.
Base R’s wilcox.test uses the classical Wilcoxon approach: discard the zero differences, then rank the remaining absolute differences. coin’s wilcoxsign_test() exposes a zero.method argument and defaults to "Pratt", which “first rank-transforms the absolute differences (including zeros) and then discards the ranks corresponding to the zero-differences.” Setting zero.method = "Wilcoxon" reproduces the base R convention, which “first discards the zero-differences and then rank-transforms the remaining absolute differences.”
Pratt’s method keeps the zeros in the ranking, so the surviving ranks are larger, and it is generally the more conservative of the two. If you have a non-trivial number of exact ties between paired measurements — common with coarse ordinal scales — say which convention you used. Otherwise a reanalysis in a different package will not reproduce your number and neither of you will know why.
When to use Brunner–Munzel instead
If the concern is that the two groups differ in spread or shape rather than purely in location, the rank-sum test is answering a question you may not want asked. The Brunner–Munzel test is the usual remedy — roughly what Welch’s t-test is to Student’s, it tests stochastic equality without assuming equal distribution shapes, and is robust to heteroscedasticity.
In R it is in the brunnermunzel package, as brunnermunzel.test(), with brunnermunzel.permutation.test() for the permuted version (also reachable via perm = TRUE). It estimates P(X < Y) + 0.5 × P(X = Y), a directly interpretable “relative effect”: the probability that a randomly drawn observation from one group falls below one from the other. Note that the permutation version switches itself back to the standard test when the number of combinations exceeds choose(28, 14), to bound the computation.
Deciding between these families is a design question more than a software question — see parametric versus non-parametric tests for the trade-offs, and the Kruskal–Wallis test if you have three or more groups rather than two.
A reporting template that survives review
Report enough that someone can reproduce the number and judge the size of the effect:
- Which test, by full name — “Wilcoxon rank-sum” or “Wilcoxon signed-rank”, not just “a Wilcoxon test”.
- The statistic, labelled the way you computed it. If you print R’s output, say so: R’s
Wis U. - Exact or approximate, and if approximate, why — ties, zeroes, or sample size — and whether a continuity correction was applied.
- Group sizes, and for paired data the number of pairs actually analysed after zero differences and incomplete pairs were dropped. This is often smaller than your stated n, and it is the number the test used.
- An effect size with a confidence interval, described accurately — a Hodges–Lehmann location shift, not “the difference in medians”.
- Descriptive medians and IQRs per group, separately from the test. These are what readers actually want, and reporting them does not commit you to the claim that the test compared them.
Frequently asked questions
What is W in the wilcox.test output?
For a two-sample test, W is the Mann–Whitney U statistic for the first sample you passed: the rank sum of that sample minus m(m+1)/2. It is not the classical Wilcoxon rank sum, which is that value plus m(m+1)/2. For a paired or one-sample test the statistic is labelled V and is the sum of the ranks of the positive differences.
How do I run a Mann-Whitney U test in R?
You already have: wilcox.test(x, y) with paired = FALSE is the Mann–Whitney U test. R’s help page describes the rank-sum test as “equivalent to the Mann-Whitney test”. There is no separate function, and packages advertising one are wrapping the same computation.
Should I just add exact = FALSE to get rid of the ties warning?
It removes the message without changing the result, because R had already switched to the normal approximation before it warned you. So it is honest only if you then report the p-value as approximate. If you need a genuine exact p-value with ties present, use coin::wilcox_test(..., distribution = "exact") or exactRankTests::wilcox.exact(), neither of which is limited the way base R is.
Why does R not give me a confidence interval by default?
conf.int defaults to FALSE. Set conf.int = TRUE. Be aware that the interval and estimate describe a Hodges–Lehmann location shift — the median of pairwise differences between groups — and, in R’s own words, do “not estimate the difference in medians”.
Does the Wilcoxon test require my data to be normally distributed?
No — that is the point of it. But “no assumptions” is equally wrong. The two-sample form assumes the distributions differ only by a location shift if you want to interpret it as a statement about location; the paired form assumes the differences are symmetric about the null value. Both assume independent observations, and the paired form assumes independence between pairs, not within them.
Why do my base R and coin results disagree on paired data?
Almost always zero differences. Base R discards zeros before ranking; coin::wilcoxsign_test() defaults to Pratt’s method, which ranks them first and then drops those ranks. Set zero.method = "Wilcoxon" in coin to match base R. A second, rarer cause is that coin computed an exact p-value where base R fell back to the approximation.
Can I use the Wilcoxon test on Likert items?
It is a common choice, and defensible for a single ordinal item, since the test only uses ranks. Expect heavy ties and therefore an approximate p-value by default. The bigger risk is interpretive: with a coarse scale, distributions in two groups often differ in shape as well as location, which is precisely the situation where a significant rank-sum result does not license a claim about medians.
What sample size do I need?
There is no fixed minimum, but with very small samples the exact test may be unable to reach conventional significance at all — with a two-sided test and tiny groups, the smallest attainable p-value can exceed 0.05 regardless of how separated the data are. Check attainable p-values before concluding a null result means anything, and note that R’s automatic exact/approximate rule turns on sample size as well as ties.
References
- R documentation:
wilcox.test— Wilcoxon Rank Sum and Signed Rank Tests (R stats package) - coin: Conditional Inference Procedures in a Permutation Test Framework (CRAN reference manual)
- coin: Symmetry tests, including
wilcoxsign_testand thezero.methodargument - rstatix:
wilcox_effsize— Wilcoxon effect size - brunnermunzel: package usage vignette (CRAN)
- exactRankTests: Exact Distributions for Rank and Permutation Tests (CRAN)
- R Handbook: Two-sample paired signed-rank test
- University of Virginia Library: The Wilcoxon Rank Sum Test








