mne-python
mne-python copied to clipboard
Addition of a non-projection-based method of removing EOG and ECG artifacts.
Describe the new feature or enhancement
The current SSP and ICA methods of removing EOG and ECG artifacts are really effective, but they do completely zap out 2 or even 3 ranks of data. With many-channel MEG and EEG recordings, that's usually fine, but since MNE-Python is getting used more and more for EEG analysis, also low channel count EEG analysis, perhaps it would be nice to provide an alternative method that is more conservative.
In the past, I've played around with regression-based approaches (regress out the EOG channels from the data), which do work pretty well, but recently @rkobler developed the SGEYESUB algorithm that may be superior.
Do others agree this is worth adding to MNE-Python?
Describe your proposed implementation
Implement mne.preprocessing.sgeyesub
following the reference implementation. It needs epochs of blinks and saccades, which are usually recorded in a dedicated segment of the experiment where the participant is following on-screen directions for blinking and moving their eyes. If you don't have such a segment in your experiment, mne.preprocessing.make_eog_epochs
could be a decent substitute.
Describe possible alternatives
We could decide SSP/ICA is good enough and if people want other algorithms, they can make their own extension packages. Alternatively, we could merge in mne_sandbox.preprocessing.eog_regression
instead.
I'd add the "standard" regression approach first, because that's widely used (and often requested). I have implemented one of the first regression-based approached described in Hillyard & Galambos (1970) here. Can you explain what's different in the approach you implemented in mne-sandbox
(Croft & Barry, 2000)? I've never seen SGEYESUB used before, so it seems rather niche and I would probably not add it right away (at least not before the standard regression approach is available).
Croft & Barry first extract blink and saccade epochs and create ERPs. Then they compute the regression weights on those ERPs. The idea being that the ERPs contain a pretty pure blink without other ongoing EEG, so the weights will be more accurate. Once you have the weights, you apply them on the raw data like in your approach.
Perhaps it's time then to move the EOG regression out of the sandbox into MNE-Python proper ;)
I think so too! It would be nice if that function had a parameter to choose from Croft & Barry and Hillyard & Galambos (since the latter is very often still used today).
Describe your proposed implementation
Implement
mne.preprocessing.sgeyesub
following the reference implementation.
reference implementation is GPL-3, which IIUC carries a "same license for the library" requirement. We'd need to request permission to relicense as BSD-3 if the plan is to simply translate the MATLAB implementation into Python.
A bonus provided by @rkobler's paper is a nice set of validation datasets we can use to test our implementation: https://osf.io/2qgrd
reference implementation is GPL-3
I'll keep that in mind if we do end up implementing SGEYESUB.
A bit OT, but I find it a bit sad that both the paper by Kobler et al. (2020) as well as the cited Schlögl et al. (2007) completely ignore relevant prior literature. The regression approach dates back to Hillyard and Galambos (1970), and a useful implementation (using the same data and separate coefficients for blinks and movements) was presented by Gratton, Coles and Donchin (1983). The latter is the "reference" implementation which I think we should provide before anything else (maybe even in simplified form with just one set of coefficients for both blinks and movements).
among the variants is their one you would consider the go to method for this task? I would like to avoid implement/maintain/test many small variants that lead to comparable results.
Message ID: @.***>
I'd prefer the one from Gratton et al. (1984), this is the most used one IMO. All of them are pretty similar anyway and also comparable in terms of performance. So it's basically about how to estimate the regression coefficients. I think the code that's already available in the sandbox is a good starting point.
If I look at the spectrum of variants, it occurs to me that most of them have to do with deciding on what type of data to fit the regression weights. If we go for a .fit()
/.apply()
style API, it would leave the user a lot of flexibility on which methodology to use. What I don't like about that approach though is that it makes it less straightforward to "just apply the method". Perhaps being opinionated on an approach is more desirable. :thinking:
I'd prefer the one from Gratton et al. (1984)
This one? https://www.sciencedirect.com/science/article/abs/pii/0013469483901359?via%3Dihub
Perhaps being opinionated on an approach is more desirable. 🤔
+1
Message ID: @.***>
Yes, this one! And yes, the differences between the various regression methods is which data to fit the coefficients on, so a fit/apply API would be perfect! To make it easier to apply, we could then provide a wrapper function for e.g. the Gratton et al. approach.
https://mne.tools/stable/generated/mne.preprocessing.regress_artifact.html 😅