Preprocessing pipeline -- bandpass filtering, autoreject, and ICA.

Hi,

I’m currently developing a pre-processing pipeline for a memory study consisting of 57 datasets, each of which is ~1.5 GB. So far, I’ve been sticking to typical EEG pre-processing procedures: I’ve imported the raw data; set the EEG reference (in my case, to the ‘Fz’ electrode); down-sampled from 2048 to 256 Hz; applied low- and high-pass filtering at 30 and 0.1 Hz, respectively; imported event IDs; and created epochs. Up to this point in the pipeline, everything seems to be going swimmingly.

Following this minimal preprocessing, I also wish to perform artifact rejection by implementing Autoreject and ICA. I’ve read through numerous tutorials on the MNE and Autoreject websites, yet these seem to be laden with inconsistent suggestions for how to properly sequence these methods. Based on what I’ve taken away from the tutorials and examples, I’ve structured these additional steps in my pipeline as follows :

  1. First run of autoreject
  2. Apply ICA
  3. Second run of autoreject

Translating these steps into code (which I brought in from the examples) yields the following:

#First instance of Autoreject

ar = autoreject.AutoReject(n_interpolate=[1, 4, 32], random_state=42,
                           n_jobs=1, verbose=True)
ar.fit(epochs)
epochs_ar, reject_log = ar.transform(epochs, return_log=True)

#Apply ICA

ica = mne.preprocessing.ICA(random_state=99)
ica.fit(epochs[~reject_log.bad_epochs])
exclude = [0,  # blinks
           2  # saccades
]
ica.plot_components(exclude)
ica.exclude = exclude

#Second instance of Autoreject

ar = autoreject.AutoReject(n_interpolate=[1, 4, 32], random_state=42,
                           n_jobs=1, verbose=True)
ar.fit(epochs)
epochs_ar, reject_log = ar.transform(epochs, return_log=True)

Note that the epochs that were fed into the first instance of Autoreject were not baseline corrected, so as not to affect their subsequent processing when applying ICA. Hence, baseline correction was only applied before submitting the ICA-ed epochs to the second instance of Autoreject. Can someone please confirm/disconfirm whether these steps are appropriate?

EDIT: I’m working with the latest release of MNE (1.11.0) on a Window’s 10 system.

Best,

Jacob

Hi Jacob,

pipeline sounds very reasonable. I remember from my own experience with autoreject than it can throw out a lot epochs if you run it before ICA (e.g. if you have strong eye movement related artefacts). This depends a lot on your dataset and the experimental setup (e.g. do you expect eye movements at specific timepoints during the epochs etc.). I suggest checking the autoreject output and visually inspect rejected epochs to make sure that you don’t loose too much data. You mentioned multiple datasets, so the parameters for autoreject might need to be ajdusted depending on the noise level in each dataset.

Regarding baseline correction, I don’t see that in your code?

I usually only baseline correct before I average epochs, is there a specific reason for baseline correction before the second round of autoreject?

Hope this was helpful.

Cheers,

Carina

Hi Carina,

Thanks for your reply! Indeed, a significant number of epochs were dropped when AutoReject was implemented before applying ICA (89/240, or approximately ~37% of the total number of epochs). Note that this sequencing is consistent with what’s outlined on the Autoreject website ( Preprocessing workflow with autoreject and ICA — autoreject 0.4.2 documentation ); they suggest to “first highpass filter the data, then run autoreject (local) and supply the bad epochs detected by it to the ICA algorithm for a robust fit, and finally run autoreject (local) again.” Perhaps this is overly conservative for my case, and maybe only a single run of AutoReject (after applying ICA) is needed to obtain good quality data. I’ll also take a look at the rejection log to see whether some of the discarded epochs can be salvaged.

As for the baseline correction, it seems that I accidentally omitted this line in my original comment. Thank you for pointing this out – the code should read as follows:

#FIRST RUN OF (LOCAL) AUTOREJECT

ar = autoreject.AutoReject(n_interpolate=[1, 4, 32], random_state=42,
n_jobs=1, verbose=True)
ar.fit(epochs)
epochs_ar, reject_log = ar.transform(epochs, return_log=True)

#APPLY ICA

ica = mne.preprocessing.ICA(random_state=99)
ica.fit(epochs[~reject_log.bad_epochs])
exclude = [0,  # blinks
2  # saccades
]
ica.plot_components(exclude)
ica.exclude = exclude

#SECOND RUN OF (LOCAL) AUTOREJECT, WITH BASELINE CORRECTION

epochs.apply_baseline((None, 0))

ar = autoreject.AutoReject(n_interpolate=[1, 4, 32], random_state=42,
n_jobs=1, verbose=True)
ar.fit(epochs)
epochs_ar, reject_log = ar.transform(epochs, return_log=True)

As mentioned earlier, I did not want to apply baseline correction before applying ICA, as the MNE tutorials note that doing so can lead to suboptimal ICA decomposition. Hence, I only applied baseline correction before the second round of AutoReject to prepare those epochs for later ERP analyses. In my head, this approach seems logical, but I would appreciate opinions from more experienced EEG data-analysts.

Cheers,

Jacob