-
Notifications
You must be signed in to change notification settings - Fork 185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Correct permutation t-tests #684
base: develop
Are you sure you want to change the base?
Conversation
Signed-off-by: gcattan <[email protected]>
Ok thanks ! Just to give more context: we wanted to display the summary plot with many datasets.
When computing the dataset statistics, we spot this warning saying there were some NaN values out of the stouffer method.
When looking at the p-values some were greater or equals to 1.
Envoyé à partir de Outlook pour Android<https://aka.ms/AAb9ysg>
…________________________________
From: Bru ***@***.***>
Sent: Friday, February 7, 2025 6:47:18 PM
To: NeuroTechX/moabb ***@***.***>
Cc: gcattan ***@***.***>; Mention ***@***.***>
Subject: Re: [NeuroTechX/moabb] Correct permutation t-tests (PR #684)
hey @gcattan<https://github.com/gcattan>,
I am not a super expert on t-tests, I am pinging @sylvchev<https://github.com/sylvchev> here.
—
Reply to this email directly, view it on GitHub<#684 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ABPQYJ2C6QG7QBJ7KBH45GL2OTWSNAVCNFSM6AAAAABWWNWHOGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMNBTGU4TKNRQGQ>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
moabb/analysis/meta_analysis.py
Outdated
@@ -121,15 +121,15 @@ def _pairedttest_random(data, nperms): | |||
pvals: ndarray of shape (n_pipelines, n_pipelines) | |||
array of pvalues | |||
""" | |||
out = np.ones((data.shape[1], data.shape[1])) | |||
out = np.zeros((data.shape[1], data.shape[1])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case of exhaustive, this is not necessary.
But in the case of random, the initial statistic is not necessarily among those found within the permutation distribution.
moabb/analysis/meta_analysis.py
Outdated
out[out == nperms] = nperms - 1 | ||
return out / nperms |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be out / (nperms + 1)
instead?
So the correction apply to all p-value? And not to the extreme one only.
Switch back to 1 for the random t-test to have at least 1 in the result. And changed check for p=1 values for _pairedttest_exhaustive to be the same as for _pairedttest_random.
Added comment
This last version was consulted with @Marco-Congedo. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unit tests could be completed to test that p-values are never equal to 0.
return out | ||
out += randperm >= true | ||
|
||
out[out >= nperms] = nperms - 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could add another control to avoid a p-value equal to 0:
out[out >= nperms] = nperms - 1 | |
out[out >= nperms] = nperms - 1 | |
out[out == 0] = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this may deserve a comment in the code. If out
is initialized to 1, or if it is initialized to 0 and we have random >= true
, then this check should not be necessary.
out[out == nperms] = nperms - 1 | ||
out += randperm >= true | ||
|
||
out[out >= nperms] = nperms - 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
out[out >= nperms] = nperms - 1 | |
out[out >= nperms] = nperms - 1 | |
out[out == 0] = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here also, I will add a comment.
moabb/analysis/meta_analysis.py
Outdated
@@ -89,7 +89,7 @@ def _pairedttest_exhaustive(data): | |||
pvals: ndarray of shape (n_pipelines, n_pipelines) | |||
array of pvalues | |||
""" | |||
out = np.ones((data.shape[1], data.shape[1])) | |||
out = np.zeros((data.shape[1], data.shape[1]), dtype=np.int32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initialization of out
should be similar between _pairedttest_exhaustive
and _pairedttest_random
:
out = np.zeros((data.shape[1], data.shape[1]), dtype=np.int32) | |
out = np.ones(data.shape[1:], dtype=np.int32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm ok. But then we will take into account the original statistic two times, as we have random >= true
The main problem was that there were p values produced equal to 1 or bigger than 1. |
Co-authored-by: Quentin Barthélemy <[email protected]> Signed-off-by: gcattan <[email protected]>
Co-authored-by: Quentin Barthélemy <[email protected]> Signed-off-by: gcattan <[email protected]>
Hi @gcattan, thank you for investing time into this issue! As we can see here, custom re-implementations in our codebase are prone to errors. Do you think it would be possible to reimplement these using functions from common libraries, such as scipy.stats.permutation_test, which have been validated by a larger community? If yes, I think it could be done in two steps:
These two steps could be done in two PRs eventually. |
Hi,
|
@PierreGtch Then the question is rather if you want to change the current implementation of What I can do as part of this PR is to validate the latest modification against the datasets we used and push some unit testing as suggested by @qbarthelemy. |
I think it's a great way to go, the less we keep the better.
…On Wed, 12 Feb 2025, 11:23 gcattan, ***@***.***> wrote:
@PierreGtch <https://github.com/PierreGtch> Then the question is rather
if you want to change the current implementation of combine_pvalues:
image.png (view on web)
<https://github.com/user-attachments/assets/cb2822e6-512b-4fa4-a8d6-6a6c558ef642>
What I can do as part of this PR is to validate the latest modification
against the datasets we used and push some unit testing as suggested by
@qbarthelemy <https://github.com/qbarthelemy>.
—
Reply to this email directly, view it on GitHub
<#684 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AKFZNATSJ56423F5BEG76IL2PMOKTAVCNFSM6AAAAABWWNWHOGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMNJTGI4DSMZUGQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Regarding the discussion about 1 and 0, I'll let Sylvain have the final
word and merge
On Wed, 12 Feb 2025, 11:37 Bruno Aristimunha Pinto, ***@***.***>
wrote:
… I think it's a great way to go, the less we keep the better.
On Wed, 12 Feb 2025, 11:23 gcattan, ***@***.***> wrote:
> @PierreGtch <https://github.com/PierreGtch> Then the question is rather
> if you want to change the current implementation of combine_pvalues:
>
> image.png (view on web)
> <https://github.com/user-attachments/assets/cb2822e6-512b-4fa4-a8d6-6a6c558ef642>
>
> What I can do as part of this PR is to validate the latest modification
> against the datasets we used and push some unit testing as suggested by
> @qbarthelemy <https://github.com/qbarthelemy>.
>
> —
> Reply to this email directly, view it on GitHub
> <#684 (comment)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AKFZNATSJ56423F5BEG76IL2PMOKTAVCNFSM6AAAAABWWNWHOGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMNJTGI4DSMZUGQ>
> .
> You are receiving this because you were mentioned.Message ID:
> ***@***.***>
>
|
Sure, but let's wait for testing before merging, this is not covered by the current test suite. I will try to tackle this during the week. |
I never used this code from moabb, so your guess is better than mine :) |
The implementation is custom because you need to correct your p-value for the Stouffer method of combining p-value.
If you really want to move away from custom implementation to a more standardized one, you need to use another method of combining p-value (in MoABB).
Marco can probably advise what it is best to do in this situation.
The trade off is that previously reported analysis may have slightly different result.
Envoyé à partir de Outlook pour Android<https://aka.ms/AAb9ysg>
…________________________________
From: Pierre Guetschel ***@***.***>
Sent: Wednesday, February 12, 2025 12:29:39 PM
To: NeuroTechX/moabb ***@***.***>
Cc: gcattan ***@***.***>; Mention ***@***.***>
Subject: Re: [NeuroTechX/moabb] Correct permutation t-tests (PR #684)
Hi,
the problem is not with the implementation, but with the fact that a permutation test can give a p-value in [1/nperm, 1] and that any p-value equal to 1 will screw up the Liptak (Stouffer) combination function as z(1)=Inf. The proposed solution is to allow p to be in [1/nperm, 1-1/nperm] only. This is not very straight, but i don't see any other solution if the Liptak combination function is to be used. In any case, using any other implementation, one would still need to constraint the p-values in [1/nperm, 1-1/nperm].
I never used this code from moabb, so your guess is better than mine :)
My remark was more general : it is a better habit to use code that is already validated than re-writing custom implementations
—
Reply to this email directly, view it on GitHub<#684 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ABPQYJZV5KNNHJ53XFW3POL2PMWCHAVCNFSM6AAAAABWWNWHOGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMNJTGQZTSNJQHA>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Yeah, and who knows how the problem has been handled before, as it is not uncommon that a pipeline gives worse results as compared to another for all subjects, which by definition results in a p-value of 1 when running a paired t-test. The Fisher combination function does not have this limitation (and probably that is why Fisher did not propose the Liptak combination function) since it is based on the sum of logarithms of the p-values; now, for a permutation test those are in [1/nperm, 1], thus the sum is always defined. However, using the Fisher combination function weights cannot be used anymore and if i understand well currently MOABB weights the combinations to account for the different numerosity in different databases. That is why, all in all, if you wish to stick to the current methodology for comparing pipelines across databases in MOABB, i don't see for the moment a better soluation than artificially restricting the p-values in [1/nperm, 1-1/nperm]. |
One important thing for the future test is that we had undeterministic error. That's it. For the same code and results data it will sometimes produce p values equal or bigger than 1. This is probably because of the random test. So it was actually hard to detect. So if you make a test ... maybe the test should be run 20 times in order to be sure that the handling of the p values is correct. Because even before there were guards for the p values, but they were not working. Or this was the idea - to warn you that these p values are strange. |
I think the
out
array should be initiated withzeros
.If not, then
out
can takenperms+1
as values, and the corrective statements (out[out == nperms] = nperms - 1
) apply on the wrong sample.@bruAristimunha what do you think?