Skip to content
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

NitfiMasker Not removing confounds #3434

Closed
DasDominus opened this issue Dec 1, 2022 · 10 comments
Closed

NitfiMasker Not removing confounds #3434

DasDominus opened this issue Dec 1, 2022 · 10 comments
Labels
Usage Usage-related questions, to be forwarded to NeuroStars.

Comments

@DasDominus
Copy link

So I tried to extract signal from the fMRI image with a given mask
and loading confounds retrieved from fmriprep. below is what I did:

The issue is, extracted signal when cross-correlated, shows significant impact from low-drift signals
image

This is very likely the result from not having done high_pass filtering.
However, I have passed in high_pass when loading confounds and I can confirm these are populated in fmriprep results.

Nilearn version:

Expected behavior

Get signals that are high_pass filtered
image

Actual behavior

data are likely not high_pass filtered

Steps and code to reproduce bug

        data_confounds_simple, sample_mask = load_confounds(
        data,
        strategy=["compcor", "high_pass", "motion", "wm_csf"],
        motion="basic", wm_csf="basic", global_signal="basic")

                mask_img = resample_to_img(
                  path,
                  data[f'{conditions[0]}_mask'],
                  interpolation='nearest'
                )

              masker = NiftiMasker(
                  mask_img=mask_img,
                  standardize=False,
                  memory=f"{path}/nilearn_cache")

            raw_signal = masker.fit_transform(
                        imgs, confounds=confounds
                    )
            pd.DataFrame(raw_signal).to_csv(fn)
@DasDominus DasDominus added the Bug for bug reports label Dec 1, 2022
@DasDominus
Copy link
Author

yeah confirmed this by passing explicit high_pass filter (1/128) to signal.clean

Not sure why high_pass in confounds didn't do the cleaning

@htwangtw
Copy link
Member

htwangtw commented Dec 1, 2022

Putting some relevant part of the code for discussion.
If NiftiMasker is having problem with filtering, all maskers would have the same issue, as they all use this base function to pass extracted signal to signal.clearn:

def _filter_and_extract(

For high pass filtering, fMRIPrep provides cosine drift terms and nilearn function simply regressing out the regressors. This is a different high-pass filtering method comparing to the butterworth filter accessed through the high_pass parameter in signal.cleans

In other words, this can be a fMRIPrep issue, but I will have to have a further look.

I would be curious to see if we generate cosine drift terms, instead of using fMRIPrep supplied ones, what difference will it make.

@htwangtw
Copy link
Member

htwangtw commented Dec 1, 2022

yeah confirmed this by passing explicit high_pass filter (1/128) to signal.clean

Not sure why high_pass in confounds didn't do the cleaning

@DasDominus Which method? The default is butterworth and there is an option for cosine drift terms. If you used butterworth, can you report back what is it like for the cosine option?

@DasDominus
Copy link
Author

thanks! @htwangtw

yeah, it seems it's a different approach.
Just tried with

rr1 = nilearn.signal.clean(rr1.to_numpy(),  high_pass=1/128, filter='cosine')

image

but also this could be due to I'm passing in high_pass threshold.

However, I don't think a filter option is provided for nilearn.maskers.NiftiMasker so seems it's using default aka butterworth

@DasDominus
Copy link
Author

I lack the expertise to debug this, tho I'm happy to provide the data & fmriprep confounds used for reproduction
let me know if that's needed

@htwangtw
Copy link
Member

htwangtw commented Dec 1, 2022

I don't think a filter option is provided for nilearn.maskers.NiftiMasker so seems it's using default aka butterworth

This is something that worth an issue. thanks for catching this!

@htwangtw
Copy link
Member

htwangtw commented Dec 1, 2022

I got some code to show the cosine option and fmriprep cosine term creates similar results:

from nilearn.datasets import fetch_development_fmri, fetch_atlas_basc_multiscale_2015
from nilearn.interfaces.fmriprep import load_confounds
from nilearn.maskers import NiftiLabelsMasker
from nilearn.signal import clean
import matplotlib.pyplot as plt


data = fetch_development_fmri(n_subjects=1, reduce_confounds=False)
atlas = fetch_atlas_basc_multiscale_2015(version='asym')

atlas_path = atlas.scale064
img = data.func[0]
high_pass_fmriprep, _ = load_confounds(img, strategy=['high_pass'])

masker = NiftiLabelsMasker(atlas_path)
raw_signal = masker.fit_transform(img)

fmriprep_cleaned = clean(raw_signal, confounds=high_pass_fmriprep)
nilearn_cleaned = clean(raw_signal, filter='cosine', high_pass=1/128)

plt.plot(fmriprep_cleaned[:, 0])
plt.plot(nilearn_cleaned[:, 0])

image

@htwangtw
Copy link
Member

htwangtw commented Dec 1, 2022

To conclude, I cannot reproduce the problem described by @DasDominus.
This question might be more appropriate to be discussed on https://neurostars.org/
There's a lot to unpack before we can conclude this is an issue in nilearn, or fmriprep implementation.

@htwangtw htwangtw added Usage Usage-related questions, to be forwarded to NeuroStars. and removed Bug for bug reports labels Dec 1, 2022
@DasDominus
Copy link
Author

thanks @htwangtw ! I suspect behavior might differ when directly using NiftiMasker to get raw signals
I'll try to repo this weekend

@htwangtw
Copy link
Member

htwangtw commented Dec 7, 2022

I am closing this issue for now as there's no updates.

@htwangtw htwangtw closed this as completed Dec 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Usage Usage-related questions, to be forwarded to NeuroStars.
Projects
None yet
Development

No branches or pull requests

2 participants