Skip to content

第 2 章:MNE-Python 核心概念

MNE-Python 是 MEG/EEG 分析领域标准的开源 Python 库 —— 大多数使用 Python 发表的 EEG 论文都用它。它的官方文档和教程在 mne.tools;这个教程系列的所有内容都以那份文档为基础,为初次接触的读者做了改编。

你在 MNE 中要做的几乎所有事情,都围绕着四种对象类型展开。掌握这四种对象,库里其他的部分自然就读得懂了,因为每个函数的工作,说到底都是创建、转换,或者从这四者之一中提取信息。

四个核心对象

对象 底层数据的形状 代表什么
Info (仅元数据) 通道名称/类型、采样率、滤波历史、坏通道、montage(电极布局)—— 描述一次记录的"表头"
Raw (n_channels, n_times) 完整的连续记录
Epochs (n_epochs, n_channels, n_times) 围绕事件切出的许多短片段
Evoked (n_channels, n_times) 跨 epoch 的平均值 —— 这就是你的 ERP

每个 RawEpochsEvoked 对象都带有一个 .info 属性 —— 同一种元数据容器,描述的是该对象所持有的具体数据。只要学会查看一次 .info,你就知道如何在这三者中的任意一个上查看它。

现在加载真实数据(前几章用到的公开样例数据集),逐一看看这几种对象。

Raw、Epochs 和 Evoked 数据的形状

import mne
from pathlib import Path

mne.set_log_level("WARNING")

sample_folder = Path(mne.datasets.sample.data_path()) / "MEG" / "sample"
raw = mne.io.read_raw_fif(sample_folder / "sample_audvis_raw.fif", preload=True)
raw.pick(["eeg", "eog"])  # 让本教程专注于 EEG,就像你自己的数据一样
raw
General
Filename(s) sample_audvis_raw.fif
MNE object type Raw
Measurement date 2002-12-03 at 19:01:10 UTC
Participant Unknown
Experimenter MEG
Acquisition
Duration 00:04:38 (HH:MM:SS)
Sampling frequency 600.61 Hz
Time points 166,800
Channels
EEG and
EOG
Head & sensor digitization 146 points
Filters
Highpass 0.10 Hz
Lowpass 172.18 Hz

Info:元数据

raw.info 的用法就像一个字典。其中一些最常用的键:

print("采样率:", raw.info["sfreq"])
print("通道数量:", raw.info["nchan"])
print("坏通道:", raw.info["bads"])
print("已应用的高通/低通:", raw.info["highpass"], raw.info["lowpass"])
raw.info  # 直接打印它会给出一份完整、可读的摘要
采样率: 600.614990234375
通道数量: 61
坏通道: ['EEG 053']
已应用的高通/低通: 0.10000000149011612 172.17630004882812
General
MNE object type Info
Measurement date 2002-12-03 at 19:01:10 UTC
Participant Unknown
Experimenter MEG
Acquisition
Sampling frequency 600.61 Hz
Channels
EEG and
EOG
Head & sensor digitization 146 points
Filters
Highpass 0.10 Hz
Lowpass 172.18 Hz

Raw:连续记录

在底层,Raw 包装了一个普通的二维 NumPy 数组:每一行是一个通道,每一列是一个时间采样点。可以用 .get_data() 直接取出这个数组 —— 值得记住的是,MNE 所做的一切,归根结底都是"数组运算 + 附带的元数据"。

data = raw.get_data()
print("数据形状(通道数,时间采样点数):", data.shape)
print("数据默认以伏特为单位;例如第一个通道的前 5 个采样点:", data[0, :5])
数据形状(通道数,时间采样点数): (61, 166800)
数据默认以伏特为单位;例如第一个通道的前 5 个采样点: [1.13989260e-05 9.85015885e-06 7.68188489e-06 5.82336435e-06
 6.81457530e-07]

你会反复见到的代码模式

MNE 中有几个惯例几乎无处不在 —— 现在认清它们,能省下不少之后的困惑:

1. 很多方法会就地修改对象本身(同时也会返回该对象,以便链式调用)—— raw.filter(...) 会改变 raw 本身。如果想保留原始数据不变,先 .copy() 一份:

raw_filtered = raw.copy().filter(l_freq=1, h_freq=40)  # raw 本身不受影响
raw.filter(l_freq=1, h_freq=40)                         # raw 本身确实被修改了
这正是我们在"应用到你自己的数据"那个 notebook 中使用的模式(raw_filt = raw.copy().filter(...)),专门是为了让未滤波的 raw 保留下来,方便对比。

2. preload:以 preload=False(有时是默认值)读取文件,只会读取头信息/元数据,不会读取实际信号 —— 如果你只是想查看 .info 或者想先裁剪(crop)再加载全部数据,这样速度更快。大多数处理步骤都需要 preload=True(无论是在读取时设置,还是之后调用 raw.load_data())。

3. picks:许多函数都接受 picks 参数,用来只处理一部分通道,例如 picks="eeg"picks=["Fz", "Cz"],或 picks="eog"

4. verbose:几乎每个函数都接受 verbose=...,用来独立控制自身的日志输出,不受我们上面设置的全局 mne.set_log_level(...) 影响。

不离开 notebook 就能获取帮助

在 Jupyter 中,在任意函数或方法后面加上 ?,就能弹出它的文档字符串(docstring,包含完整的参数列表、默认值和说明)—— 这是在不离开 VS Code 的情况下,最快搞清楚"这个参数是干什么的"的方法。

raw.filter?

小结

  • Info = 元数据,附加在所有对象上。
  • Raw = 连续记录(二维:通道 × 时间)。
  • Epochs = 试次片段(三维:试次 × 通道 × 时间)—— 第 6 章。
  • Evoked = Epochs 的平均值 = 你的 ERP —— 第 7 章。
  • 记住:就地修改方法之前先 .copy(),要实际加载数据需要 preload=True,用 picks 选择通道,用 函数名? 即时查文档。

下一章:第 3 章 —— 加载与检查数据