非官方中文翻译 本页译自 MNE-Python 官方文档: 查看英文原文 ↗。 文档版权归 MNE Developers 所有(BSD-3-Clause)。

剔除坏数据段与中断#

本教程涵盖:

  • 手动标记坏数据段;

  • 基于信号振幅自动剔除数据段;以及

  • 自动检测实验过程中的中断。

与往常一样,我们首先导入所需的 Python 模块并加载一些示例数据;为节省内存,我们将使用经过预滤波和降采样的示例数据版本,同时加载一个 events 数组,以便在将连续数据转换为 Epochs 时使用:

# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.
import os

import numpy as np

import mne

sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = os.path.join(
    sample_data_folder, "MEG", "sample", "sample_audvis_filt-0-40_raw.fif"
)
raw = mne.io.read_raw_fif(sample_data_raw_file, verbose=False)
events_file = os.path.join(
    sample_data_folder, "MEG", "sample", "sample_audvis_filt-0-40_raw-eve.fif"
)
events = mne.read_events(events_file)

标注坏数据段#

教程《从原始数据中解析事件》介绍了如何从原始记录文件内嵌的事件中读取 Annotations,而《标注连续数据》则详细说明了如何以交互方式标注 Raw 数据对象。这里我们重点关注标注坏数据段的最佳实践,以便将它们排除在分析流程之外。

reject_by_annotation 参数#

在交互式 raw.plot() 窗口中,按 a 键可以打开标注控件。在这里,可以创建新的标注标签,或选择已有的标注标签来使用。

fig = raw.plot()
fig.fake_keypress("a")  # Simulates user pressing 'a' on the keyboard.
Raw plot

可以看到,必须先添加描述才能开始标记数据段(点击“Add Description”按钮并输入描述)。你可以使用任意描述,但那些标记应被排除在分析流程之外的数据段的标注,都应以“BAD”或“bad”开头(例如“bad_cough”、“bad-eyes-closed”、“bad door slamming”等)。遵循这一惯例后,MNE-Python 的许多处理步骤会自动排除带有“bad”标签的数据段;该行为由参数 reject_by_annotation 控制,它出现在许多 MNE-Python 函数或类构造函数中,包括:

例如,从连续数据创建 Epochs 时,如果 reject_by_annotation=True,Epochs 构造函数会丢弃任何与以“bad”开头的标注数据段部分或完全重叠的 epoch。

以编程方式生成标注#

《伪迹检测概览》教程介绍了伪迹检测函数 find_eog_events() 和 find_ecg_events()(不过该教程主要依赖它们更高层的封装 create_eog_epochs() 和 create_ecg_epochs())。这里,为演示起见,我们使用较低层的伪迹检测函数获得一个 events 数组,告诉我们眨眼发生的位置,然后在它们周围自动添加“bad_blink”标注(使用 create_eog_epochs() 时无需这样做,此处只是为了展示如何以非交互方式添加标注)。我们将标注的起点设在眨眼前 250 ms,终点设在眨眼后 250 ms:

Using EOG channel: EOG 061
EOG channel index for this subject is: [375]
Filtering the data to remove DC offset to help distinguish blinks from saccades
Selecting channel EOG 061 for blink detection
Setting up band-pass filter from 1 - 10 Hz

FIR filter parameters
---------------------
Designing a two-pass forward and reverse, zero-phase, non-causal bandpass filter:
- Windowed frequency-domain design (firwin2) method
- Hann window
- Lower passband edge: 1.00
- Lower transition bandwidth: 0.50 Hz (-12 dB cutoff frequency: 0.75 Hz)
- Upper passband edge: 10.00 Hz
- Upper transition bandwidth: 0.50 Hz (-12 dB cutoff frequency: 10.25 Hz)
- Filter length: 1502 samples (10.003 s)

Now detecting blinks and generating corresponding events
Found 46 significant peaks
Number of EOG events detected: 46
General
Filename(s) sample_audvis_filt-0-40_raw.fif
MNE object type Raw
Measurement date 2002-12-03 at 19:01:10 UTC
Participant Unknown
Experimenter Unknown
Acquisition
Duration 00:04:38 (HH:MM:SS)
Sampling frequency 150.15 Hz
Time points 41,700
Channels
Magnetometers
Gradiometers and
EEG and
EOG
Stimulus
Head & sensor digitization 146 points
Filters
Highpass 0.10 Hz
Lowpass 40.00 Hz
Projections PCA-v1 (off)
PCA-v2 (off)
PCA-v3 (off)
Average EEG reference (off)


现在可以确认这些标注以 EOG 事件为中心。由于眨眼通常在 EEG 通道中最容易观察到,这里我们只绘制 EEG:

Raw plot

有关以编程方式创建标注的更多细节,请参阅“以编程方式生成标注”一节。

检测并标注中断#

另一个有用的函数是 mne.preprocessing.annotate_break,尽管它本身并不直接涉及伪迹检测:它会在数据中不存在现有标注(或者,在基于事件的模式下不存在事件)的片段生成标注。因此,它可用于自动检测并标记中断,例如在记录持续进行时,实验区块之间的中断。

为便于本示例,假设实验由两个区块组成,第一个区块从 30 秒持续到 90 秒,第二个从 120 秒到 180 秒。我们将用标注标记这些区块,然后使用 mne.preprocessing.annotate_break 检测并标注所有中断。

注意

我们需要考虑 raw.first_time,否则起始时间会不正确!

onsets = [raw.first_time + 30, raw.first_time + 180]
durations = [60, 60]
descriptions = ["block_1", "block_2"]

block_annots = mne.Annotations(
    onset=onsets,
    duration=durations,
    description=descriptions,
    orig_time=raw.info["meas_date"],
)
raw.set_annotations(raw.annotations + block_annots)  # add to existing
raw.plot()
Raw plot

现在检测中断时段。我们可以控制中断标注向每个中断两端扩展的距离。

break_annots = mne.preprocessing.annotate_break(
    raw=raw,
    min_break_duration=20,  # consider segments of at least 20 s duration
    t_start_after_previous=5,  # start annotation 5 s after end of previous one
    t_stop_before_next=2,  # stop annotation 2 s before beginning of next one
)

raw.set_annotations(raw.annotations + break_annots)  # add to existing
raw.plot()
Raw plot
Ignoring annotations with descriptions starting with: bad, edge

Detected 3 break periods of >= 20 s duration:
    0.0 – 28.0 s [28.0 s]
    95.0 – 178.0 s [83.0 s]
    245.0 – 277.7 s [32.7 s]
In total, 51.7% of the data (143.7 s) have been marked as a break.

可以看到,有 3 个片段被标注为 BAD_break:

  • 第一个从记录开始处起,到区块 1 开始前 2 秒结束(因为 t_stop_before_next=2);

  • 第二个从区块 1 结束后 5 秒开始,到区块 2 开始前 2 秒结束(t_start_after_previous=5、t_stop_before_next=2);

  • 最后一个从区块 2 结束后 5 秒开始(t_start_after_previous=5),一直持续到记录结束。

还可以看到,在检测中断时段时只考虑了 block_1 和 block_2 标注——EOG 标注被直接忽略了。这是因为默认情况下,annotate_break 会忽略所有以 'bad' 开头的标注。你可以通过 ignore 参数控制此行为。

也可以基于 events 数组执行中断时段检测:只需通过 events 参数传入该数组。此时,原始数据中已有的标注将被忽略:

# only keep some button press events (code 32) for this demonstration
events_subset = events[events[:, -1] == 32]
# drop the first and last few events
events_subset = events_subset[3:-3]

break_annots = mne.preprocessing.annotate_break(
    raw=raw,
    events=events_subset,  # passing events will ignore existing annotations
    min_break_duration=25,  # pick a longer break duration this time
)

# replace existing annotations (otherwise it becomes difficult to see any
# effects in the plot!)
raw.set_annotations(break_annots)
raw.plot(events=events_subset)
Raw plot
Detected 2 break periods of >= 25 s duration:
    0.0 – 51.4 s [51.4 s]
    185.6 – 277.7 s [92.1 s]
In total, 51.7% of the data (143.5 s) have been marked as a break.

基于通道峰峰值振幅剔除 Epochs#

除了“bad”标注之外,mne.Epochs 类构造函数还有一种剔除 Epoch 的方法,即基于每种通道类型的信号振幅阈值。在概览教程中我们见过这样一个例子:使用 reject 参数为每个 Epoch 中的每种通道类型设置可接受的最大峰峰值振幅。还有一个相关参数 flat,可用于设置每个 Epoch 中每种通道类型可接受的最小峰峰值振幅:

reject_criteria = dict(
    mag=3000e-15,  # 3000 fT
    grad=3000e-13,  # 3000 fT/cm
    eeg=100e-6,  # 100 µV
    eog=200e-6,
)  # 200 µV

flat_criteria = dict(mag=1e-15, grad=1e-13, eeg=1e-6)  # 1 fT  # 1 fT/cm  # 1 µV

合适的取值取决于数据集和硬件,因此可能需要反复尝试,才能在数据质量与丢弃过多 Epoch 导致的统计功效损失之间找到正确平衡。这里,为便于说明,我们将剔除标准设置得相当严格。

另外两个参数 reject_tmin 和 reject_tmax 用于设置计算峰峰值振幅以进行 Epoch 剔除的时间窗。它们默认与整个 Epoch 的 tmin 和 tmax 相同。举例来说,如果你只想对 Epoch 中事件标记之前的部分应用剔除阈值(事件标记是 Epoch 切分的中心),可以设置 reject_tmax=0。可以使用 plot_drop_log() 方法生成 Epoch 被剔除原因的汇总:

raw.set_annotations(blink_annot)  # restore the EOG annotations
epochs = mne.Epochs(
    raw,
    events,
    tmin=-0.2,
    tmax=0.5,
    reject_tmax=0,
    reject=reject_criteria,
    flat=flat_criteria,
    reject_by_annotation=False,
    preload=True,
)
epochs.plot_drop_log()
8 of 319 epochs removed (2.5%)
Not setting metadata
319 matching events found
Setting baseline interval to [-0.19979521315838786, 0.0] s
Applying baseline correction (mode: mean)
Created an SSP operator (subspace dimension = 4)
4 projection items activated
Loading data for 319 events and 106 original time points ...
    Rejecting  epoch based on EEG : ['EEG 001', 'EEG 002', 'EEG 003', 'EEG 007']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EEG : ['EEG 001', 'EEG 003', 'EEG 007']
    Rejecting  epoch based on MAG : ['MEG 1711']
    Rejecting  epoch based on EEG : ['EEG 007']
    Rejecting  epoch based on EEG : ['EEG 003']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on EEG : ['EEG 001', 'EEG 002', 'EEG 003']
8 bad epochs dropped

注意,上面我们传入了 reject_by_annotation=False,以便单独观察剔除阈值的效果。如果以 reject_by_annotation=True(默认值)重新运行分段,会发现因 EEG 和 EOG 通道导致的剔除消失了(这表明这些通道的波动可能与眨眼有关,并且已被基于“bad blink”标签的剔除所涵盖)。

epochs = mne.Epochs(
    raw,
    events,
    tmin=-0.2,
    tmax=0.5,
    reject_tmax=0,
    reject=reject_criteria,
    flat=flat_criteria,
    preload=True,
)
epochs.plot_drop_log()
39 of 319 epochs removed (12.2%)
Not setting metadata
319 matching events found
Setting baseline interval to [-0.19979521315838786, 0.0] s
Applying baseline correction (mode: mean)
Created an SSP operator (subspace dimension = 4)
4 projection items activated
Loading data for 319 events and 106 original time points ...
    Rejecting  epoch based on MAG : ['MEG 1711']
39 bad epochs dropped

更重要的是,请注意基于眨眼标签剔除时会丢弃多得多的 Epoch(约 12.2%,而不是约 2.5%),这凸显了为什么通常更希望修复伪迹,而不是将其排除。

plot_drop_log() 方法是对 Epochs 属性 epochs.drop_log 的可视化,该属性为保留下来的 Epoch 存储空列表,为被丢弃的 Epoch 存储字符串列表,字符串指明 Epoch 被丢弃的原因。例如:

(('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), ('bad blink',), (), ('bad blink',), ('bad blink',), (), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('MEG 1711',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), ('bad blink',), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), ('bad blink',), ('bad blink',), (), (), (), ('bad blink',), ('bad blink',), (), (), (), (), ('bad blink',), (), (), (), ('bad blink',), (), (), ('bad blink',), ('bad blink',), (), (), ('bad blink',), (), (), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), (), (), (), (), (), ('bad blink',), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), ('bad blink',), ('bad blink',), (), (), ('bad blink',), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ('bad blink',), (), (), (), ())

最后需要注意,“被丢弃”的 Epoch 不一定会立即从 Epochs 对象中删除。上文我们通过 preload=True 参数,在创建 Epochs 对象时就强制完成了丢弃。如果没有这样做,Epochs 对象会以内存映射方式存在(未加载到 RAM),此时只存储丢弃 Epoch 的标准,实际的丢弃会在 Epochs 数据最终被加载和使用时发生。有几种方式可以触发这一过程,例如:

也可以使用 drop_bad() 方法触发丢弃;如果已经向 Epochs 构造函数提供了 reject 和/或 flat 标准,则可以不带参数调用 drop_bad(),直接删除已标记为待移除的 Epoch(如果这些 Epoch 已被丢弃,则不会再发生任何操作):

General
MNE object type Epochs
Measurement date 2002-12-03 at 19:01:10 UTC
Participant Unknown
Experimenter Unknown
Acquisition
Total number of events 280
Events counts 1: 62
2: 64
3: 69
32: 15
4: 55
5: 15
Time range -0.200 – 0.499 s
Baseline -0.200 – 0.000 s
Sampling frequency 150.15 Hz
Time points 106
Metadata No metadata set
Channels
Magnetometers
Gradiometers and
EEG and
EOG
Stimulus
Head & sensor digitization 146 points
Filters
Highpass 0.10 Hz
Lowpass 40.00 Hz
Projections PCA-v1 (on)
PCA-v2 (on)
PCA-v3 (on)
Average EEG reference (on)


或者,如果最初没有向 Epochs 构造函数提供剔除阈值,也可以稍后将其传给 drop_bad();这也可以作为一种逐步施加更严格剔除标准的方式:

stronger_reject_criteria = dict(
    mag=2000e-15,  # 2000 fT
    grad=2000e-13,  # 2000 fT/cm
    eeg=100e-6,  # 100 µV
    eog=100e-6,
)  # 100 µV

epochs.drop_bad(reject=stronger_reject_criteria)
print(epochs.drop_log)
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1441', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 1421', 'MEG 1431', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1541']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1441', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1221', 'MEG 1321', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1441', 'MEG 1541', 'MEG 1741', 'MEG 2141', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 1741', 'MEG 2141', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421']
    Rejecting  epoch based on MAG : ['MEG 1421', 'MEG 1431']
    Rejecting  epoch based on MAG : ['MEG 1431']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 2621']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 0811', 'MEG 0911', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431']
    Rejecting  epoch based on EOG : ['EOG 061']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1321', 'MEG 1331', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 0521', 'MEG 0811', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 1421']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2131', 'MEG 2531', 'MEG 2541', 'MEG 2611', 'MEG 2621', 'MEG 2631']
    Rejecting  epoch based on MAG : ['MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 2421']
    Rejecting  epoch based on MAG : ['MEG 1321', 'MEG 1331']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1541']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621']
    Rejecting  epoch based on MAG : ['MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 2621']
65 bad epochs dropped
(('bad blink',), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1441', 'MEG 1541', 'MEG 2621'), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), ('bad blink',), ('bad blink',), (), (), (), (), ('MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), (), ('bad blink',), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), ('bad blink',), (), ('MEG 1421', 'MEG 1431', 'MEG 2621'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), (), (), (), ('bad blink',), (), (), ('EOG 061',), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), ('bad blink',), ('bad blink',), (), ('bad blink',), ('bad blink',), (), (), ('bad blink',), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431'), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1541'), ('EOG 061',), ('bad blink',), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1441', 'MEG 1541', 'MEG 2621', 'EOG 061'), (), (), (), ('EOG 061',), ('MEG 0111', 'MEG 0141', 'MEG 1221', 'MEG 1321', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1441', 'MEG 1541', 'MEG 1741', 'MEG 2141', 'MEG 2621'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 1741', 'MEG 2141', 'MEG 2621'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), ('EOG 061',), (), ('MEG 1711',), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1541'), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431'), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541'), ('bad blink',), (), ('bad blink',), ('bad blink',), (), ('MEG 0111', 'MEG 0141', 'MEG 1421'), (), (), (), (), ('MEG 1421', 'MEG 1431'), (), ('MEG 1431',), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431'), (), ('bad blink',), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), (), (), (), (), (), ('EOG 061',), (), ('bad blink',), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 2621'), ('EOG 061',), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), ('bad blink',), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 2621'), ('bad blink',), ('bad blink',), ('MEG 0111', 'MEG 0141', 'MEG 0811', 'MEG 0911', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), ('bad blink',), ('bad blink',), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431'), ('bad blink',), ('EOG 061',), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), ('bad blink',), (), (), ('bad blink',), ('bad blink',), (), (), ('bad blink',), (), (), (), ('bad blink',), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1541'), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1321', 'MEG 1331', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 0521', 'MEG 0811', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), ('bad blink',), ('MEG 1421',), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), (), ('MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 2621'), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 2621'), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2131', 'MEG 2531', 'MEG 2541', 'MEG 2611', 'MEG 2621', 'MEG 2631'), (), (), (), (), ('bad blink',), (), (), (), (), ('MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 2621'), ('MEG 2421',), (), ('bad blink',), ('bad blink',), ('MEG 1321', 'MEG 1331'), (), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541'), ('bad blink',), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1541'), ('bad blink',), ('bad blink',), (), (), ('bad blink',), (), ('bad blink',), (), (), (), (), (), (), (), (), (), (), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), (), (), (), (), ('MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 2621'), (), (), ('MEG 0111', 'MEG 0141', 'MEG 1421', 'MEG 1431', 'MEG 1541', 'MEG 2621'), (), (), (), (), ('bad blink',), (), (), ('MEG 0141', 'MEG 1411', 'MEG 1421', 'MEG 1431', 'MEG 2621'), ())

使用可调用对象(函数)剔除 Epochs#

有时,基于峰峰值振幅以外的标准剔除 Epoch 会很有用。例如,我们可能希望根据通道的最大或最小振幅剔除 Epoch。在这种情况下,mne.Epochs.drop_bad 函数还在 reject 和 flat 参数中接受可调用对象(函数)。这使我们能够定义函数,根据所需的标准剔除 Epoch。

我们首先在一个 EEG 通道中生成带有大幅伪迹的 Epoch 数据,以展示这种方法的灵活性。

raw.crop(0, 5)
raw.del_proj()
chans = raw.info["ch_names"][-5:-1]
raw.pick(chans)
data = raw.get_data()

new_data = data
new_data[0, 180:200] *= 1e3
new_data[0, 460:580] += 1e-3
edit_raw = mne.io.RawArray(new_data, raw.info)

# Create fixed length epochs of 1 second
events = mne.make_fixed_length_events(edit_raw, id=1, duration=1.0, start=0)
epochs = mne.Epochs(edit_raw, events, tmin=0, tmax=1, baseline=None)
epochs.plot(scalings=dict(eeg=50e-5))
Raw plot
Creating RawArray with float64 data, n_channels=4, n_times=752
    Range : 0 ... 751 =      0.000 ...     5.002 secs
Ready.
Not setting metadata
5 matching events found
No baseline correction applied
0 projection items activated
Using data from preloaded Raw for 5 events and 151 original time points ...
0 bad epochs dropped
Using data from preloaded Raw for 5 events and 151 original time points ...
Using data from preloaded Raw for 5 events and 151 original time points ...
Using data from preloaded Raw for 5 events and 151 original time points ...

可以看到,第一个通道中有两个大幅伪迹:一个振幅尖峰,以及一段振幅大幅升高的片段。

# Let's try to reject the epoch containing the spike in amplitude based on the
# maximum amplitude of the first channel. Please note that the callable in
# ``reject`` must return a (good, reason) tuple. Where the good must be bool
# and reason must be a str, list, or tuple where each entry is a str.

epochs = mne.Epochs(
    edit_raw,
    events,
    tmin=0,
    tmax=1,
    baseline=None,
    preload=True,
)

epochs.drop_bad(
    reject=dict(eeg=lambda x: ((np.max(x, axis=1) > 1e-2).any(), "max amp"))
)
epochs.plot(scalings=dict(eeg=50e-5))
Raw plot
Not setting metadata
5 matching events found
No baseline correction applied
0 projection items activated
Using data from preloaded Raw for 5 events and 151 original time points ...
0 bad epochs dropped
1 bad epochs dropped

这里,包含振幅尖峰的 Epoch 因最大振幅大于 1e-2 伏特而被剔除。请注意使用了 any() 函数来检查是否有任一通道超过阈值。我们也可以使用 all() 函数来检查是否所有通道都超过阈值。

# Next, let's try to reject the epoch containing the increase in amplitude
# using the median.

epochs = mne.Epochs(
    edit_raw,
    events,
    tmin=0,
    tmax=1,
    baseline=None,
    preload=True,
)

epochs.drop_bad(
    reject=dict(eeg=lambda x: ((np.median(x, axis=1) > 1e-4).any(), "median amp"))
)
epochs.plot(scalings=dict(eeg=50e-5))
Raw plot
Not setting metadata
5 matching events found
No baseline correction applied
0 projection items activated
Using data from preloaded Raw for 5 events and 151 original time points ...
0 bad epochs dropped
1 bad epochs dropped

最后,我们尝试结合最大值和中位数来剔除这两个 Epoch。我们将定义一个自定义函数,并使用布尔运算符组合这两个标准。

def reject_criteria(x):
    max_condition = np.max(x, axis=1) > 1e-2
    median_condition = np.median(x, axis=1) > 1e-4
    return ((max_condition.any() or median_condition.any()), ["max amp", "median amp"])


epochs = mne.Epochs(
    edit_raw,
    events,
    tmin=0,
    tmax=1,
    baseline=None,
    preload=True,
)

epochs.drop_bad(reject=dict(eeg=reject_criteria))
epochs.plot(events=True)
Raw plot
Not setting metadata
5 matching events found
No baseline correction applied
0 projection items activated
Using data from preloaded Raw for 5 events and 151 original time points ...
0 bad epochs dropped
2 bad epochs dropped

此外,补充性的 Python 包 autoreject 使用机器学习来寻找最佳剔除标准,并设计为可与 MNE-Python 工作流顺畅集成。在处理异质性数据集时,这可以节省大量时间。

脚本总运行时间:(0 分钟 2.354 秒)

图库由 Sphinx-Gallery 生成