说明
转到末尾下载完整示例代码。
处理事件#
本教程介绍事件的表示方式,以及如何使用 Events 数组来筛选数据。
与往常一样,我们先导入所需的模块、加载一些示例数据,并在将 Raw 对象载入 RAM 之前先将其裁剪到仅 60 秒,以节省内存:
# 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_raw.fif"
)
raw = mne.io.read_raw_fif(sample_data_raw_file, verbose=False)
raw.crop(tmax=60).load_data()
Reading 0 ... 36037 = 0.000 ... 60.000 secs...
教程“从原始数据中解析事件”详细介绍了从 Raw 对象获取 Events 数组的各种方法(详见“检测实验事件”一节)。由于示例数据集包含记录在 stim 通道 STI 014 上的实验事件,我们将通过 mne.find_events() 从该通道解析事件,以此开始本教程:
events = mne.find_events(raw, stim_channel="STI 014")
Finding events on: STI 014
86 events found on stim channel STI 014
Event IDs: [ 1 2 3 4 5 32]
从文件读写事件#
事件数组是 NumPy array 对象,因此可以用 numpy.save() 将其以二进制 .npy 文件的形式保存到磁盘。不过,MNE-Python 提供了便捷函数 mne.read_events() 和 mne.write_events(),可将事件数组读写为文本文件(常见扩展名为 .eve、.lst 和 .txt)或二进制 .fif 文件。示例数据集在某个 .fif 文件中包含了 mne.find_events(raw) 的结果。由于我们已对 Raw 对象做了截断,它包含的事件数会少于从磁盘加载的事件文件(后者包含整个记录的事件),但前 60 秒的事件应当是一致的:
sample_data_events_file = os.path.join(
sample_data_folder, "MEG", "sample", "sample_audvis_raw-eve.fif"
)
events_from_file = mne.read_events(sample_data_events_file)
assert np.array_equal(events, events_from_file[: len(events)])
将事件数组写入磁盘时,格式会根据你提供的文件扩展名推断。按照惯例,MNE-Python 要求事件文件的扩展名为 .eve,或者文件基名以 -eve 或 _eve 结尾(例如 my_experiment_eve.fif);如果不遵守这一惯例,将会发出警告。
筛选与合并事件#
上面 find_events() 的输出(此处再次显示)告诉了我们找到的事件数量,以及其中出现的唯一整数事件 ID:
mne.find_events(raw, stim_channel="STI 014")
Finding events on: STI 014
86 events found on stim channel STI 014
Event IDs: [ 1 2 3 4 5 32]
如果其中某些事件并不需要,可以使用 mne.pick_events() 轻松筛选事件,它有 include 和 exclude 参数。例如,在示例数据中 Event ID 32 对应被试按键,可以这样将其排除:
events_no_button = mne.pick_events(events, exclude=32)
也可以使用 mne.merge_events() 合并两个 Event ID;下面的示例将 Event ID 1、2 和 3 合并为一个标记为 1 的事件:
merged_events = mne.merge_events(events, [1, 2, 3], 1)
print(np.unique(merged_events[:, -1]))
[ 1 4 5 32]
但请注意,如果你只是想在分析时合并试次类型,则无需合并事件;下一节将介绍 MNE-Python 如何使用事件字典将整数 Event ID 映射为更具描述性的标签字符串。
将 Event ID 映射到试次描述符#
到目前为止,本教程只涉及整数 Event ID,它们是根据直流电压脉冲幅度分配的(最终取决于实验者选择向 STIM 通道发送何种信号)。跟踪哪个 Event ID 对应哪个实验条件可能十分繁琐,而在分析过程中通常希望合并实验条件。你可能还记得,入门教程中的这个表格给出了示例数据集中整数 Event ID 到有意义描述的映射。这里我们只是将该映射重现为一个事件字典:
event_dict = {
"auditory/left": 1,
"auditory/right": 2,
"visual/left": 3,
"visual/right": 4,
"smiley": 5,
"buttonpress": 32,
}
像这样的事件字典会在从连续数据中提取 epochs 时使用,得到的 Epochs 对象允许通过请求部分试次描述符来合并试次。例如,如果我们想合并所有听觉试次,不必使用 merge_events() 函数合并 Event ID 1 和 2,而可以利用 event_dict 的键包含以 / 字符分隔的多个试次描述符这一特点:请求 'auditory' 试次将选中所有 Event ID 为 1 和 2 的 epochs;请求 'left' 试次将选中所有 Event ID 为 1 和 3 的 epochs。教程“Epochs 数据结构:不连续数据”的“筛选 epochs”一节稍后给出了这方面的示例。
绘制事件#
事件字典的另一个用途是在绘制事件时使用,这有助于检查事件信号是否已正确发送到 STIM 通道,以及 MNE-Python 是否成功找到了它们。函数 mne.viz.plot_events() 会绘制每个事件与其采样点编号的关系(如果提供采样频率,则绘制它们与时间(秒)的关系)。它还可以通过 first_samp 参数处理 Neuromag 系统中采样点编号与采样索引之间的偏移。如果提供了事件字典,将用它生成图例:
fig = mne.viz.plot_events(
events, sfreq=raw.info["sfreq"], first_samp=raw.first_samp, event_id=event_dict
)

同时绘制事件与原始数据#
也可以将 Events 数组作为 raw.plot 的 events 参数传入,从而将事件与提取它们的 Raw 对象一起绘制:

生成等间隔 Events 数组#
对于某些实验(例如打算分析静息态活动的实验),原始记录中可能不包含任何实验事件。在这种情况下,可以使用 mne.make_fixed_length_events() 生成由等间隔事件组成的 Events 数组:
new_events = mne.make_fixed_length_events(raw, start=5, stop=50, duration=2.0)
默认情况下,所有事件都会被赋予整数 Event ID 1,但你可以通过 id 参数更改。也可以指定重叠时长——也就是说,如果你最终想要 2.5 秒长的 epochs,但希望它们彼此重叠 0.5 秒,可以在调用 make_fixed_length_events() 时指定 duration=2.5, overlap=0.5(这样得到的事件间隔与 duration=2, overlap=0 相同)。