非官方中文翻译 本页译自 MNE-Python 官方文档: 查看英文原文 ↗。 文档版权归 MNE Developers 所有(BSD-3-Clause)。

使用 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 秒)

由 Sphinx-Gallery 生成的示例库