第1章:MNE库入门——加载示例EEG数据
各位同学,欢迎来到实战课的第一站。
说实话,很多搞深度学习的同行一听到「神经信号」就觉得头大。什么采样率、电极排布、伪迹去除……听着就劝退。但我想说,处理EEG数据其实没那么玄乎。你只需要一个好用的工具箱——MNE-Python。
我个人习惯把MNE比作「神经信号界的Pandas」。它把那些乱七八糟的脑电数据,整理成规规矩矩的数据结构。你想想看,如果没有它,我们得手动解析二进制文件、处理时间戳、对齐事件……那画面太美我不敢看。
核心要点:MNE库是Python生态中最成熟的EEG/MEG处理库。它封装了数据加载、预处理、可视化、统计分析的全流程。说白了,你学会它,就等于拿到了神经信号处理的入场券。
1.1 安装与导入
先搞定环境。我建议你用conda创建虚拟环境,别把依赖搞乱了。我曾经在一个项目里同时装了三个版本的numpy,结果MNE报错报得我怀疑人生……
# 推荐用conda安装,省心
conda install -c conda-forge mne
# 或者用pip
pip install mne
安装完成后,导入库。注意,我习惯把mne简写为mn,但官方惯例是直接用mne。
import mne
import numpy as np
import matplotlib.pyplot as plt
# 检查版本
print(mne.__version__)
小技巧:如果你在Jupyter Notebook里跑,建议加上 %matplotlib inline,这样图直接显示在单元格下方,不用弹窗。
1.2 加载示例数据
MNE自带了好几个示例数据集。我最常用的是sample数据集,它包含了一个受试者的EEG和MEG数据。嗯,这里要注意——第一次加载需要联网下载,大概100MB左右。
# 加载示例数据
sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = sample_data_folder / 'MEG' / 'sample' / 'sample_audvis_raw.fif'
# 读取raw数据
raw = mne.io.read_raw_fif(sample_data_raw_file, verbose=False)
print(raw)
你会看到类似这样的输出:
<Raw | sample_audvis_raw.fif, 376 x 166800 (277.7 s), ~3.7 MB, data not loaded>
这里376是通道数,166800是采样点数,277.7秒是时长。我刚开始接触时,看到这些数字完全没概念。后来做项目多了才明白——通道数决定了你的空间分辨率,采样点数决定了时间分辨率。
1.3 三大核心数据结构
MNE里有三个你必须搞懂的数据结构:Raw、Epochs、Evoked。它们的关系就像「原材料→半成品→成品」。
让我用一张图来说明:
1.3.1 Raw——原始连续数据
Raw就是最原始的数据,像一卷长长的录音带。它包含了所有通道的连续时间序列。我一般拿到数据后,第一件事就是看raw.info,里面藏着所有元信息。
# 查看基本信息
print(raw.info)
print(f"采样率: {raw.info['sfreq']} Hz")
print(f"通道数: {len(raw.ch_names)}")
print(f"时长: {raw.times[-1]:.1f} 秒")
避坑指南:我曾经犯过一个低级错误——直接拿Raw数据做分类。结果模型学到的全是低频漂移和工频干扰,准确率还不如随机猜。记住:Raw数据必须经过预处理才能用。
1.3.2 Epochs——事件分段数据
Epochs是把Raw按照「事件」切成一个个小片段。比如,屏幕上出现一个刺激,我们就切出刺激前后各0.5秒的数据。这样每个试次就是一个Epoch。
# 从Raw创建Epochs
events = mne.find_events(raw, stim_channel='STI 014')
event_id = {'auditory/left': 1, 'auditory/right': 2}
epochs = mne.Epochs(raw, events, event_id=event_id,
tmin=-0.2, tmax=0.5,
baseline=(-0.2, 0), preload=True)
print(epochs)
输出示例:
<Epochs | 145 events, 2 conditions, -0.2 - 0.5 s, baseline -0.2 - 0 s, 376 ch, ~12 MB>
你看,145个试次,2种条件,每个试次从-0.2秒到0.5秒。baseline校正用的是刺激前200ms的数据。嗯,这里要注意——baseline的选择直接影响你的结果。选太短了校正不干净,选太长了可能包含前一个试次的残留。
1.3.3 Evoked——平均诱发响应
Evoked就是把同一条件下的Epochs做平均。为什么要平均?因为单次试次的信噪比太低了,平均之后才能看到稳定的诱发响应。
# 计算Evoked
evoked_aud_left = epochs['auditory/left'].average()
evoked_aud_right = epochs['auditory/right'].average()
print(evoked_aud_left)
print(evoked_aud_right)
输出:
<Evoked | 'auditory/left', 376 ch, -0.2 - 0.5 s, ~0.3 MB>
<Evoked | 'auditory/right', 376 ch, -0.2 - 0.5 s, ~0.3 MB>
个人经验:我一般会先看Evoked的波形,确认有没有明显的诱发成分(比如N100、P300)。如果波形乱成一团,那说明预处理可能有问题,或者实验设计有bug。别急着往下跑深度学习,先回头检查数据质量。
1.4 基础可视化
光看数字没感觉,画图才是王道。MNE的可视化功能非常强大,我挑三个最常用的给你看。
1.4.1 绘制Raw数据
# 绘制Raw的前10秒
raw.plot(n_channels=10, duration=5, start=0,
scalings='auto', block=True)
这个图会显示10个通道的波形。你可以用鼠标缩放、平移,还能标记坏道。我个人习惯先快速扫一遍Raw图,看看有没有明显的坏道或大伪迹。
1.4.2 绘制Epochs
# 绘制所有Epochs
epochs.plot(n_channels=10, events=True, block=True)
Epochs图会显示每个试次的波形,不同颜色代表不同条件。我经常用它来检查试次间的一致性。如果某个试次的波形明显异常,我会考虑把它剔除。
1.4.3 绘制Evoked
# 绘制Evoked对比
evoked_aud_left.plot(show=True)
evoked_aud_right.plot(show=True)
# 或者叠加对比
mne.viz.plot_compare_evokeds(
{'left': evoked_aud_left, 'right': evoked_aud_right},
picks=['EEG 001', 'EEG 002'])
Evoked图是最清晰的。你能看到刺激后几十毫秒到几百毫秒的波形变化。我一般会重点关注额叶和中央区的电极,因为听觉诱发电位在这些位置最明显。
1.5 本章小结
好了,这一章我们走通了MNE的基本流程:
- 安装导入——环境搭好,库导入
- 加载数据——用示例数据集练手
- 三大数据结构——Raw、Epochs、Evoked,从连续到分段再到平均
- 基础可视化——用眼睛检查数据质量
说实话,这些内容看起来简单,但它们是后续所有分析的基础。我见过太多人一上来就调深度学习模型,结果数据预处理都没做对,白白浪费算力。你想想看,如果输入的数据都是脏的,模型再牛也白搭。
下一章,我们会深入EEG的预处理流程——滤波、去伪迹、重参考。这些才是真正拉开差距的地方。