第 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 |
每个 Raw、Epochs、Evoked 对象都带有一个 .info 属性 —— 同一种元数据容器,描述的是该对象所持有的具体数据。只要学会查看一次 .info,你就知道如何在这三者中的任意一个上查看它。
现在加载真实数据(前几章用到的公开样例数据集),逐一看看这几种对象。
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 本身确实被修改了
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 章 —— 加载与检查数据