步骤 19:应用 ICA
从数据中去除伪迹 ICA 成分
1. 目标
把 ica.exclude 中的成分真正从数据中移除,重建 EEG 时间序列。剔除后眼电/心电等伪迹源被消除,但不影响其他成分。
2. 何时使用 / 何时跳过
- 必须使用:ICA 识别出伪迹成分后,最终施加剔除
- 绝不可跳过:否则
ica.exclude仅是标注,未实际生效
3. 前置条件
- 已执行步骤 18:
ica.exclude列表已稳定(包含 EOG + ECG 成分) - 注意:不要在原始数据上 apply,应在 epochs 上 apply(详见下文)
4. 核心代码
Python
import mne
# ====== 推荐做法:在 Epochs 上施加 ======
# ICA 施加前先创建 epochs(步骤 21)
# epochs = mne.Epochs(raw, events, ...)
# epochs.load_data()
# ica.apply(epochs)
# ====== 临时在 Raw 上施加(仅调试用) ======
# 警告:会修改 raw,建议保留 raw_for_ica 副本
raw_clean = ica.apply(raw.copy()) # 不修改原 raw
# 或就地修改:
# ica.apply(raw)
# ====== 验证剔除效果 ======
# 对比 raw vs raw_clean 的 EOG 通道附近(如 Fp1)
fp1_before = raw.copy().pick(['Fp1']).get_data()[0]
fp1_after = raw_clean.copy().pick(['Fp1']).get_data()[0]
variance_reduction = (fp1_before.var() - fp1_after.var()) / fp1_before.var() * 100
print(f"Fp1 方差降低: {variance_reduction:.1f}%")
# 期望:10-50%(显著降低但不会变 0)
# ====== 检查 exclude 列表 ======
print(f"ICA 排除成分: {ica.exclude}")
assert len(ica.exclude) > 0, "exclude 列表为空,未生效"
5. 参数详解(真实签名)
ica.apply(inst, include=None, exclude=None, n_pca_components=None, start=None, stop=None, *, on_baseline='warn', verbose=None)
| 参数 | 含义 | 推荐值 |
|---|---|---|
inst |
要施加的对象 | Epochs(推荐)/ Raw(仅调试) |
exclude |
要剔除的成分 | 默认用 ica.exclude |
include |
仅保留的成分(白名单) | 默认全部 |
n_pca_components |
PCA 降维后再剔除 | 默认 None |
start / stop |
时间窗 | 默认全部 |
⚠️ 真实签名中无
picks参数——ica.apply()不接受通道选择;它只对所有通道施加已计算好的 ICA 解混矩阵。
⚠️ 建议施加时机:在 Epochs 上ica.apply(),不要在 Raw 上。原因: 1. Raw 上剔除可能影响后续可视化判断; 2. Epochs 是最终分析对象,避免 Raw 与 Epochs 不一致。
6. 验证方法
Python
# 验证 1:exclude 列表已生效
print(f"剔除成分数: {len(ica.exclude)}")
assert len(ica.exclude) >= 1
# 验证 2:眼电时刻的振幅明显降低
# 手动找到一次眨眼时刻
blink_idx = raw.copy().pick(['VEOG']).get_data()[0].argmax()
blink_window = slice(blink_idx - 100, blink_idx + 100)
before = raw.get_data(picks=['Fp1'])[0, blink_window].var()
after = raw_clean.get_data(picks=['Fp1'])[0, blink_window].var()
print(f"眨眼时刻 Fp1 方差: 剔除前={before:.2e}, 剔除后={after:.2e}")
# 期望:after 显著小于 before
# 验证 3:脑电成分(视觉诱发)不应受影响
# 用 ERP 信号验证(具体研究依赖)
# 验证 4:可视化对比
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 1, sharex=True)
axes[0].plot(raw.times[:5000], raw.get_data(picks=['Fp1'])[0, :5000]*1e6)
axes[0].set_title('Before ICA')
axes[1].plot(raw_clean.times[:5000], raw_clean.get_data(picks=['Fp1'])[0, :5000]*1e6)
axes[1].set_title('After ICA')
7. 常见错误
| 错误 | 原因 | 解决方案 |
|---|---|---|
apply 后 ERP 没改善 |
误识别了一些正常成分 | 人工逐个核对 ica.exclude |
| 误删过多成分导致数据"过干净" | threshold 太低,自动识别过多 |
减少 ica.exclude |
apply 报错 unexpected keyword 'picks' |
picks 不是 apply 的参数 |
删除 picks= 参数;apply() 自动施加到 inst 的全部通道 |
| ICA 施加后通道变少 | 配置错误 | apply() 不会减通道;如减了请检查 n_pca_components |
| apply 在 Raw 上做了,epochs 又 apply 一次 | 双重剔除 | 仅在 Epochs 上 apply 一次 |
8. 官方来源
| 资源类型 | 链接 |
|---|---|
ica.apply |
https://mne.tools/stable/generated/mne.preprocessing.ICA.html#mne.preprocessing.ICA.apply |
| ICA 教程 | https://mne.tools/stable/auto_tutorials/preprocessing/plot_40_artifact_correction_ica.html |
9. 学术引用
Iriarte, J., et al. (2003). Independent component analysis as a tool for the analysis of EEG data. Clinical Neurophysiology, 114(11), 1995-2001.