Order of denoising steps including scrubbing - rs-fMRI

Hello everyone,

I’m working on denoising resting-state fMRI data by regressing out nuisance parameters (motion, WM, CSF, etc.), applying filtering, detrending, and performing scrubbing.

Specifically, I want to set the signal in scrubbed volumes to zero while z-scoring the remaining volumes. This approach aim to preserve the temporal structure of the signal, important for dynamic FC.

However, I’m unsure about the correct point in the pipeline to apply scrubbing. I’m currently using the following NiftiLabelsMasker in Nilearn to perform all preprocessing steps except scrubbing:

masker = NiftiLabelsMasker(labels_img=atlas_path, standardize=True, detrend=True, low_pass=0.1, high_pass=0.01, t_r=2.0)
full_ts = masker.fit_transform(fmri_img, confounds=confound_data)

Would it be valid to apply scrubbing after calling fit_transform by zeroing out the scrubbed volumes and re-z-scoring the remaining ones manually?

Any guidance or best practices would be greatly appreciated.
Best regards,
Szymon

NiftiLabelsMasker.fit_transform() accepts a sample_mask parameter to do the scrubbing. I recommend using that parameter instead of scrubbing separately.

Can you clarify what you mean by setting the scrubbed volumes to zero while z-scoring the remaining volumes? Setting “bad” volumes to zero would affect the mean and standard deviation of the time series, so I wouldn’t recommend doing that.

Thank you so much for the answer.

I am trying to do something similar to what was done in this paper:
https://www.science.org/doi/10.1126/sciadv.adr8164

“High-pass temporal filtering >0.013 Hz, (iv) regressing out confounds including the average signal of white matter and cerebrospinal fluid voxels as well as 24 motion parameters (translation and rotation in the three directions, in addition to their squares, derivatives, and squares of derivatives), and (v) scrubbing motion outliers, defined on the basis of root mean squared translation >0.25 mm. The scrubbing was done by setting the signal in motion outlier volumes to zero while Z-scoring the rest of the volumes. This approach, compared to discarding the motion outliers, preserves the temporal structure of the BOLD signal, which is important in calculating dynamic FC.”

The idea is to preserve the shape of the BOLD time series and maintain consistent dimensions of sliding-window functional connectivity dynamics matrices.

I’m not sure how to approach this without interfering with filtering or reintroducing noise to components that were already removed orthogonally.

Thank you very much for any input.

You still don’t want to denoise the data using extreme volumes, so I’d recommend using the sample_mask parameter and then creating an uncensored version of the array out of NaNs.

Something like this maybe:

n_volumes = fmri_img.shape[3]
n_parcels = full_ts.shape[1]
# assumes sample_mask is boolean array with True = good and False = bad
low_motion_idx = np.where(sample_mask)[0]
uncensored_array = np.full((n_volumes, n_parcels), np.nan)
uncensored_array[low_motion_idx, :] = full_ts

I would strongly discourage using 0s in the array, because those are actual values that would skew the correlations. You should be able to adapt the sliding-window FC code to work with NaNs though.

1 Like

If I understand your suggestion correctly:
I should run the masker using the sample_mask to exclude bad volumes (standard scrubbing). Then, reintroduce NaNs into the cleaned time series exactly at the positions of the excluded frames to preserve the original temporal structure. Finally, calculate FC and FCD while properly handling NaNs — i.e., ignoring them in the computations. Is that correct?

Once again, thank you very much for your time

Yes, that’s what I recommend.

That sounds reasonable. I truly appreciate your input - thank you.