Python-MNE全套教程(官网翻译)-入门03:从raw数据中解析events

本教程描述了如何从原始记录中读取event,以及如何在两种不同event的表示之间进行转换(Events arrays 和 Annotations objects,数组表述和注释表述)。在入门教程中,我们有了一个从“STIM”通道阅读实验事件的例子,而在这里,我们将更广泛地讨论event。

老样子,加载数据先:

import numpy as np

import mne

sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = sample_data_folder / "MEG" / "sample" / "sample_audvis_raw.fif"
raw = mne.io.read_raw_fif(sample_data_raw_file)
raw.crop(tmax=60).load_data()

Events array和Annotations objects的区别

Events和Annotations都有相同的目的,它们提供EEG/MEG记录期间的时间映射,并描述在这些时间发生的事情。换句话说,他们把“何时”和“什么”联系在一起。主要的区别是:

  1. 单位:Events表示以采样率为单位的时间,而Annotations表示以秒为单位的时间。
  2. 描述:Events的事件是一个ID,是一个整数,而Annotations的事件是一个字符串。
  3. 持续时间如何编码:Event数组中的事件没有持续时间(尽管可以用Events数组中的开始/结束事件对表示持续时间),而annotation对象的每个元素都必须包含持续时间(尽管如果需要瞬时事件,持续时间可以为0)。
  4. 类型:events存储为NumPy数组,而annotation是在MNE-Python中定义的类似liest的一个新类型。

什么是STIM通道

STIM就是刺激通道,是一个不接收来自EEG, MEG或其他传感器信号的通道。STIM通道记录电压信号,通常是由实验室控制计算机发送的固定大小的方波直流脉冲,这些电压被时间锁定在实验事件上,例如刺激的开始,或受试者按下按钮等,这些脉冲有时被称为TTL脉冲、event脉冲、trigger或marker,我比较喜欢叫trigger)。

直流脉冲可以全部在一个STIM通道上,在这种情况下,不同的实验事件或试验类型被编码为不同的电压方波的振幅。或者它们可以分布在几个通道上,在这种情况下,脉冲发生的通道可以用来编码不同的事件或条件。即使在具有多个STIM通道的系统上,通常也会有一个通道记录其他STIM通道的加权和,因此该通道上的电压水平可以明确地解码为特定的事件类型。在旧的神经成像系统上,一般这个通道叫做STI 014,新的系统上,一般叫做STIM101。我们可以直接在raw上pick出来这些通道:

raw.copy().pick(picks="stim").plot(start=3, duration=6)

在这里插入图片描述
可以看到,STI 014是包含STI 001等通道的方波信号的。

把一个STIM通道的信号转换成event array

使用find_events可以将STIM上的信号转换为event array。每个信号的起始/结束的样本数被记录为事件时间,振幅被转换为整数,存储在NumPy数组中。在其最简单的形式中,该函数只需要Raw对象,以及从中读取事件的通道名称:

events = mne.find_events(raw, stim_channel="STI 014")
print(events[:5])  # show the first 5

86 events found on stim channel STI 014
Event IDs: [ 1 2 3 4 5 32]
[[27977 0 2]
[28345 0 3]
[28771 0 1]
[29219 0 4]
[29652 0 2]]

MNE-Python事件实际上有三个值,第一个表示样本数,第三个表示事件代码,第二个表示前一个样本上的事件(一般都是0),它可以用于检测持续时间长于一个样本的事件的端点。

如果你没有提供STIM通道的名称,find_events将首先查找MNE_STIM_CHANNEL、MNE_STIM_CHANNEL_1等变量的MNE-Python配置变量。如果没有找到,则尝试通道STI 014和STI101,还没有找到,就选择raw.ch_names中类型为“STIM”的第一个通道。

如果我们经常使用来自具有不同STIM通道名称的几个不同MEG系统的数据,则设置MNE_STIM_CHANNEL 这个config变量可能不是很有用,但对于数据全部来自单个系统的研究人员来说,config该变量肯定可以节省时间。

find_events有几个选项,包括将事件与STIM通道信号的起始/偏移量进行对齐、设置最小信号持续时间和处理连续信号(其间不返回零)的选项。例如,可以通过将output='step’传递给find_events来有效地编码事件持续时间。

将嵌入events转换为annotation

一些EEG/MEG系统生成的文件里,event存储在单独的数据阵列中而不是STIM通道上。例如,EEGLAB格式将事件存储为.set文件中。当读取这些文件时,MNE-Python会自动将存储的事件转换为一个Annotations对象,并将其存储为Raw对象的Annotations属性:

testing_data_folder = mne.datasets.testing.data_path()
eeglab_raw_file = testing_data_folder / "EEGLAB" / "test_raw.set"
eeglab_raw = mne.io.read_raw_eeglab(eeglab_raw_file)
print(eeglab_raw.annotations)

Reading /home/circleci/mne_data/MNE-testing-data/EEGLAB/test_raw.fdt
<Annotations | 154 segments: rt (74), square (80)>

annotation对象中的数据可以通过它的三个属性访问:开始时间、持续时间和描述。在这里我们可以看到EEGLAB文件中存储了154个事件,它们的持续时间都是0秒,有两种不同的事件类型,第一个事件发生在记录开始后1秒左右:

print(len(eeglab_raw.annotations))
print(set(eeglab_raw.annotations.duration))
print(set(eeglab_raw.annotations.description))
print(eeglab_raw.annotations.onset[0])

154
{0.0}
{‘rt’, ‘square’}
1.000068

在Events arrays 和Annotations objects之间进行转换

这样做可能是因为,例如,需要Events array来遍历连续数据,或者需要利用某些函数的“annotation-aware”功能,该功能可以在数据与某些annotation重叠时自动忽略数据的范围。

要将annotation转换为Events,请使用函数mne.events_from_annotations这个函数将为raw.annotations.description的每个唯一元素分配一个整数ID,并将返回整数ID的映射的event array。

默认情况下,还将在每个annotation开始时创建一个event,可以通过events_from_annotations的chunk_duration参数来修改,以在每个注释范围内创建等间距的event。

events_from_annot, event_dict = mne.events_from_annotations(eeglab_raw)
print(event_dict)
print(events_from_annot[:5])

Used Annotations descriptions: [‘rt’, ‘square’]
{‘rt’: 1, ‘square’: 2}
[[128 0 2]
[217 0 2]
[267 0 1]
[602 0 2]
[659 0 1]]

可以传递一个dict,指定映射作为events_from_annotations的event_id参数。

custom_mapping = {"rt": 77, "square": 42}
(events_from_annot, event_dict) = mne.events_from_annotations(
    eeglab_raw, event_id=custom_mapping
)
print(event_dict)
print(events_from_annot[:5])

Used Annotations descriptions: [‘rt’, ‘square’]
{‘rt’: 77, ‘square’: 42}
[[128 0 42]
[217 0 42]
[267 0 77]
[602 0 42]
[659 0 77]]

进行想法 的转换,可以使用annotation_from_events来进行,如:

mapping = {
    1: "auditory/left",
    2: "auditory/right",
    3: "visual/left",
    4: "visual/right",
    5: "smiley",
    32: "buttonpress",
}
annot_from_events = mne.annotations_from_events(
    events=events,
    event_desc=mapping,
    sfreq=raw.info["sfreq"],
    orig_time=raw.info["meas_date"],
)
raw.set_annotations(annot_from_events)

现在,annotation将在绘制raw数据时自动出现,并将根据其标签值进行颜色编码:

raw.plot(start=5, duration=5)

在这里插入图片描述

用一个annotation生成多个events

如上所述,可以使用events_from_annotations的chunk_duration参数从annotation对象生成等间隔的event。例如,假设我们在Raw对象中有一个annotation,表明受试者何时处于REM睡眠状态,并且我们希望对这些数据范围执行静息状态分析。我们可以在每个“REM”范围内创建一系列等间隔事件的Events,然后使用这些事件生成epoch,然后进一步分析这些epoch。

这其实就是静息态分析的一种方法。

# create the REM annotations
rem_annot = mne.Annotations(onset=[5, 41], duration=[16, 11], description=["REM"] * 2)
raw.set_annotations(rem_annot)
(rem_events, rem_event_dict) = mne.events_from_annotations(raw, chunk_duration=1.5)

Used Annotations descriptions: [‘REM’]

现在我们可以检查我们的event确实落在5-21秒和41-52秒的范围内,并且间隔约1.5秒(由于采样率会引起的一些抖动)。以下是四舍五入到毫秒的事件时间:

print(np.round((rem_events[:, 0] - raw.first_samp) / raw.info["sfreq"], 3))

[ 5. 6.5 8. 9.5 11. 12.501 14.001 15.501 16.999 18.499 41. 42.5 44. 45.5 47. 48.5 50. ]

其他静息态分析可以参考mne.make_fixed_length_events的用法,官网可查,此处省略。

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值