MNE-Python 第2天学习笔记:Montage与通道信息管理

一、什么是 Montage?

1.1 通俗理解

Montage (蒙太奇)在脑电领域指的是电极在头皮上的位置布局

想象一下:

(1)你的头皮是一张地图 🗺️

(2)每个电极是一个城市标记点 📍

(3)Montage 就是告诉你每个"城市"在地图上的坐标

1.2 为什么 Montage 很重要?

没有位置信息的数据就像:

(1)知道有 64 个人在说话,但不知道他们坐在哪里

(2)知道有温度数据,但不知道温度计放在哪个城市

有了 Montage 才能:

(1)🗺️ 绘制脑地形图(头皮电活动分布图)

(2)🔗 进行源定位(推测大脑内部哪个区域活跃)

(3)📊 对比不同被试的相同脑区

二、10-20 国际标准系统

2.1 什么是 10-20 系统?

这是国际通用的电极放置标准,"10-20"的含义是:

(1)相邻电极之间的距离是头骨前后/左右总距离的 10%20%

2.2 电极命名规则

每个电极名称由字母 + 数字组成:

数字规则:

(1)奇数(1,3,5,7):左侧

(2)偶数(2,4,6,8):右侧

(3)z(zero):中线

2.3 可视化 10-20 系统

python 复制代码
# 第二天完整代码开头(先运行这个)
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import mne
import numpy as np
import os
from collections import Counter

# 加载数据
sample_data_folder = mne.datasets.sample.data_path()
raw_fname = os.path.join(sample_data_folder, 'MEG', 'sample', 'sample_audvis_raw.fif')
raw = mne.io.read_raw_fif(raw_fname, preload=False)
print("✅ 数据加载完成")

三、实战:探索数据通道(重要!)

在实际分析中,数据往往不像教科书那么"标准"。我们必须先了解数据里有什么,才能正确处理。

3.1 查看通道类型

python 复制代码
print("\n📊 通道类型统计:")
ch_types = raw.get_channel_types()
type_counts = Counter(ch_types)

for ch_type, count in type_counts.items():
    print(f"  {ch_type}: {count} 个")

输出示例:

python 复制代码
  mag: 102 个     ← 脑磁图磁力计
  grad: 204 个    ← 脑磁图梯度计
  eeg: 60 个      ← 脑电图
  stim: 1 个      ← 刺激标记通道
  eog: 1 个       ← 眼电

3.2 查看 EEG 通道名称(关键!)

python 复制代码
# 找到所有 EEG 通道的索引
eeg_picks = mne.pick_types(raw.info, eeg=True)
print(f"\nEEG 通道数量: {len(eeg_picks)}")

# 查看 EEG 通道的名称
eeg_names = [raw.ch_names[i] for i in eeg_picks]
print(f"前10个 EEG 通道名称: {eeg_names[:10]}")

关键发现: 实际数据中的 EEG 通道名是 EEG 001, EEG 002, ...,而标准 Montage 中的名称是 Fz, Cz, Pz, ...

这就是设置 Montage 时会报错的原因!

四、解决通道名不匹配问题(实战核心)

4.1 问题诊断流程图

python 复制代码
数据通道名: EEG 001, EEG 002, EEG 003, ...
                 ↓
              ❌ 不匹配
                 ↓
标准Montage: Fz, Cz, Pz, C3, C4, ...
                 ↓
          【解决方案】
                 ↓
    提取EEG通道 → 重命名 → 设置Montage

4.2 解决方案:提取 + 重命名 + 设置

这是最常用的处理方法,分为三步:

python 复制代码
# ========== 步骤1:提取 EEG 通道 ==========
print("\n步骤1:提取 EEG 通道...")
raw_eeg = raw.copy().pick_types(eeg=True)
print(f"  提取了 {len(raw_eeg.ch_names)} 个 EEG 通道")
print(f"  通道名称示例: {raw_eeg.ch_names[:5]}")

# ========== 步骤2:创建标准 Montage ==========
print("\n步骤2:创建标准 Montage...")
montage = mne.channels.make_standard_montage('standard_1020')
print(f"  标准 Montage 包含 {len(montage.ch_names)} 个电极")
print(f"  标准电极名称示例: {montage.ch_names[:5]}")

# ========== 步骤3:重命名通道 ==========
print("\n步骤3:重命名通道...")
# 建立映射关系:EEG 001 → Fz, EEG 002 → Cz, ...
eeg_names = raw_eeg.ch_names  # 原始名称列表
standard_names = montage.ch_names[:len(eeg_names)]  # 取相同数量的标准名称

# 创建重命名字典
rename_dict = dict(zip(eeg_names, standard_names))
raw_eeg.rename_channels(rename_dict)
print("✅ 通道已重命名为标准 10-20 名称")
print(f"   示例: {list(rename_dict.items())[:3]}")

print(f"  重命名完成!")
print(f"  新通道名称: {raw_eeg.ch_names[:5]}")

# ========== 步骤4:设置 Montage ==========
print("\n步骤4:设置 Montage...")
raw_eeg.set_montage(montage)
print("  ✅ Montage 设置成功!")

至于为什么要加list,运行这段代码就知道了:

python 复制代码
rename_dict = {'Fz': 'Frontal', 'Cz': 'Central', 'Pz': 'Parietal', 'Oz': 'Occipital'}

# 情况1:不加 list
print(rename_dict.items())
# 输出:dict_items([('Fz', 'Frontal'), ('Cz', 'Central'), ('Pz', 'Parietal'), ('Oz', 'Occipital')])
# 不能加 [:3],会报错

# 情况2:加 list
print(list(rename_dict.items()))
# 输出:[('Fz', 'Frontal'), ('Cz', 'Central'), ('Pz', 'Parietal'), ('Oz', 'Occipital')]

# 情况3:加 list 并且只取前3个
print(list(rename_dict.items())[:3])
# 输出:[('Fz', 'Frontal'), ('Cz', 'Central'), ('Pz', 'Parietal')]  ← 干净清爽

4.3 代码详解

zip() 函数的作用:

python 复制代码
# zip 将两个列表配对
list1 = ['EEG 001', 'EEG 002', 'EEG 003']
list2 = ['Fz', 'Cz', 'Pz']

# zip 后变成:
# [('EEG 001', 'Fz'), ('EEG 002', 'Cz'), ('EEG 003', 'Pz')]

# dict() 将其变成字典:
# {'EEG 001': 'Fz', 'EEG 002': 'Cz', 'EEG 003': 'Pz'}

⚠️ 重要提示: 这个重命名假设 EEG 001 对应 Fz、EEG 002 对应 Cz...实际情况中,你需要根据实验记录来确定对应关系!

五、可视化电极位置

5.1 2D 电极位置图

python 复制代码
print("\n显示 2D 电极位置...")
raw_eeg.plot_sensors(show_names=True, title='EEG 电极位置(10-20系统)', block=True)

怎么看这个图?

(1)圆圈代表电极位置

(2)鼻子朝上(上方是额头方向)

(3)左耳在左边,右耳在右边

(4)可以直观看到电极覆盖的脑区

5.2 查看电极坐标

python 复制代码
print("\n部分电极的 3D 坐标:")
for ch in ['Fz', 'Cz', 'Pz', 'Oz', 'C3', 'C4']:
    if ch in montage.ch_names:
        pos = montage.get_positions()['ch_pos'][ch]
        print(f"  {ch}: x={pos[0]*1000:.1f}mm, y={pos[1]*1000:.1f}mm, z={pos[2]*1000:.1f}mm")

输出示例:

python 复制代码
  Fz: x=0.0mm, y=70.0mm, z=0.0mm    ← 额头正中
  Cz: x=0.0mm, y=0.0mm, z=70.0mm    ← 头顶正中
  Pz: x=0.0mm, y=-70.0mm, z=0.0mm   ← 后脑正中
  Oz: x=0.0mm, y=-140.0mm, z=-30.0mm ← 枕骨位置

5.3 3D 电极位置图(可选)

python 复制代码
print("\n尝试 3D 电极位置...")
try:
    raw_eeg.plot_sensors(kind='3d', title='3D 电极位置视图', block=True)
except Exception as e:
    print(f"  需要安装 pyvista: pip install pyvista")

六、通道管理技能

6.1 选择特定电极

python 复制代码
print("\n选择特定电极:")
# 选择运动想象常用的电极
selected = ['Fz', 'Cz', 'Pz', 'C3', 'C4']
raw_selected = raw_eeg.copy().pick([ch for ch in selected if ch in raw_eeg.ch_names])
print(f"  选择的电极: {raw_selected.ch_names}")

# 可视化选中的电极
raw_selected.plot_sensors(show_names=True, title='运动想象常用电极', block=True)

6.2 通道类型修改

python 复制代码
print("\n修改通道类型:")
# 假设 C3 和 C4 是主要的运动区电极
raw_selected.set_channel_types({
    'C3': 'eeg',
    'C4': 'eeg',
    'Cz': 'eeg'
})
print(f"  C3 类型: {raw_selected.get_channel_types(picks='C3')[0]}")

七、完整可运行代码

python 复制代码
# ========== 环境设置 ==========
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import mne
import numpy as np
import os
from collections import Counter

print("="*60)
print("📘 MNE-Python 第2天:Montage与通道信息管理")
print("="*60)

# ---------- 1. 加载数据 ----------
sample_data_folder = mne.datasets.sample.data_path()
raw_fname = os.path.join(sample_data_folder, 'MEG', 'sample', 'sample_audvis_raw.fif')
raw = mne.io.read_raw_fif(raw_fname, preload=False)
print("✅ 数据加载完成")

# ---------- 2. 探索数据通道 ----------
print("\n📊 通道类型统计:")
ch_types = raw.get_channel_types()
type_counts = Counter(ch_types)
for ch_type, count in type_counts.items():
    print(f"  {ch_type}: {count} 个")

print("\n🔍 查看 EEG 通道:")
eeg_picks = mne.pick_types(raw.info, eeg=True)
print(f"  EEG 通道数量: {len(eeg_picks)}")
print(f"  EEG 通道名称示例: {[raw.ch_names[i] for i in eeg_picks[:5]]}")

# ---------- 3. 提取 EEG + 重命名 + 设置 Montage ----------
print("\n🔧 处理步骤:提取 → 重命名 → 设置 Montage")

# 步骤1:提取 EEG 通道
raw_eeg = raw.copy().pick_types(eeg=True)
print(f"  步骤1: 提取了 {len(raw_eeg.ch_names)} 个 EEG 通道")

# 步骤2:创建标准 Montage
montage = mne.channels.make_standard_montage('standard_1020')
print(f"  步骤2: 标准 Montage 有 {len(montage.ch_names)} 个电极")

# 步骤3:重命名
eeg_names = raw_eeg.ch_names
standard_names = montage.ch_names[:len(eeg_names)]
rename_dict = dict(zip(eeg_names, standard_names))
raw_eeg.rename_channels(rename_dict)
print(f"  步骤3: 重命名完成,示例: {list(rename_dict.items())[:3]}")

# 步骤4:设置 Montage
raw_eeg.set_montage(montage)
print("  步骤4: ✅ Montage 设置成功!")

# ---------- 4. 可视化 ----------
print("\n🎨 可视化电极位置:")
raw_eeg.plot_sensors(show_names=True, title='EEG 电极位置(10-20系统)', block=True)

# ---------- 5. 通道操作练习 ----------
print("\n🔧 通道操作练习:")
selected = ['Fz', 'Cz', 'Pz', 'C3', 'C4']
raw_selected = raw_eeg.copy().pick([ch for ch in selected if ch in raw_eeg.ch_names])
print(f"  选择的电极: {raw_selected.ch_names}")

raw_selected.set_channel_types({'C3': 'eeg', 'C4': 'eeg'})
print("  ✅ 通道类型设置完成")

print("\n" + "="*60)
print("✅ 第2天学习完成!")
print("="*60)
相关推荐
涛声依旧-底层原理研究所1 小时前
防止Agent胡来五大安全防线
人工智能·python
RSTJ_16251 小时前
PYTHON+AI LLM DAY FIFITY-THREE
开发语言·人工智能·python
晚烛1 小时前
CANN 模型蒸馏实战:大模型知识迁移到小模型
python·线性代数·矩阵
俊哥工具1 小时前
解决网速卡顿、断网、网络报错,万能网络修复工具教程
网络·python·django·计算机外设·智能路由器·pygame
WL_Aurora1 小时前
Python爬虫实战(九):百度百聘招聘数据采集
爬虫·python·百度
lili00121 小时前
Gemini 3.5发布后的AI格局:谷歌重新定义行业标准
java·人工智能·python·ai编程
JunLa1 小时前
Java语法糖
java·python·哈希算法
财经资讯数据_灵砚智能1 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年5月21日
大数据·人工智能·python·信息可视化·自然语言处理
水木流年追梦1 小时前
大模型入门-RL基础
开发语言·python·算法·leetcode·正则表达式