Skip to content
睡眠与生理

用 Potato 标注睡眠与生理信号

以 30 秒为一帧为多导睡眠图分期,标记 EEG 伪迹和癫痫发作,或审核 ECG 心搏,再把每位评分者的标签导出为 BIDS events 文件。

Potato 在浏览器中显示多导睡眠图、脑电(EEG)、心电(ECG)和可穿戴设备记录,标注者可以按 30 秒一帧判定睡眠分期,也可以在信号上把伪迹、癫痫发作、心搏和活动片段标为区间和事件。Potato 免费开源,运行在你自己的服务器上,并把每位评分者的标签分开保存,导出为 BIDS events 文件。

睡眠分期为多导睡眠图的每个 30 秒帧(epoch)判定一个分期,即美国睡眠医学会(AASM)定义的 W、N1、N2、N3 和 R(REM)五期之一。在 AASM 的评分者间信度项目中,2,500 多名评分者为同样的 1,800 帧分期,睡眠分期的平均一致率为 82.6%(Rosenberg and Van Hout, 2013)。与多数评分的一致率以 N1 最低,为 63.0%,N3 次之,为 67.4%。因此,报告 N1 或 N3 时长的研究,能从每段记录安排多名评分者、并给出评分者之间的一致性数值中获益。Potato 运行的正是这类研究:把每段记录发给你设定人数的评分者,并把每位评分者的分期存在该评分者的名下。

Potato 中的睡眠与生理任务

下表每一行都使用 Potato 2.13 新增的 time_series 显示类型和 interval_label 方案,链接页面给出了配置。

任务Potato 的做法文档
睡眠分期分帧模式一次显示一个 30 秒帧,按分期键即为该帧标注并跳到下一帧时间序列
标记觉醒或呼吸暂停在同一张图上添加第二个自由模式方案,标注者点击标记事件,拖动标记区间时间序列
标记 EEG 伪迹、癫痫发作和棘波自由模式,每个区间作用于所有通道或某一个通道行,由 channel_scope 设置时间序列
审核 ECG 心搏和节律WFDB 记录从 .hea 头文件打开,.atr 文件中的心搏和节律作为点事件和区间载入,供标注者修正时间序列
标注可穿戴设备记录每个通道一列的 CSV 或 Parquet 文件(例如加速度计各轴),在自由模式下标注时间序列
评分者间一致性所有评分者的逐帧分期写在同一个导出文件中,可用于计算 Cohen's kappa 或 Fleiss' kappa标注者间一致性

一项由三名评分者完成的睡眠分期研究

下面的配置让三名评分者在一个 EEG 通道行、一个 EOG 通道行和一个颏肌 EMG 通道行上,以 30 秒为一帧为每段记录分期。时间序列页面列出了所有选项和条目格式。

yaml
annotation_task_name: "Sleep staging"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
data_files: [data/psg.json]       # each item names its EDF file in "signal"
item_properties: {id_key: id, text_key: note}
user_config:
  allow_all_users: true
 
num_annotators_per_item: 3
 
instance_display:
  fields:
    - key: signal
      type: time_series
      label: "PSG"
      display_options:
        window: 30
        channels:
          - {name: "EEG Fpz-Cz", range: [-120, 120]}
          - {name: "EOG", range: [-150, 150]}
          - "EMG chin"
 
annotation_schemes:
  - annotation_type: interval_label
    name: stage
    description: "Sleep stage of each 30-second epoch"
    signal_field: signal
    mode: epoch
    epoch_length: 30
    pre_annotations: false
    require_all_epochs: true
    label_requirement: {required: true}
    labels:
      - {name: W, key_value: "1"}
      - {name: N1, key_value: "2"}
      - {name: N2, key_value: "3"}
      - {name: N3, key_value: "4"}
      - {name: REM, key_value: "5"}

num_annotators_per_item: 3 把每段记录发给三名评分者。EDF+ 文件中已有的睡眠图(hypnogram)会以虚线显示为起点,pre_annotations: false 隐藏这份睡眠图,使三次评分彼此独立。require_all_epochs 与 label_requirement 同时设置时,每一帧都有分期之前,Next 一直不可用。

导入记录与导出标签

每段记录的文件扩展名决定使用哪个读取器:

  • EDF 和 BDF。 EDF、EDF+、BDF 和 BDF+ 文件无需额外的库即可打开。EDF+ 注释作为预标注载入,preannotation_labels 把“Sleep stage 2”这类睡眠图名称改为方案的标签。
  • WFDB。 PhysioNet 记录从 .hea 文件打开,需要 signals 可选依赖(pip install 'potato-annotation[signals]')。多段记录需要先拼接再载入。
  • CSV 和 Parquet。 一个时间列加上每个通道一列,适合可穿戴设备导出的数据。条目字段中指定的 BIDS events.tsv 会作为预标注载入。

信号文件由 Potato 服务器从媒体目录读取,这个显示类型拒绝 URL。bids_events 导出为每位评分者的每段记录写出一个 events.tsv,包含 BIDS 规范要求的 onset 和 duration 列:

bash
python -m potato.export -c config.yaml -f bids_events -o exports/bids

Potato 的一致性指标不覆盖 interval_label 方案。interval_label 导出写出 intervals.csv,在分帧模式下,这个文件中每位评分者的每一帧各占一行。按 instance_id 和 start 连接这些行,就得到每帧一行、包含每位评分者分期的表格,可用于计算两名评分者的 Cohen's kappa 或更多评分者的 Fleiss' kappa。

与 EDFbrowser、Lunascope 及 MNE-Python 的分工

EDFbrowser 是用于 EDF、EDF+ 和 BDF 文件的免费查看器、注释器和工具箱,带有注释编辑器和睡眠图,适合一名评分者在桌面上逐个处理文件。Lunascope 是用于睡眠信号可视化、注释和分析的桌面应用,支持自动分期和从美国国家睡眠研究资源库(National Sleep Research Resource)导入数据,适合先由模型分期的大型队列。MNE-Python 让 EEG 研究者在 raw.plot() 上拖动添加注释,适合在脚本化分析中完成的标注。对于 ECG,PhysioNet 的 LightWAVE 可以在浏览器中查看和编辑 WFDB 注释。当多名评分者标注同样的记录时,Potato 更合适,因为 Potato 把每段记录分配给设定人数的评分者,并把每位评分者的标签分开导出。

借助编程智能体搭建研究

potato-skill 1.2.0 认得 interval_label 和 time_series 这两个名称,并指导 Claude Code、Codex 或 Cursor 完成研究设计这一侧的工作,例如向评分者问什么、每段记录由几名评分者查看、培训和注意力检查,以及导出。这个技能目前还没有记录信号文件格式、显示选项和 signals 可选依赖。请让智能体参考时间序列页面及其 Markdown 副本 https://www.potatoannotator.com/docs/annotation-types/time-series.md,以了解格式和选项。

常见问题

有没有免费软件可以按 30 秒一帧为睡眠分期?

Potato 是免费的开源软件(GPL-3.0-or-later),在 interval_label 方案的分帧模式下,一次一个 30 秒帧地为多导睡眠图分期。按分期键即为当前帧标注并跳到下一帧,[ 和 ] 只移动不标注。图下方的条带按分期为每个已评分的帧着色。

能否只在部分 EEG 通道上标记癫痫发作或伪迹?

能。设置 channel_scope: channel 时,区间作用于拖动开始所在的通道行;设置 channel_scope: either 时,图上方的开关用来在某一个通道行和所有通道之间选择。电极伪迹可以只落在一个通道行上,而全面性癫痫发作横跨所有通道。存储的区间记录通道名称,所有通道则记为 null,导出中的 channel 列指明同一个通道行。

评分者能否从已有的睡眠图出发修正分期?

能。EDF+ 文件中的分期注释会作为虚线的起始睡眠图载入,preannotation_labels 把“Sleep stage 2”这类名称映射到方案的标签。评分者可以保留、编辑或丢弃这些起始分期,未被改动的分期导出时 source 为 file。

如何把人工 EEG 注释保存到文件?

Potato 把每位标注者的标签存储在 Potato 服务器上,python -m potato.export 把这些标签写入 intervals.csv,或为每位标注者的每段记录写出一个 BIDS events.tsv。intervals.csv 的每一行记录标注者、条目、标签、起止时间和通道。

延伸阅读

参考文献

  1. Rosenberg and Van Hout (2013). The American Academy of Sleep Medicine Inter-scorer Reliability Program: Sleep Stage Scoring. Journal of Clinical Sleep Medicine 9(1). https://doi.org/10.5664/jcsm.2350

从这里开始

其他领域

全部应用场景