If you have a question or issue with MNE-Python, please include the following info:
MNE version: 1.13.2
PyPrep version: 0.9.0
operating system: Windows 10
Hello everyone,
I am working with a public EEG dataset recorded using a 64-channel system and stored in BrainVision format. Pz was used as the reference during recording, but Pz itself is not included in the saved channels.
Following the MNE tutorial on setting the EEG reference, I added Pz back using:
raw = mne.add_reference_channels(raw, ref_channels=["Pz"])
At this point, the added Pz channel contains only zeros.
I plan to preprocess the data using PyPREP’s full PrepPipeline, with both ref_chs and reref_chs set to "eeg".
My understanding is that, if I pass the data to PyPREP immediately after adding Pz, the zero-filled Pz channel may be detected as a flat/bad channel before robust referencing is performed. Is this understanding correct?
To address this, I am considering applying common average reference first, including the added Pz channel:
I would then run PyPREP with ref_chs="eeg" and reref_chs="eeg", allowing it to perform its own robust average referencing.
My questions are:
Is adding the original Pz reference as a zero-filled channel and then re-referencing the data an appropriate way to obtain a Pz signal relative to the new reference?
Is it appropriate to apply ordinary common average reference before PyPREP in this situation, and then perform robust average referencing within PyPREP? Could the initial average referencing adversely affect PyPREP’s bad-channel detection or robust reference estimation?
Is there a recommended alternative for handling the original reference channel when using PyPREP?
I would like to retain Pz for subsequent analyses, while avoiding having it treated as a genuinely flat or malfunctioning electrode simply because it was the original recording reference.
I would separate restoring the original reference channel from how PyPREP classifies that channel.
If the stored EEG is still referenced to Pz, adding Pz as a zero-filled channel before changing the reference is appropriate; this is the procedure described in the MNE reference tutorial. After subtracting a new reference signal r(t), the added channel becomes -r(t): Pz expressed relative to the new reference, not a spatially interpolated channel.
Applying ordinary average reference first would generally make Pz nonzero, but that alone does not establish that it is the best workaround. Subtracting the mean also changes the signals used for bad-channel detection, and a noisy channel included in that mean contributes to every re-referenced channel. I would therefore check the resulting bad-channel and interpolation decisions, not just whether Pz stops being flat.
Could you share the public dataset link and a minimal example showing loading, montage assignment, and the PrepPipeline call, plus the bad-channel log if you have already run it? That would let us check this on the same input with a fixed random_state. I have checked the source, but have not reproduced the full pipeline on your recording.
I think an even better approach is to run PyPREP on the original data (64 channels without the Pz reference). If you later want to have Pz in your data, I would add it after running PyPREP, something like
pz = -prep.reference_after_interpolation
This channel can then be added with the add_channels() method (but you will have to convert it to a RawArray first I think). Finally, you can compute an average reference from this set of 65 channels.
I apologize for the delayed response, and thank you very much for suggesting this approach. It was very helpful.
I am planning to use PyPREP and ICALabel because I have a relatively large dataset (more than 200 participants), and I would like to establish a standardized and reproducible preprocessing pipeline that can be applied consistently across all participants.
I think using these two methods is a reasonable approach, but I was wondering if you might recommend a better strategy for a dataset of this size. In particular, I am a little concerned that there may occasionally be data quality issues or artifacts that are not detected by the automated algorithms.
Would you recommend any additional quality-control steps or a particular strategy for identifying artifacts that PyPREP or ICALabel might miss, while still keeping the preprocessing pipeline standardized across participants?
Thank you so much for your reply and for sharing your thoughts! For now, I’m going to try the approach Clemens suggested, where I reconstruct and add Pz after running PyPREP.
I’ll see how this works with my data first. If I run into any issues or have any problems with the channel handling, I’ll let you know!
I think PyPREP and ICALabel should catch most large artifacts, and smaller artifacts should normally not matter in such a large dataset (if one missed artifact changes the outcome, something’s wrong with the analysis anyway). If you really want to make sure you are not missing anything, I don’t think there’s an alternative to manually reviewing the data – at least that’s what I am still doing, and having automated artifact annotations as a starting point makes that process reasonably fast. If you want more automated tools, you could take a look at autoreject — autoreject 0.5.1 documentation, but I doubt it will add anything substantial if you’re already using PyPREP/ICALabel, so I wouldn’t really recommend it.
Thank you very much for the helpful advice! I agree that manual review is probably necessary to catch issues that automated methods might miss, and using automated annotations as a starting point sounds like a practical approach.
I have actually tried Autoreject before. If I remember correctly, I used it in a workflow involving ICA, although I would need to revisit my previous implementation to be sure.
I have one more question regarding bad-channel handling. In my current project, it is important to keep the channel configuration as consistent as possible across all participants, since the EEG data will eventually be used as input to a deep learning model.
If some channels are still marked as bad by PyPREP after its interpolation and robust referencing procedures, how would you recommend handling them? Would manual inspection of these channels be the best approach, or would it be reasonable to interpolate them again if necessary?
My concern is that repeatedly interpolating channels that remain bad could introduce unreliable or overly smoothed signals, whereas dropping different channels for different participants would result in inconsistent channel configurations.
Would you recommend a particular strategy for balancing data quality and channel consistency in this situation?
Thank you again for sharing your experience and advice!
I haven’t really used Autoreject, so I can’t make any good recommendations, but I think sticking to PyPREP should definitely be OK.
Regarding any remaining bad channels, if this really happens (it shouldn’t be the rule), then I would manually review the flagged channels and decide if interpolating would work (this would require the surrounding channels to be good). But this is hopefully the exception, otherwise I’d be concerned about the general data quality of the recordings in the first place.
For the deep learning model, if it requires consistent channels across data sets, I would define quality control and participant exclusion criteria a priori - if a data set doesn’t meet these criteria, I would then exclude it.
I’m not really a PyPREP expert though, so maybe @sappelhoff wants to weigh in?