第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里有三个你必须搞懂的数据结构:RawEpochsEvoked。它们的关系就像「原材料→半成品→成品」。

让我用一张图来说明:

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的预处理流程——滤波、去伪迹、重参考。这些才是真正拉开差距的地方。


公众号:蓝海数据掘金营,微信 deep3321