简介
在这篇文章中,我们将学习如何使用MNE-Python库用Python处理EEG信号。
目录
- 脑电图简介
- 安装/设置
- 加载数据
- 绘制EEG信号图
- 预处理
- 划线
- 结论
脑电图简介
脑电图(EEG)是一种以脑电波形式连续记录大脑活动的技术。脑电图被普遍使用,因为它提供了一种无创的、简单的、廉价的方法来测量高分辨率的神经活动。
脑电图分析被大量用于评估大脑疾病,特别是癫痫或其他发作性疾病。它也被用于脑-机接口(BCI)。
脑电信号可以被看作是一个时间序列,因为脑电记录测量的是特定时间段的大脑活动。
脑电图设备是由放置在头皮上的不同电极组成。这些电极用蒙太奇表示为通道。有不同类型的蒙太奇,在这段视频中有详细描述。一个典型的EEG系统可以有1到256个通道。这些通道是根据它们在头皮上的位置来命名的。
安装/设置
在这篇文章中,我们将使用 MNE-Python库。它包含很多工具和算法,我们可以用来轻松分析EEG/MEG的记录。
我们可以通过使用以下pip
命令来安装 MNE:
pip install mne
NumPy也需要被安装:
pip install numpy
关于更详细的安装说明,请看这个链接的MNE和这个链接的NumPy。
导入必要的模块/库:
import os
import numpy as np
import mne
处理脑电图数据
加载数据
MNE软件包支持各种EEG文件格式,包括以下几种:
- 欧洲数据格式(.edf)
- EGI简单的二进制文件(.egi)
- EEGLAB集合文件(.set)
MNE有一个样本数据集,我们可以用它来熟悉处理EEG文件。下面的代码显示了我们如何读取一个MEG/EEG样本文件。对于不同的文件格式,有不同的方法。由于样本文件的扩展名是.fif,我们调用read_raw_fif
方法。另外,由于我们特别关注EEG通道,我们可以通过使用pick_types
方法排除所有非EEG通道:
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)
raw = raw.pick_types(meg=False, eeg=True, eog=False, exclude='bads')
这将创建一个Raw
对象(更多细节见这里)。
我们可以通过打印info
属性(一个类似字典的对象)来检查这个Raw
对象:
print(raw.info)
Output:
<Info | 14 non-empty values
bads: []
ch_names: EEG 001, EEG 002, EEG 003, EEG 004, EEG 005, EEG 006, EEG 007, ...
chs: 59 EEG
custom_ref_applied: False
dev_head_t: MEG device -> head transform
dig: 146 items (3 Cardinal, 4 HPI, 61 EEG, 78 Extra)
file_id: 4 items (dict)
highpass: 0.1 Hz
hpi_meas: 1 item (list)
hpi_results: 1 item (list)
lowpass: 40.0 Hz
meas_date: 2002-12-03 19:01:10 UTC
meas_id: 4 items (dict)
nchan: 59
projs: Average EEG reference: off
sfreq: 150.2 Hz
>
info
属性记录了频道位置、录制日期、频道数量等信息。关于Info
结构的进一步详细信息,可以在这里找到MNE文档。
裁剪数据
MNERaw
对象有一个crop
方法,可以用来限制原始文件中的数据在特定时间(以秒为单位)之间。这可以帮助节省内存:
raw.crop(0, 60) # keeps the first minute of data and discards the rest
绘制脑电图信号
MNE有几种方法来绘制Raw
对象。这里有一个方法可以生成原始数据的图:
raw.plot()
我们还可以绘制每个通道的功率谱密度(PSD)。PSD显示功率与频率的关系,以每单位频率的功率来衡量。它显示了哪些频率的变化是强的,以及哪些频率的变化是弱的:
raw.plot_psd()
在交互式Python会话中,plot
函数创建交互式图表。这些功能允许滚动、缩放、注释等。
预处理
重新取样
脑电图记录具有很高的时间分辨率,所以它们通常以高采样率记录(例如,1000赫兹或更高)。虽然这使得记录非常精确,但也消耗了更多的内存。在不需要高度精确计时的情况下,对EEG信号进行降频可以帮助节省大量的计算时间。
Raw
物体有一个 方法,可以用来从一个采样率转换到另一个。resample
raw.resample(600) #resamples to a rate of 600 Hz
Output:
Measurement date December 03, 2002 19:01:10 GMT
Experimenter Unknown
Participant Unknown
Digitized points 0 points
Good channels 59 EEG
Bad channels None
EOG channels Not available
ECG channels Not available
Sampling frequency 600.00 Hz
Highpass 1.00 Hz
Lowpass 40.00 Hz
Projections Average EEG reference : off
Filenames sample_audvis_filt-0-40_raw.fif
Duration 00:01:00 (HH:MM:SS)
滤波
脑电图数据可能有各种假象和噪声,因此必须进行预处理,以最大限度地提高信噪比(SNR),它衡量的是信号功率与噪声功率的比率。
滤波是用于降低噪音/去除伪影的几种技术之一。
Raw
对象有一个 ,该方法需要两个参数-- ,代表低通带边缘, ,代表高通带边缘。filter
lfreq
hfreq
高通滤波
高通滤波衰减了低于某一截止频率的频率。信号的其余部分保持不变。
下面的代码过滤信号衰减了1Hz以下的信号,其余部分保持不变。由于hfreq
是None
,没有上通带的边缘,所以信号是高通的。
raw.filter(1., None)
低通滤波
低通滤波本质上与高通滤波相反。它不是减弱低于某一频率的部分信号,而是减弱高于某一频率的部分信号。它之所以被称为低通,是因为它让低于某一截止点的频率通过。
下面的代码衰减了信号中高于50Hz的部分,其余部分没有变化。由于lfreq
是None
,所以没有低通带的边缘,所以信号是低通的。
raw.filter(None, 50.)
陷波滤波器(带阻滤波器)
陷波滤波器是低通和高通滤波器的结合。它可以在一个特定的频率范围内衰减信号。带阻滤波器所衰减的频率范围被称为止损带。
Raw
对象有一个 方法,它接收一个特定的频率或一个频率列表来衰减信号。notch_filter
raw.notch_filter(60)
上面这个例子,将信号衰减在60赫兹。
陷波滤波器通常用于去除电力线噪音,电力线噪音的频率为50或60赫兹,这取决于录音地点。在谐波频率(电力线频率的整数倍,如60、120、180等)可能会有峰值。
我们可以通过使用numpy.arange
方法将陷波滤波器应用于这些频率中的每一个频率。它在start
(含)和stop
(不含)参数之间转出一个均匀间隔的数值阵列。这些均匀的值之间的距离为step
,这是另一个参数numpy.arange
。
下面的代码将对频率为60、120、180和240的部分信号进行衰减。
# the first 60 is start (inclusive), 241 is stop (exlusive), and 60 is step
raw.notch_filter(np.arange(60, 241, 60))
分期付款
历时是指从连续EEG数据中提取的等长的数据段。通常情况下,历时是围绕刺激事件或反应提取的,但有时也会使用连续或重叠的历时。
MNE有一个Epochs
对象,用来表示 epoched数据。Epochs
对象被用于EEG分析的其他步骤,包括用于机器学习的特征提取。
为了创建 epoched 数据,MNE-Python需要一个Raw
对象以及一个事件数组。
事件
MNE中的事件提供了EEG/MEG记录期间特定时间和这些时间发生的事情之间的映射。事件以二维NumPy数组的形式存储。
有两种方法来创建事件:从文件/Raw
对象中读取或创建同等大小的事件。
读取事件
我们将使用一个不同的样本记录,因为我们最初使用的那个样本不包含任何事件。
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
对象中读取事件。
events = mne.find_events(raw)
Output:
320 events found
Event IDs: [ 1 2 3 4 5 32]
创建等长的事件
有时,原始EEG记录中可能不包含任何事件。在这种情况下,可以生成一个等距的事件阵列。下面的代码为EEG数据的前10秒创建了秒长的事件。
events = mne.make_fixed_length_events(raw, start=0, stop=10, duration=1.)
要创建重叠一定时间的事件,我们可以在调用make_fixed_length_events
方法时使用overlap
参数指定这个时间。
events = mne.make_fixed_length_events(raw, start=0, stop=10, duration=1., overlap=0.5)
从事件中创建Epoched数据
在加载/创建事件之后,创建一个Epochs
对象是相当简单的。
epochs = mne.Epochs(raw, events, preload=True).pick_types(eeg=True)
preload=True
在创建 对象时,从磁盘加载所有的历时。Epochs
选择历时数据
现在我们有了带有事件标签的Epochs
对象,我们可以用方括号选择历时。
例如,我们可以绘制事件标签为 "1 "的历时(这些事件标签有实际意义,但为了简单起见,这里没有显示)。
epochs['1'].plot()
输出。
结论
在这篇文章中,我们了解了EEG信号,如何加载、分析、预处理等。了解如何处理脑电信号对建立在它之上的任务非常有帮助--其中一个重要的例子是训练机器学习模型来对脑电片段进行分类。
这篇文章就到这里,感谢您的阅读。