说明
转到末尾下载完整示例代码。
使用可变时间窗自动生成 Epochs 元数据#
使用 Epochs 时,元数据非常有价值。有详细教程介绍如何自动生成元数据。下面的简短示例演示限定元数据时间窗的不同方式。
# Authors: Richard Höchenberger <richard.hoechenberger@gmail.com>
#
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.
我们使用 Eriksen flanker 任务期间的 EEG 记录,为演示起见只加载前 60 秒数据。
import mne
data_dir = mne.datasets.erp_core.data_path()
infile = data_dir / "ERP-CORE_Subject-001_Task-Flankers_eeg.fif"
raw = mne.io.read_raw(infile, preload=True)
raw.crop(tmax=60).filter(l_freq=0.1, h_freq=40)
Opening raw data file /home/circleci/mne_data/MNE-ERP-CORE-data/ERP-CORE_Subject-001_Task-Flankers_eeg.fif...
Range : 0 ... 935935 = 0.000 ... 913.999 secs
Ready.
Reading 0 ... 935935 = 0.000 ... 913.999 secs...
Filtering raw data in 1 contiguous segment
Setting up band-pass filter from 0.1 - 40 Hz
FIR filter parameters
---------------------
Designing a one-pass, zero-phase, non-causal bandpass filter:
- Windowed time-domain design (firwin) method
- Hamming window with 0.0194 passband ripple and 53 dB stopband attenuation
- Lower passband edge: 0.10
- Lower transition bandwidth: 0.10 Hz (-6 dB cutoff frequency: 0.05 Hz)
- Upper passband edge: 40.00 Hz
- Upper transition bandwidth: 10.00 Hz (-6 dB cutoff frequency: 45.00 Hz)
- Filter length: 33793 samples (33.001 s)
可视化事件#
所有实验事件都以 Annotations 形式保存在 Raw 实例中。首先需要把它们转换为事件,以及事件码到事件名称的映射(event_id),然后可视化事件。
all_events, all_event_id = mne.events_from_annotations(raw)
mne.viz.plot_events(events=all_events, event_id=all_event_id, sfreq=raw.info["sfreq"])

Used Annotations descriptions: ['response/left', 'response/right', 'stimulus/compatible/target_left', 'stimulus/compatible/target_right', 'stimulus/incompatible/target_left', 'stimulus/incompatible/target_right']
可以看到,共有四类刺激事件与两类反应事件。
声明“行事件”#
本示例假设分析时以刺激起始事件对齐分段,因此希望为每个刺激生成一行元数据。把所有刺激事件名称指定为 row_events 即可实现。
row_events = [
"stimulus/compatible/target_left",
"stimulus/compatible/target_right",
"stimulus/incompatible/target_left",
"stimulus/incompatible/target_right",
]
指定元数据时间窗#
下面探索在生成元数据时限定 row_events 周围时间窗的不同方式。落入同一时间窗的所有事件会加入元数据表的同一行。
固定时间窗#
指定时间窗范围的一种简单方式是给出相对于行事件的秒数。下例中时间窗从行事件(时间点 0)延伸到其后 3 秒。
metadata_tmin = 0.0
metadata_tmax = 3.0
metadata, events, event_id = mne.epochs.make_metadata(
events=all_events,
event_id=all_event_id,
tmin=metadata_tmin,
tmax=metadata_tmax,
sfreq=raw.info["sfreq"],
row_events=row_events,
)
metadata
乍看没问题。但在第 2、3 行中列出了两个反应(左与右),因为 3 秒时间窗显然过宽,捕获了不止一个试次。可以把它收窄,但若窗口太窄又可能丢失事件。归根结底,问题在于反应时逐试次变化,很难设定固定的时间窗上界。
使用 keep_first 的固定时间窗#
一种变通方法是使用 keep_first 参数,它会新建一列,包含指定类型的第一个事件。
metadata_tmin = 0.0
metadata_tmax = 3.0
keep_first = "response" # <-- new
metadata, events, event_id = mne.epochs.make_metadata(
events=all_events,
event_id=all_event_id,
tmin=metadata_tmin,
tmax=metadata_tmax,
sfreq=raw.info["sfreq"],
row_events=row_events,
keep_first=keep_first, # <-- new
)
metadata
可以看到新建了 response 列,记录落入时间窗的第一个反应事件的时间;first_response 列则指明哪个反应先发生(左或右)。
可变时间窗#
另一种应对可变时间窗、且无需新建列的方法,是把 tmin 与 tmax 指定为事件名称。本例中 tmin=row_events,因为希望时间窗从锁时事件开始;tmax 则是反应事件:tmin 之后的第一个反应事件将决定时间窗长度。
metadata_tmin = row_events
metadata_tmax = ["response/left", "response/right"]
metadata, events, event_id = mne.epochs.make_metadata(
events=all_events,
event_id=all_event_id,
tmin=metadata_tmin,
tmax=metadata_tmax,
sfreq=raw.info["sfreq"],
row_events=row_events,
)
metadata
可变时间窗(简化写法)#
上面的代码可以略微简化:既然 tmin 应设为 row_events,可以传入 tmin=None,这是表达 tmin=row_events 更简便的方式。得到的元数据与上例相同。
metadata_tmin = None # <-- new
metadata_tmax = ["response/left", "response/right"]
metadata, events, event_id = mne.epochs.make_metadata(
events=all_events,
event_id=all_event_id,
tmin=metadata_tmin,
tmax=metadata_tmax,
sfreq=raw.info["sfreq"],
row_events=row_events,
)
metadata
脚本总运行时间:(0 分 1.627 秒)