注意
转到末尾下载完整示例代码。
使用 mne.Report 创建质量控制(QC)报告#
质量控制(QC)是指在分析流程的各个阶段系统地检查 M/EEG 数据的过程,包括原始数据、中间预处理步骤以及衍生结果。
虽然 QC 通常始于对原始记录的初步检查,但同样重要的是确认信号在经过滤波、伪迹校正、分段和平均等操作后仍然“看起来合理”。任何阶段引入或遗漏的问题都可能向下游传播,使后续分析失效。
本教程演示如何使用 mne.Report 创建一份连贯的叙述式 QC 报告,重点在于应当检查什么以及如何解读结果,而非详尽介绍 API。
为保证清晰和可复现,下面的示例聚焦于在分析流程代表性阶段常用的 QC 检查。每当应用新的处理步骤时,同样的报告方法都可以——也应该——被复用。
我们使用 MNE 示例数据集进行演示。并非所有 QC 部分都适用于每个数据集(例如连续头位跟踪),本教程会明确处理这类情况。
注意
更多完整报告的示例,请参阅 MNE-BIDS-Pipeline 的 QC 报告。
# Authors: The MNE-Python contributors
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.
from pathlib import Path
import mne
from mne.preprocessing import ICA, create_eog_epochs
加载示例数据集#
我们从 MNE 示例数据集中加载一段已预滤波的 MEG/EEG 记录,仅保留与 QC 相关的通道(MEG、EEG、EOG、刺激通道)。
data_path = Path(mne.datasets.sample.data_path(verbose=False))
subject = "sample"
sample_dir = data_path / "MEG" / subject
subjects_dir = data_path / "subjects"
raw_path = sample_dir / "sample_audvis_filt-0-40_raw.fif"
raw = mne.io.read_raw(raw_path)
# We will also crop the dataset for speed
raw.crop(0, 60).load_data()
# Retain only channels relevant for QC to simplify visualization and
# focus inspection on signals typically reviewed during data quality checks.
raw.pick(["meg", "eeg", "eog", "stim"])
sfreq = raw.info["sfreq"] # Sampling Frequency (Hz)
Opening raw data file /home/circleci/mne_data/MNE-sample-data/MEG/sample/sample_audvis_filt-0-40_raw.fif...
Read a total of 4 projection items:
PCA-v1 (1 x 102) idle
PCA-v2 (1 x 102) idle
PCA-v3 (1 x 102) idle
Average EEG reference (1 x 60) idle
Range : 6450 ... 48149 = 42.956 ... 320.665 secs
Ready.
Reading 0 ... 9009 = 0.000 ... 59.999 secs...
创建 QC 报告#
报告充当一个容器,将图形、表格和文本汇集到单个 HTML 文档中。
report = mne.Report(
title="Sample dataset - Quality Control report",
subject=subject,
subjects_dir=subjects_dir,
)
Embedding : jquery-3.6.0.min.js
Embedding : bootstrap.bundle.min.js
Embedding : bootstrap.min.css
Embedding : bootstrap-table/bootstrap-table.min.js
Embedding : bootstrap-table/bootstrap-table.min.css
Embedding : bootstrap-table/bootstrap-table-copy-rows.min.js
Embedding : bootstrap-table/bootstrap-table-export.min.js
Embedding : bootstrap-table/tableExport.min.js
Embedding : bootstrap-icons/bootstrap-icons.mne.min.css
Embedding : highlightjs/highlight.min.js
Embedding : highlightjs/atom-one-dark-reasonable.min.css
数据集概览#
简要的概览能帮助审阅者立即了解数据集的规模和基本属性。
html_overview = """
This report presents a quality control (QC) overview of the MNE sample dataset.<br><br>
For information about the paradigm, see
<a href="https://mne.tools/stable/documentation/datasets.html#sample">the MNE docs</a>.
"""
report.add_html(
title="Overview",
html=html_overview,
tags=("overview"),
)
原始数据检查#
原始数据的目视检查是最重要的单项 QC 步骤。这里我们同时检查时间序列和功率谱密度(PSD)。
留意振幅异常大或信号平坦的通道。
在 PSD 中,检查是否存在过度的低频漂移、强烈的工频噪声,或与相邻通道相比异常的频谱形态。
report.add_raw(
raw,
title="Raw data overview",
psd=False, # omit just for speed here
)
Using matplotlib as 2D backend.
Using qt as 2D backend.
事件与刺激时序#
正确的事件检测对所有后续基于分段的分析至关重要。
确认事件数量与预期一致。
检查事件时间是否合理且分布均匀。
事件缺失或重复通常表明触发通道存在问题。
events = mne.find_events(raw)
report.add_events(
events,
sfreq=sfreq,
title="Detected events",
)
Finding events on: STI 014
86 events found on stim channel STI 014
Event IDs: [ 1 2 3 4 5 32]
分段与剔除统计#
分段(Epoching)可以检查与事件锁时的数据段,并基于振幅阈值进行自动剔除。
event_id = {
"auditory/left": 1,
"auditory/right": 2,
"visual/left": 3,
"visual/right": 4,
}
epochs = mne.Epochs(
raw,
events,
event_id=event_id,
tmin=-0.2,
tmax=0.5,
baseline=(None, 0),
reject=dict(eeg=150e-6),
preload=True,
)
report.add_epochs(
epochs,
title="Epochs and rejection statistics",
)
Not setting metadata
78 matching events found
Setting baseline interval to [-0.19979521315838786, 0.0] s
Applying baseline correction (mode: mean)
Created an SSP operator (subspace dimension = 4)
4 projection items activated
Using data from preloaded Raw for 78 events and 106 original time points ...
Rejecting epoch based on EEG : ['EEG 001', 'EEG 002', 'EEG 003', 'EEG 007']
1 bad epochs dropped
Using multitaper spectrum estimation with 7 DPSS windows
Plotting power spectral density (dB=True).
Averaging across epochs before plotting...
Averaging across epochs before plotting...
Averaging across epochs before plotting...
诱发响应#
平均后的响应应呈现生理上合理的波形和适当的信噪比。
检查诱发响应的极性和时序是否符合预期。
若缺乏清晰的诱发结构,可能表明数据质量较差或事件定义不正确。
cov_path = sample_dir / "sample_audvis-cov.fif"
evoked = mne.read_evokeds(
sample_dir / "sample_audvis-ave.fif",
baseline=(None, 0),
)[0] # just one for speed
evoked.decimate(4) # also for speed
report.add_evokeds(
evokeds=evoked,
noise_cov=cov_path,
n_time_points=5,
)
Reading /home/circleci/mne_data/MNE-sample-data/MEG/sample/sample_audvis-ave.fif ...
Read a total of 4 projection items:
PCA-v1 (1 x 102) active
PCA-v2 (1 x 102) active
PCA-v3 (1 x 102) active
Average EEG reference (1 x 60) active
Found the data of interest:
t = -199.80 ... 499.49 ms (Left Auditory)
0 CTF compensation matrices available
nave = 55 - aspect type = 100
Projections have already been applied. Setting proj attribute to True.
Applying baseline correction (mode: mean)
Read a total of 4 projection items:
PCA-v1 (1 x 102) active
PCA-v2 (1 x 102) active
PCA-v3 (1 x 102) active
Average EEG reference (1 x 60) active
Found the data of interest:
t = -199.80 ... 499.49 ms (Right Auditory)
0 CTF compensation matrices available
nave = 61 - aspect type = 100
Projections have already been applied. Setting proj attribute to True.
Applying baseline correction (mode: mean)
Read a total of 4 projection items:
PCA-v1 (1 x 102) active
PCA-v2 (1 x 102) active
PCA-v3 (1 x 102) active
Average EEG reference (1 x 60) active
Found the data of interest:
t = -199.80 ... 499.49 ms (Left visual)
0 CTF compensation matrices available
nave = 67 - aspect type = 100
Projections have already been applied. Setting proj attribute to True.
Applying baseline correction (mode: mean)
Read a total of 4 projection items:
PCA-v1 (1 x 102) active
PCA-v2 (1 x 102) active
PCA-v3 (1 x 102) active
Average EEG reference (1 x 60) active
Found the data of interest:
t = -199.80 ... 499.49 ms (Right visual)
0 CTF compensation matrices available
nave = 58 - aspect type = 100
Projections have already been applied. Setting proj attribute to True.
Applying baseline correction (mode: mean)
366 x 366 full covariance (kind = 1) found.
Read a total of 4 projection items:
PCA-v1 (1 x 102) active
PCA-v2 (1 x 102) active
PCA-v3 (1 x 102) active
Average EEG reference (1 x 60) active
NOTE: pick_types() is a legacy function. New code should use inst.pick(...).
Computing rank from covariance with rank=None
Using tolerance 4.7e-14 (2.2e-16 eps * 59 dim * 3.6 max singular value)
Estimated rank (eeg): 58
EEG: rank 58 computed from 59 data channels with 1 projector
Computing rank from covariance with rank=None
Using tolerance 1.8e-13 (2.2e-16 eps * 203 dim * 3.9 max singular value)
Estimated rank (grad): 203
GRAD: rank 203 computed from 203 data channels with 0 projectors
Computing rank from covariance with rank=None
Using tolerance 2.5e-14 (2.2e-16 eps * 102 dim * 1.1 max singular value)
Estimated rank (mag): 99
MAG: rank 99 computed from 102 data channels with 3 projectors
Created an SSP operator (subspace dimension = 4)
Computing rank from covariance with rank={'eeg': 58, 'grad': 203, 'mag': 99, 'meg': 302}
Setting small MEG eigenvalues to zero (without PCA)
Setting small EEG eigenvalues to zero (without PCA)
Created the whitener using a noise covariance matrix with rank 360 (4 small eigenvalues omitted)
使用 ICA 检查伪迹#
在 QC 过程中可以使用独立成分分析(ICA)来识别眨眼和眼动等刻板性伪迹。
就 QC 而言,ICA 通常采用轻量配置(例如较少的成分数或时间抽取)运行,以便快速反馈数据质量,而不是为最终分析进行优化的分解。
利用地形图识别伪迹特有的空间模式(例如眨眼对应的额区模式)。
成分属性查看器用于详细检查单个成分,与分段数据或明确的伪迹评分结合使用时信息量最大。
与 EOG 相关的成分应表现出额区地形图和刻板的时间进程。
只应剔除与伪迹明确相关的成分。
ica = ICA(
n_components=15,
rng=97,
max_iter=50, # just for speed!
)
# Fit ICA using a decimated signal for speed
ica.fit(raw, picks=("meg", "eeg"), decim=10, verbose="error")
# Identify EOG-related components
eog_epochs = create_eog_epochs(raw)
eog_inds, eog_scores = ica.find_bads_eog(eog_epochs)
ica.exclude = eog_inds
report.add_ica(
ica=ica,
inst=epochs,
eog_evoked=eog_epochs.average(),
eog_scores=eog_scores,
title="ICA components (artifact inspection)",
)
Using EOG channel: EOG 061
EOG channel index for this subject is: [375]
Filtering the data to remove DC offset to help distinguish blinks from saccades
Selecting channel EOG 061 for blink detection
Setting up band-pass filter from 1 - 10 Hz
FIR filter parameters
---------------------
Designing a two-pass forward and reverse, zero-phase, non-causal bandpass filter:
- Windowed frequency-domain design (firwin2) method
- Hann window
- Lower passband edge: 1.00
- Lower transition bandwidth: 0.50 Hz (-12 dB cutoff frequency: 0.75 Hz)
- Upper passband edge: 10.00 Hz
- Upper transition bandwidth: 0.50 Hz (-12 dB cutoff frequency: 10.25 Hz)
- Filter length: 1502 samples (10.003 s)
Now detecting blinks and generating corresponding events
Found 10 significant peaks
Number of EOG events detected: 10
Not setting metadata
10 matching events found
No baseline correction applied
Created an SSP operator (subspace dimension = 4)
Using data from preloaded Raw for 10 events and 151 original time points ...
0 bad epochs dropped
Using EOG channel: EOG 061
Applying ICA to Evoked instance
Transforming to ICA space (15 components)
Zeroing out 1 ICA component
Projecting back using 364 PCA components
Applying baseline correction (mode: mean)
Using matplotlib as 2D backend.
Using qt as 2D backend.
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
Using multitaper spectrum estimation with 7 DPSS windows
Not setting metadata
77 matching events found
No baseline correction applied
0 projection items activated
MEG–MRI 配准#
准确的配准(coregistration)对源定位至关重要。
头形点应与 MRI 头皮表面良好对齐。
系统性错位表明数字化或坐标变换存在错误。
trans = sample_dir / "sample_audvis_raw-trans.fif"
report.add_trans(
trans,
info=raw.info,
title="MEG–MRI-head coregistration",
subject=subject,
subjects_dir=subjects_dir,
)
Using outer_skin.surf for head surface.
Getting helmet for system 306m
Channel types:: grad: 203, mag: 102, eeg: 59
Using surface from /home/circleci/mne_data/MNE-sample-data/subjects/sample/bem/sample-head.fif.
MRI 与 BEM 表面#
边界元法(BEM)表面定义了用于正向和逆向求解的头模型。
表面应光滑、闭合且互不相交。
构建不良的表面会严重降低源估计的质量。
report.add_bem(
subject,
subjects_dir=subjects_dir,
title="BEM surfaces",
decim=20, # for speed
)
Using surface: /home/circleci/mne_data/MNE-sample-data/subjects/sample/bem/inner_skull.surf
Using surface: /home/circleci/mne_data/MNE-sample-data/subjects/sample/bem/outer_skull.surf
Using surface: /home/circleci/mne_data/MNE-sample-data/subjects/sample/bem/outer_skin.surf
查看最终报告#
如有需要,可以设置 open_browser=True 让其在浏览器标签页中打开:
report.save("qc_report.html", overwrite=True, open_browser=False)
Saving report to : /home/circleci/project/tutorials/preprocessing/qc_report.html
脚本总运行时间:(0 分 19.154 秒)