步骤 07:坏导检测(第一次)
在原始数据上自动检测坏导通道
1. 目标
在未滤波的原始数据上识别明显坏导(如全段平坦、超高噪声、电极脱落)。本次检测侧重"明显物理异常",第二次检测(步骤 11)会在滤波后做更精细的统计检测。
2. 何时使用 / 何时跳过
- 应当使用:当通道数 ≥ 32、电极较多时;这是 mne-bids-pipeline 的标准做法
- 可跳过:极小数据集(< 16 导),但仍然建议至少跑一次
3. 前置条件
- 已执行步骤 06:montage 已设置
raw已preload=True
4. 核心代码
import mne
import numpy as np
# ====== 方法 A:LOF(Local Outlier Factor) ======
# mne-bids-pipeline 默认的自动检测算法
# 真实函数: mne.preprocessing.find_bad_channels_lof(New in MNE 1.7)
from mne.preprocessing import find_bad_channels_lof
bad_channels = find_bad_channels_lof(
raw,
n_neighbors=20,
threshold=1.5, # 阈值,越小越激进
picks=['eeg'],
verbose='INFO',
)
print(f"LOF 检测到的坏导: {bad_channels}")
# ====== 方法 B:基于功率谱的自动检测(无需额外依赖) ======
# 适合超平坦或超噪通道
psd = raw.compute_psd(picks='eeg')
psd_data = psd.get_data(power=True)
log_power = 10 * np.log10(psd_data)
# 自定义阈值(dB)
log_power_mean = log_power.mean(axis=1)
median_power = np.median(log_power_mean)
mad = np.median(np.abs(log_power_mean - median_power))
threshold_high = median_power + 5 * mad
threshold_low = median_power - 5 * mad
flat_channels = [psd.ch_names[i] for i, p in enumerate(log_power_mean) if p < threshold_low]
noisy_channels = [psd.ch_names[i] for i, p in enumerate(log_power_mean) if p > threshold_high]
print(f"平导: {flat_channels}, 噪导: {noisy_channels}")
# ====== 方法 C:交互式人工标记(推荐!) ======
# 弹出 GUI 窗口,点击通道名可标记坏导
raw.plot(block=True, bad_color='red')
# ====== 应用:把检测结果写入 raw.info['bads'] ======
raw.info['bads'] = bad_channels # 加入自动检测结果
# raw.info['bads'].extend(flat_channels) # 手动补充
print(f"当前坏导: {raw.info['bads']}")
⚠️
find_bad_channels_ransac不在 MNE 核心 API 中。mne-bids-pipeline 的旧版曾有自定义实现;新版推荐使用 LOF + 功率谱 + 人工标记三段法,或直接使用 autoreject.Ransac(需pip install autoreject)做通道级插值。
5. 参数详解
find_bad_channels_lof
| 参数 | 含义 | 推荐值 |
|---|---|---|
n_neighbors |
LOF 邻域大小 | 20(≤64 导)/ 50(≥128 导) |
threshold |
离群分数阈值 | 1.5(保守)/ 1.0(激进) |
picks |
参与检测的通道 | ['eeg'] |
⚠️ RANSAC 替代方案:本教材原稿提到的
find_bad_channels_ransac不在 MNE 核心 API。
推荐替代:
- autoreject.Ransac(pip install autoreject):https://autoreject.github.io/
- pyprep(PREP pipeline):https://github.com/sappelhoff/pyprep
- 手工 + PSD 阈值法:见本步骤方法 B |
6. 验证方法
# 验证 1:打印坏导列表
print(f"坏导数: {len(raw.info['bads'])}/{len(raw.ch_names)}")
print(f"坏导列表: {raw.info['bads']}")
# 验证 2:坏导占比应在 5%~15%
bad_ratio = len(raw.info['bads']) / sum(1 for ch in raw.info['chs'] if ch['kind'] == 2)
assert 0 <= bad_ratio <= 0.20, "坏导比例异常,请人工复核"
# 验证 3:可视化(坏导在 plot 中会被标红或标灰)
raw.plot(duration=5, n_channels=30)
# 验证 4:检查 raw.info['projs'] 是否仍为 []
# 坏导检测本身不投影,仅标记
assert len(raw.info['projs']) == 0, "本步骤不应创建 SSP 投影"
7. 常见错误
| 错误 | 原因 | 解决方案 |
|---|---|---|
| LOF 漏检明显坏导 | n_neighbors 太大或 threshold 太保守 |
调小 threshold 或用 plot 人工补 |
| RANSAC 检测过慢 | 数据太长 | 减小 n_samples 或分段检测 |
| 误把正常通道标为坏导 | 数据本身高噪声(如幼童 EEG) | 调低灵敏度,并结合可视化复核 |
| 自动检测结果不可信 | 缺乏领域知识 | 永远要配合步骤 11 的二次检测 + 人工 |
8. 官方来源
| 资源类型 | 链接 |
|---|---|
find_bad_channels_lof |
https://mne.tools/stable/generated/mne.preprocessing.find_bad_channels_lof.html |
find_bad_channels_ransac |
该函数不在 MNE 核心 API。见上 ⚠️ 警告小节,用 autoreject 或 pyprep 替代 |
compute_psd |
https://mne.tools/stable/generated/mne.io.Raw.html#mne.io.Raw.compute_psd |
| 坏导检测教程 | https://mne.tools/stable/auto_tutorials/preprocessing/15_handling_bad_channels.html |
| mne-bids-pipeline 默认算法 | https://mne.tools/mne-bids-pipeline/stable/settings/preprocessing/autobads.html |
9. 学术引用
Kumaravel, V. P., et al. (2022). Robust autocalibration of EEG electrode positions using LOF and RANSAC. Sensors, 22(19), 7314. (MNE LOF 检测参考)
Breunig, M. M., et al. (2000). LOF: identifying density-based local outliers. ACM SIGMOD Record, 29(2), 93-104. (LOF 算法原始论文)
Jas, M., et al. (2017). Autoreject: Automated artifact rejection for MEG and EEG. Neuroimage, 159, 417-429. (RANSAC 替代参考)