Open larsoner opened 6 months ago
Quoting from @sappelhoff here:
I would also suggest comparing against pyprep's: pyprep.NoisyChannels(raw).find_all_bads() ... you can use pyprep.NoisyChannels.get_bads with as_dict=True to then get info on why channels were marked bad :-)
and @hoechenberger :
I have to say that find_all_Bads marks way too many channels as bad in my datasets. I usually only use a subset of the functions in pyprep (I can share which those are specifically in case you're interested)
I have never tried pyprep
-- @hoechenberger do you think it would make sense to add an option to MNE-BIDS-Pipeline to use pyprep
with a user-selected subset of "why"s (maybe suggesting users try your subset of functions as a starting point)?
This is from 3 years ago -- @hoechenberger is it still relevant?
I don't think so. We should leave it in the pipeline, even though I'd prefer users to run bad channel detection on the BIDS dataset before they run the pipeline. But there are situations where you might want to work with a dataset that was provided to you that doesn't have all problematic channels marked as bad, and then this feature comes in handy. WDYT?
Any objection to adding bad channel detection for EEG in the meantime
Not at all!
I have never tried
pyprep
-- @hoechenberger do you think it would make sense to add an option to MNE-BIDS-Pipeline to usepyprep
with a user-selected subset of "why"s (maybe suggesting users try your subset of functions as a starting point)?
Yes. Users may provide a tuple of processing steps to run. FWIW here's what I currently use before converting to BIDS; I don't use the full set of pyprep
features, but iterate 3 times (cc @sappelhoff); importantly, I mark break periods first so they'll get excluded from data quality assessment:
class BadChannels(TypedDict):
Subject: str
Run: int
Bads: str # "Ch1, Ch2, …"
def run_bads_detection(subject: str, subject_run_path: Path) -> BadChannels:
# run number is appended at the end of the input filename ater the 2nd underscore,
# or after a dash, or after one underscore
print(f"Processing file: {subject_run_path.name}")
if subject_run_path.stem.count("_") == 2:
run = int(subject_run_path.stem.split("_")[2])
elif "-" in subject_run_path.stem:
run = int(subject_run_path.stem.split("-")[1])
else:
run = int(subject_run_path.stem.split("_")[1])
# read input data
raw = mne.io.read_raw(subject_run_path, preload=True, verbose=False)
assert isinstance(raw, mne.io.BaseRaw)
raw.set_montage("easycap-M1")
annot_breaks = mne.preprocessing.annotate_break(
raw=raw,
min_break_duration=10,
t_start_after_previous=2,
t_stop_before_next=2,
ignore=(
"bad",
"edge",
"New Segment",
),
)
raw.set_annotations(raw.annotations + annot_breaks)
all_bads: list[str] = []
for _ in range(3):
nc = pyprep.NoisyChannels(raw=raw, random_state=42)
nc.find_bad_by_deviation()
nc.find_bad_by_correlation()
nc.find_bad_by_ransac()
bads = nc.get_bads()
all_bads.extend(bads)
all_bads = sorted(all_bads)
raw.info["bads"] = all_bads
print(all_bads)
return {"Subject": subject, "Run": run, "Bads": ", ".join(sorted(all_bads))}
In https://mne.tools/mne-bids-pipeline/stable/settings/preprocessing/autobads.html it says:
This is from 3 years ago -- @hoechenberger is it still relevant? Any objection to adding bad channel detection for EEG in the meantime (e.g., https://github.com/mne-tools/mne-python/issues/12384)?