第 3 章:加载与检查数据¶
本章讲解如何把 EEG 文件读入 MNE,以及在做任何处理之前值得先做的检查 —— 就是我们对你自己的文件所做的那些检查,这里会完整讲一遍。
文件格式及其对应的读取函数¶
对大多数 EEG/MEG 文件格式,MNE 都提供了专门的读取函数。一些常见的例子:
| 格式 | 扩展名 | 读取函数 |
|---|---|---|
| European Data Format | .edf、.bdf |
mne.io.read_raw_edf |
| BrainVision | .vhdr(+ .vmrk、.eeg) |
mne.io.read_raw_brainvision |
| Neuroscan | .cnt |
mne.io.read_raw_cnt |
| EEGLAB | .set |
mne.io.read_raw_eeglab |
| Neuromag/Elekta/MEGIN(MEG,样例数据集使用的格式) | .fif |
mne.io.read_raw_fif |
它们返回的都是同一种对象 —— Raw,所以一旦加载完成,无论原始文件格式是什么,后续的一切处理(也就是本教程剩下的全部内容)都是完全一样的。这正是为什么你自己的 .edf 文件和样例数据集的 .fif 文件可以走完全相同的处理流程。
import mne
import matplotlib.pyplot as plt
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"])
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 | |
处理前检查清单¶
在动手处理数据之前,务必先检查: 1. 通道名称和类型 —— 是否与预期一致? 2. 采样率和记录时长。 3. 是否存在标注(annotation)/事件。 4. 电极位置(montage)是否已经设置好。 5. 用肉眼看有没有明显异常的坏通道。
print("通道名称:", raw.ch_names)
print("通道类型:", set(raw.get_channel_types()))
print("采样率 (Hz):", raw.info["sfreq"])
print("时长 (s):", raw.times[-1])
通道名称: ['EEG 001', 'EEG 002', 'EEG 003', 'EEG 004', 'EEG 005', 'EEG 006', 'EEG 007', 'EEG 008', 'EEG 009', 'EEG 010', 'EEG 011', 'EEG 012', 'EEG 013', 'EEG 014', 'EEG 015', 'EEG 016', 'EEG 017', 'EEG 018', 'EEG 019', 'EEG 020', 'EEG 021', 'EEG 022', 'EEG 023', 'EEG 024', 'EEG 025', 'EEG 026', 'EEG 027', 'EEG 028', 'EEG 029', 'EEG 030', 'EEG 031', 'EEG 032', 'EEG 033', 'EEG 034', 'EEG 035', 'EEG 036', 'EEG 037', 'EEG 038', 'EEG 039', 'EEG 040', 'EEG 041', 'EEG 042', 'EEG 043', 'EEG 044', 'EEG 045', 'EEG 046', 'EEG 047', 'EEG 048', 'EEG 049', 'EEG 050', 'EEG 051', 'EEG 052', 'EEG 053', 'EEG 054', 'EEG 055', 'EEG 056', 'EEG 057', 'EEG 058', 'EEG 059', 'EEG 060', 'EOG 061']
通道类型: {'eeg', 'eog'}
采样率 (Hz): 600.614990234375
时长 (s): 277.7136813300495
通道类型与 picks¶
一份文件里常常混合了 EEG 与其他类型的通道(EOG 记录眼动、ECG 记录心跳、stim/触发通道)。MNE 需要正确的类型信息才知道,比如说,不要把一个触发通道当作脑信号来处理。如果某个通道的类型不对,可以用 raw.set_channel_types({"chan_name": "eog"}) 来修正。
类型正确之后,大多数函数都可以用 picks 参数只处理其中一部分通道 —— picks="eeg" 是最常见的用法。
for ch_name, ch_type in zip(raw.ch_names, raw.get_channel_types()):
print(f"{ch_name:>8} -> {ch_type}")
EEG 001 -> eeg
EEG 002 -> eeg
EEG 003 -> eeg
EEG 004 -> eeg
EEG 005 -> eeg
EEG 006 -> eeg
EEG 007 -> eeg
EEG 008 -> eeg
EEG 009 -> eeg
EEG 010 -> eeg
EEG 011 -> eeg
EEG 012 -> eeg
EEG 013 -> eeg
EEG 014 -> eeg
EEG 015 -> eeg
EEG 016 -> eeg
EEG 017 -> eeg
EEG 018 -> eeg
EEG 019 -> eeg
EEG 020 -> eeg
EEG 021 -> eeg
EEG 022 -> eeg
EEG 023 -> eeg
EEG 024 -> eeg
EEG 025 -> eeg
EEG 026 -> eeg
EEG 027 -> eeg
EEG 028 -> eeg
EEG 029 -> eeg
EEG 030 -> eeg
EEG 031 -> eeg
EEG 032 -> eeg
EEG 033 -> eeg
EEG 034 -> eeg
EEG 035 -> eeg
EEG 036 -> eeg
EEG 037 -> eeg
EEG 038 -> eeg
EEG 039 -> eeg
EEG 040 -> eeg
EEG 041 -> eeg
EEG 042 -> eeg
EEG 043 -> eeg
EEG 044 -> eeg
EEG 045 -> eeg
EEG 046 -> eeg
EEG 047 -> eeg
EEG 048 -> eeg
EEG 049 -> eeg
EEG 050 -> eeg
EEG 051 -> eeg
EEG 052 -> eeg
EEG 053 -> eeg
EEG 054 -> eeg
EEG 055 -> eeg
EEG 056 -> eeg
EEG 057 -> eeg
EEG 058 -> eeg
EEG 059 -> eeg
EEG 060 -> eeg
EOG 061 -> eog
Montage(电极位置)¶
有些文件格式/采集系统会保存真实的、数字化的三维电极位置(这个样例数据集就是这样 —— 下面用 raw.get_montage() 看一下)。而另一些,比如你自己导出的 .edf 文件,则不会保存,你需要通过匹配通道名称,自己给它套上一个通用的标准 montage —— 这正是为什么在 raw.set_montage(...) 能在你的文件上生效之前,我们需要先做通道改名这一步(EEG Fp1-CPz → Fp1)。
montage = raw.get_montage()
print(montage)
montage.plot(kind="topomap", show_names=True)
plt.show()
<DigMontage | 78 extras (headshape), 4 HPIs, 3 fiducials, 60 channels>

事件存放在哪里:标注(annotations)还是刺激通道¶
事件标记会出现在两个地方之一,取决于记录系统:
raw.annotations—— 附加在文件上的一系列带标签的时间点(常见于.edf导出文件,比如你的文件)。- 专门的刺激/触发通道 —— 这个通道的值会跳变,用来编码刚刚发生了哪个事件,用
mne.find_events()读取(本样例数据集用的就是这种方式,通道名为STI 014)。
第 6 章我们会用真实数据实际操作这两种方法。现在先看看当前数据里有什么:
print("标注:", raw.annotations)
print("是否存在 'stim' 类型的通道?", "stim" in raw.get_channel_types())
# 说明:我们前面已经只挑选了 eeg/eog 通道,所以这份文件原本的刺激通道在这里已经被特意去掉了
标注: <Annotations | 0 segments>
是否存在 'stim' 类型的通道? False
可视化原始数据¶
两种互补的视角:随时间变化的原始波形,以及功率谱密度(power spectral density,即每个频率上存在多少信号功率 —— 快速发现电源线噪声或过度高频肌肉污染的好办法)。
raw.plot(n_channels=20, duration=10, scalings="auto")
plt.show()

raw.compute_psd(picks="eeg").plot()
plt.show()

留意在 50 或 60 Hz 处是否有一个尖峰(电源线噪声 —— 第 4 章陷波滤波器要针对的目标),并检查功率在更高频率处是平滑下降,还是出现了异常的凸起(可能是肌肉污染)。
标记坏通道¶
在上面用 raw.plot() 逐屏查看时,如果某个通道是平的、始终异常嘈杂,或者和邻近通道差异很大,就是被标记为"坏(bad)"的候选对象。坏通道默认会被大多数分析和绘图排除在外,之后也可以选择通过从邻近好通道插值来重建它(raw.interpolate_bads(),需要有 montage)。
raw.info["bads"] = [] # 例如,如果上面发现了坏通道,可以写 ["EEG 053"]
小结¶
- 每种格式都有专门的
mne.io.read_raw_*函数,但它们产出的都是同一种Raw对象。 - 处理数据前,务必先检查通道名称/类型、采样率、montage,以及事件存放在哪里。
raw.plot()用于时域检查,raw.compute_psd().plot()用于频域检查。
下一章:第 4 章 —— 预处理