2
$\begingroup$

I'm running a pre-post hypothesis test on a small dataset, due to it's size n = 12 I am running the test for the exact distribution.

df = 
ID  Period  Varieble    Value
1   0 Month Something   18
1   3 Month Something   26
2   0 Month Something   23
2   3 Month Something   4
3   0 Month Something   24
3   3 Month Something   3
4   0 Month Something   27
4   3 Month Something   26
5   0 Month Something   9
5   3 Month Something   0
6   0 Month Something   40
6   3 Month Something   3
7   0 Month Something   17
7   3 Month Something   10
8   0 Month Something   33
8   3 Month Something   9
9   0 Month Something   6
9   3 Month Something   7
10  0 Month Something   8
10  3 Month Something   1
11  0 Month Something   9
11  3 Month Something   4
13  0 Month Something   26
13  3 Month Something   9

This works fine in python:

dfb = df.query('Period == "0 Month"')

dfa = df.query('Period == "3 Month"')

wilcoxon(dfb.Value, dfa.Value, alternative='two-sided', correction=True, 
          mode ='exact',)

Result = WilcoxonResult(statistic=7.5, pvalue=0.01220703125)

When I try to do the same in R I get a different result as it defaults to the Normal Approximation and provides the warning:

Warning message:
"In wilcox.test.default(dfb$Value, dfa$Value, paired = TRUE, 
         exact = TRUE,  :
  cannot compute exact p-value with ties"

R Code:

dfb <- filter(df, Period == "0 Month")
dfa <- filter(df, Period == "3 Month")

wilcox.test(dfb$Value,dfa$Value,paired=TRUE, exact = FALSE, 
       alternative = 'two.sided')

Result:V = 70.5, p-value = 0.01494

Is there a statistically sound reason why R is defaulting to the normal approximation due to the existing ties? I can't find this in any of the literature.

Conversely, is the method that the scipy library is using valid?

$\endgroup$
1

2 Answers 2

3
$\begingroup$

You should note the following paragraph in the scipy manual:

To derive the p-value, the exact distribution (mode == 'exact') can be used for sample sizes of up to 25. The default mode == 'auto' uses the exact distribution if there are at most 25 observations and no ties, otherwise a normal approximation is used (mode == 'approx').

(bolding is my own). The question remains why the results differ.

$\endgroup$
5
  • 1
    $\begingroup$ Thank you. Should we not then expect the scipy derived p-value to match that of the R one? In this case R calculates a p-value = 0.0149 and python returns p-value = 0.0122 $\endgroup$
    – John Conor
    Commented Mar 22, 2022 at 19:45
  • $\begingroup$ indeed. I cannot find the source code for the python function, but I would compare that to the R source. In particular i would note that the "statistic" these two functions output is different (7.5 vs 70.5). Which makes me think the scipy implementation does not match $\endgroup$
    – bdeonovic
    Commented Mar 22, 2022 at 20:00
  • 1
    $\begingroup$ It's very odd, when I change the mode = 'approx' in scipy I get the exact same result as in R p-value=0.0149. Which suggest it is carrying out some other calcualtion when set to 'exact'. The even stranger thing is that it defaults to 'exact' in scipy. It only changes to 'approx' when I force it, which is how I noticed a difference in the first place. $\endgroup$
    – John Conor
    Commented Mar 22, 2022 at 20:07
  • $\begingroup$ I would submit a bug report on their github. $\endgroup$
    – bdeonovic
    Commented Mar 23, 2022 at 2:00
  • $\begingroup$ It's just that there are different ways to calculate the test and derive the p-value. If you run an exact test in R, for example by using the coin package, it will match your results from the exact test in Python. Likewise, as you note, you can ask Python to perform the test to match the method used by default in R when there ties. Note also that with the Wilcoxon signed rank test, that there are different ways to handle the tied values, which may affect the results. ... None of these methods is "wrong". It's just that there are different methods, particularly with ties. $\endgroup$ Commented Jun 6, 2022 at 13:14
1
$\begingroup$

I don't have enough reputation points to add this as a comment, so although not an answer, hope it does help.

I've adjusted your code a bit for convenience:

import numpy as np
dfa = np.array([26, 4, 3, 26, 0, 3, 10, 9, 7, 1, 4, 9])
dfb = np.array([18, 23, 24, 27, 9, 40, 17, 33, 6, 8, 9, 26])
d = dfb - dfa

One thing to notice is that in the differences a few will have the same absolute value, and will therefore get the same rank.

If I run the following:

wilcoxon(d, alternative='two-sided', correction=False, mode ='exact')

The result of a statistic of 7.5 and a pvalue of 0.012207 is the same as when I run my own exact test but with a statistic of 8. I've made my own using the information from https://www.real-statistics.com/non-parametric-tests/wilcoxon-signed-ranks-test/wilcoxon-signed-ranks-exact-test/

It could be that scipy simply rounds the test statistic, but that is just a guess and it might be using something far more complex (perhaps something from https://www.jstor.org/stable/2284536 but I haven't read the article myself yet).

The result from R can be obtained using:

wilcoxon(d, alternative='two-sided', correction=True, mode ='approx')

So R uses the normal approximation, with a continuity correction (which is different from the correction for ties).

Hope this helps a bit.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.