信息速览
VitalDB Arrhythmia 不是一个新采集的数据库,而是 VitalDB 主库上长出来的一层标注。主库把六千多例非心脏手术的术中监护信号原样存了下来,这一层则在其中四百多例里挑出心电图,由麻醉科医师一个搏一个搏地判读,标出哪个搏是正常的、哪个是室早、哪个是房颤中的一次传导。它回答的是「手术台上那几分钟的心跳,到底属于什么」这个问题。
它的价值集中在一件别处很难买到的事上:术中场景的、逐搏的、经过多名麻醉科医师交叉复核的节律判读。公开的心电数据库大多来自动态心电图或重症监护,术中记录稀少;而术中恰恰是心律失常高发、干扰最多、算法最容易失效的环境。把这类记录整理成可训练、可评测的形态,是这个数据集存在的理由。
它同时有三条硬边界,一开始就要说清楚:包内没有波形,只有标注;标注只覆盖每例约二十分钟的候选段,不是整台手术;语料只有 II 导联一条通道。任何把它当全程连续记录、或多导联语料、或心律失常发生率调查的用法,都会在第一步就错。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 中文名 | VitalDB 心律失常数据库(术中版本) |
| 官方全名 | VitalDB Arrhythmia Database |
| 建设方 | 首尔国立大学医院麻醉与疼痛医学系 |
| 发布平台 | PhysioNet(开放获取) |
| 版本与日期 | 1.0.0,2026 年 2 月 26 日 |
| DOI | 10.13026/axd6-wm13 |
| 病例数 | 482 例非心脏手术 |
| 标注总时长 | 734,528 秒(约二百小时) |
| 逐搏标注数 | 逾六十六万个心搏 |
| 搏级类别 | 4 类(正常、室上性、室性、无法归类) |
| 节律类别 | 10 类,另加噪声与无法归类标记 |
| 导联与采样 | II 导联单通道,标注按 500 Hz 时间轴 |
| 复核方式 | 五名麻醉科医师,每段至少两人独立判读 |
| 包内内容 | 标注 CSV、元数据、许可与校验文件 |
| 包内是否含波形 | 不含,须按 case_id 回主库取 |
| 许可 | CC BY 4.0 |
| 最典型的误用 | 把候选段标注当全程节律发生率 |
§1 它要解决的具体麻烦
1.1 术中这段心电图,公开语料里几乎没有
心电数据库并不稀缺。动态心电图有 MIT-BIH 系列,重症监护有 MIMIC 波形库,可穿戴有各种单导联长程记录,竞赛型语料更是年年更新。但把「手术进行中」这四个字单独拎出来,公开语料立刻稀疏下来。
原因不难理解。术中监护的原始信号归医院所有,采集涉及麻醉机、监护仪、输注泵多台设备的同步,脱标识与伦理审批都比常规体检数据复杂。愿意把整台手术的多参数波形开放出来的团队,全世界屈指可数,VitalDB 是其中最知名的一个。而在这批已经开放的波形里,标注层几乎是空白——波形有了,但没人告诉你哪一段是房颤、哪一段只是肌电干扰。
术中环境又恰恰是心律失常的高发场景。手术刺激、麻醉药物、通气变化、容量波动、电解质偏移,任何一种都能在几分钟内把窦性心律改写成别的形态。这种「短时间内节律反复切换」的形态,与动态心电图里那种以小时计的稳定节律完全不同。用门诊语料训练的检测器搬到手术台上,会同时犯两类错:把麻醉诱导期的快速心率当成室上速,把电刀干扰当成室颤。
这个数据集补的正是这段空白。它没有重新采集,而是从现成的 VitalDB 里挑出心电部分,补上人工判读。这是一个成本极低、收益很高的做法:波形已经在那儿了,缺的是有人愿意花时间把它读一遍。
1.2 三条常见的错误期待
第一条期待:把它当成「术中发生率的流行病学样本」。四百多例手术里有多少例出现房颤,看起来像是一个可以引用的数字。但抽样的方式决定了它不能这么用。进入标注集的前提是「被算法判定为存在异常」,正常手术的比例被系统性压低了。拿它的病例构成去估计术中房颤的患病率,会得到远高于真实值的结论。
第二条期待:把它当成「一个独立的数据集」。它不是。它更像一本贴在墙上的批注册,真正的书在隔壁。所有波形都要回主库取,标注文件里的时间戳只有配上同一例的波形才有意义。把它单独下载下来,等于拿到了一堆没有正文的页码。
第三条期待:把它当成「全导联的形态学语料」。术中监护通常只接 II 导联或 V5 导联,这个数据集用的是 II 导联。单导联意味着很多形态学特征——比如束支传导阻滞的 V1 形态、室早的起源定位——根本无法从这份语料里学。它是一个节律识别的语料,不是一个形态学诊断的语料。
1.3 它能给到的与给不到的
下表左列写的是具体的需求,不是功能名词。凡标「不够」的行,都是它明确做不到的事。
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 训练一个术中室早检测器 | 逐搏四分类标签,含室性搏 | 够,但需回主库配波形 |
| 识别术中房颤片段 | 十类节律标签中的房颤类 | 够用于训练,评测需注意抽样偏倚 |
| 判读麻醉诱导期的心率骤升 | 候选段内的节律标签与搏标签 | 部分够,诱导期是否入选取决于筛选 |
| 做多导联心电形态分析 | 仅 II 导联 | 不够,需另找多导联语料 |
| 统计术中各类心律失常发生率 | 候选段抽样的病例 | 不够,抽样方式不支持分母 |
| 评估信号质量算法 | 低质量区间起止标记与噪声段 | 够用于二分类,但只区分粗粒度 |
| 研究房室传导阻滞 | 十类中的房室阻滞类 | 够,但该类样本很少 |
| 做跨中心外部验证 | 单中心数据 | 不够,需另找队列 |
| 训练新生儿或儿科模型 | 成人手术患者 | 不够,人群完全不同 |
| 对齐血压、血氧做多模态 | 主库有同步信号,标注在同一时间轴 | 够,是这份语料少见的加分项 |
| 复现论文里的逐搏分类基准 | 官方给出标注与用法说明 | 够,需自行划分训练与测试 |
| 做心脏手术人群的分析 | 只含非心脏手术 | 不够,完全不覆盖 |
1.4 你的处境与它能帮到的事
同一份标注,不同处境的人该拿它做什么完全不同。下表左列是处境,右列是下一步动作,中间才是标注本身能提供的部分。
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 你在做术中监护设备的算法预研 | 提供带人工判读的术中单导联语料 | 先按 case_id 批量取波形,再对齐标注时间轴 |
| 你在写围术期心律失常的论文 | 提供可复算的标注与元数据 | 明确说明抽样方式,不要用它算发生率 |
| 你在做心电大模型的预训练 | 提供与门诊语料风格不同的术中片段 | 只把它当微调或评测集,不要当预训练主体 |
| 你是麻醉科医生,想核对某个判读 | 提供他人的独立判读作为参照 | 读官方对信号质量的定义,再比对分歧 |
| 你在审核一份算法的临床声明 | 提供术中场景的证据 | 要求补充多中心验证,单靠此集不足 |
| 你在做信号质量与伪差抑制 | 提供噪声段与低质量区间的标记 | 用噪声段做负例,但注意它与正常搏不是一类 |
| 你在做多模态融合研究 | 同一时间轴上有血压、血氧等信号 | 回主库取同步通道,注意采样率与起点 |
| 你只想找一份心电语料做入门 | 提供结构清晰的 CSV | 先读 §5 的最小流程,避免空跑 |
1.5 一句话判断
它是 VitalDB 主库上的一层人工批注:波形不在这儿,读法在这儿;能教你认识术中节律,但不能替你回答发生率。
1.6 不适合谁:四条边界
第一条边界:需要全程连续记录的研究。标注只覆盖每例约二十分钟的候选段,其余时间既没有搏标签也没有节律标签。用它做「整台手术的心律负荷」这类指标,分母根本不存在。
第二条边界:需要多导联的形态学诊断。只有一条 II 导联,束支阻滞的分支定位、室早的起源定位、缺血性 ST 段改变的空间分布,这些都做不到。单导联能回答节律问题,不能回答空间问题。
第三条边界:需要流行病学分母的人群研究。进入标注集的门槛是「算法筛出可能存在异常」,这是病例富集抽样的典型形态。任何以它为分母的发生率、患病率、风险比,都会被抽样的选择性污染。
第四条边界:需要跨机构泛化的验证。全部病例来自一家医院、一个时期、一套设备。术中监护的设备差异、贴片位置、滤波器设置都会改变波形形态,单中心语料上的高分不能直接外推。
§2 数据构成与规格
2.1 两层结构:波形在主库,标注在这一层
理解这份数据的第一件事,是把「数据」与「标注」两个词分开。VitalDB 主库存的是原始多参数波形,每一例对应一个二进制病例文件,里面按轨道存着心电、有创血压、血氧容积波、二氧化碳等信号,波形采样率因通道而异,心电常见 500 Hz。这一层数据体量巨大,全库接近百 GB 量级。
VitalDB Arrhythmia 存的是另一类东西:每例一份 CSV,逐行记下第几秒出现了一个心搏、这个搏属于哪一类、它所在的整段属于哪种节律、这一段信号质量如何。整包压缩后只有几 MB,正是因为它不含任何波形。
| 层 | 内容 | 存放位置 | 体量 | 谁维护 |
|---|---|---|---|---|
| 主库波形层 | 多参数原始波形与数值轨道 | VitalDB 主库 | 近百 GB | VitalDB 团队 |
| 主库临床层 | 围术期临床信息与实验室结果 | 主库附带 CSV | 数十 MB | VitalDB 团队 |
| 标注层 | 逐搏分类与节律判读 | 本包 Annotation_Files | 数 MB | 本项目团队 |
| 元数据层 | 每例的分析时长、搏数、节律类别 | 本包 metadata.csv | 数百 KB | 本项目团队 |
这个两层结构带来一个直接推论:本包的下载成本可以忽略,真正的成本在波形。四百多例的术中信号即便只取单通道,也需要相当规模的传输与存储;如果还要同步取血压与血氧做多模态,体量会进一步上升。做规划时要按主库的体量算,而不是按标注包的体量算。
2.2 字段与记录的完整字典
元数据表一例一行,标注文件一例一份、一行一个心搏。两边的字段加起来,构成这份语料的全部结构。下表的类型与含义依据官方说明与随包示例整理。
| 字段 | 所在文件 | 类型 | 含义与用法 | 需要留意的地方 |
|---|---|---|---|---|
| case_id | metadata.csv、标注文件名 | 整数 | 主库中的病例编号,对齐波形的唯一键 | 与主库编号一一对应,不可重编 |
| analyzed_duration_sec | metadata.csv | 数值 | 该例被标注覆盖的时长(秒) | 不是整台手术时长 |
| total_beats | metadata.csv | 整数 | 该例被标注的搏总数 | 与文件行数应基本一致 |
| rhythm_classes | metadata.csv | 文本列表 | 该例出现过的节律类别 | 多类别以分隔符并列 |
| time_second | 标注文件 | 数值 | R 波时刻,以记录起点为零点 | 与主库时间轴同源,可直接对上 |
| beat_type | 标注文件 | 文本 | 搏级四分类 | 取值见 2.3 的分类表 |
| rhythm_label | 标注文件 | 文本 | 该搏所属片段的节律类别 | 相邻搏可共享同一节律 |
| bad_signal_quality | 标注文件 | 布尔 | 该搏是否落在低质量片段 | 置真时波形仍可见 QRS |
| bad_signal_quality_label | 标注文件 | 文本 | 低质量片段的起止标记 | 非边界行为空 |
| 文件命名 | 标注文件 | 文本 | 固定为标注文件名前缀加 case_id | 批量遍历时按文件名取号最稳 |
字段表里最容易出错的三处:analyzed_duration_sec 容易被误读成手术时长;bad_signal_quality 为真的搏并非不可用,只是 P 波与 T 波被掩盖;bad_signal_quality_label 只在片段边界上有值,做区间重建时必须靠它配对起止,不能靠布尔列的跳变简单推断。
2.3 一套双层标签:搏级四类,节律十类
标签体系是两个粒度叠在一起。细的一层是搏,回答「这一次心室除极来自哪里」;粗的一层是节律,回答「这一段整体是什么心律」。两层不是冗余关系,因为同一个节律下可以有不同来源的搏:房颤段落里,绝大多数搏是室上性下传,偶尔会插进一个室性早搏。
| 粒度 | 类别数 | 类别含义 | 典型用途 |
|---|---|---|---|
| 搏级 | 4 | 正常搏、室上性异位搏、室性异位搏、无法归类 | 训练搏分类器、计算异位负荷 |
| 节律级 | 10 | 窦性心律、房颤、室上性快速性心律失常、室性快速性心律失常、成串室性异位、成串房性异位、窦房结功能不全、房室阻滞、游走性心房起搏或多源性房性心律、噪声 | 训练节律分段、做片段级评测 |
| 附加标记 | 1 | 无法归类节律 | 极少数疑难段落的兜底 |
十类节律里,最常见的是窦性心律,这也符合直觉:即使是被筛出来的异常病例,大部分被标注的时段仍是窦性。房颤类覆盖的病例数排在前面,这与术中房颤的实际频度一致——它是最容易被算法抓到、也最容易被医师确认的异常。房室阻滞类的病例数最少,这是术中相对少见、且往往与麻醉深度或迷走张力相关的一类。
噪声被单列为一个节律类别,这一点值得强调。被标为噪声的片段,伪差严重到连 QRS 都无法辨认,因此这些片段内部不产生任何搏级标注。这意味着标注文件的行数与「该例被标注的总时长」并不严格成比例——噪声越长,缺失的搏级行越多。做训练集统计时,如果只数行数,会低估实际覆盖的时间跨度。
2.4 一条标注记录的完整解剖
拿一例真实标注文件的头部做样本,可以看到两个粒度是怎么并排放在同一行里的。下面这份节选保留列名与字段形态,便于核对解析器。
time_second,beat_type,rhythm_label,bad_signal_quality,False,bad_signal_quality_label
0.412,Normal,Sinus Rhythm,False,
0.988,Normal,Sinus Rhythm,False,
1.566,Normal,Sinus Rhythm,False,
2.140,Supraventricular,Atrial Fibrillation,False,
2.718,Normal,Atrial Fibrillation,False,
3.296,Ventricular,Atrial Fibrillation,False,
3.870,Normal,Atrial Fibrillation,False,
4.452,Unclassifiable,Noise,False,
4.960,Normal,Sinus Rhythm,True,Start1
5.560,Normal,Sinus Rhythm,True,
6.130,Normal,Sinus Rhythm,True,End1
#-- 节选:列名以官方随包文件为准,行内容为结构示意,时间戳与类别组合用于说明两个粒度的并置方式
这份节选里藏着三件事。第一,band_label 与 beat_type 会同时出现在一行,一个搏的标签是「室性」,它所在片段的标签可能是「房颤」,两者并不矛盾。第二,bad_signal_quality 为真的连续若干行,用 Start1 与 End1 标出边界,中间的布尔值重复出现。第三,被标为噪声的那一行,搏类型填的是无法归类,说明噪声段的处理是「整行兜底」而不是「整段删除」。
用代码把一例读进来,最容易犯的错是把时间当作毫秒或是把布尔列当字符串比较。下面这段是最小可运行的正确读法。
import pandas as pd
#-- 读入一例标注,时间列按浮点解析,布尔列按真值映射
ann = pd.read_csv("Annotation_Files/Annotation_file_337.csv")
ann["bad"] = ann["bad_signal_quality"].astype(str).str.strip().str.lower().eq("true")
#-- 搏级:统计四类搏的数量
beat_counts = ann["beat_type"].value_counts()
print(beat_counts)
#-- 节律级:把同一节律的相邻行压成区间
ann = ann.sort_values("time_second").reset_index(drop=True)
change = ann["rhythm_label"].ne(ann["rhythm_label"].shift())
starts = ann.loc[change, ["time_second", "rhythm_label"]].reset_index(drop=True)
durations = ann["time_second"].diff().shift(-1).fillna(0)
print(starts.head(10))
这段代码的第二个用途更有价值:把逐搏标签压成节律区间,是做节律分段任务的起点。压缩规则很简单,相邻搏的节律标签相同就合并,不同就断开。压完之后,一例二十分钟的记录通常会变成几十个区间,而不是几千个搏。
2.5 与主库字段的对照
把这份语料与主库放在一起看,才能判断它在整个 VitalDB 体系里的位置。两者共享同一个病例编号,共享同一条时间轴,但记录的抽象层级完全不同。
| 对照项 | VitalDB 主库 | VitalDB Arrhythmia |
|---|---|---|
| 记录的物理量 | 原始电压或压力值 | 搏与节律的判读结论 |
| 数据形态 | 二进制病例文件 | CSV 文本 |
| 通道数 | 每例十余至数十轨 | 单通道(II 导联) |
| 时间粒度 | 采样点级 | 搏级 |
| 覆盖时长 | 整台手术 | 每例约二十分钟候选段 |
| 体积量级 | 近百 GB | 数 MB |
| 是否需要人工判读 | 否 | 是,全部 |
| 主要用途 | 信号建模、多模态 | 节律识别、搏分类 |
这张表最该读出的一句话是:主库给的是「记录」,这一层给的是「解读」。记录可以重新解读,解读不能反过来生出记录。所以任何以这一层为主的分析,最终都要下沉到主库去取波形;而任何以主库为主的分析,都可以把这一层当作现成的、免费的标注补充。
§3 身份层:它到底是什么
3.1 一个派生层,不是一次独立采集
严格说,它不是「数据集」,而是「数据集的一个标注视图」。官方的做法很清楚:从 VitalDB 的公开病例里筛选,取出心电图,补上人工判读,把判读结果单独发布。波形留在原处,标注另立门户,两者用病例编号连接。
这个身份带来一个不太直观的后果:它的版本独立性是有限的。标注可以单独升版,但它依赖的波形在主库那边是另一个版本号。如果主库将来修订了某例波形的时间轴或采样率,标注层必须跟着调整,否则时间戳就对不上。使用者在引用时应当同时记下两个版本号,而不是只记本包的。
| 身份维度 | 具体表述 | 对使用者的含义 |
|---|---|---|
| 法律地位 | PhysioNet 上的开放数据库,独立 DOI | 可单独引用,但要并列引用主库 |
| 结构地位 | 主库的标注派生层 | 波形必须回主库取 |
| 采集地位 | 未新采集,全部复用主库 | 采集条件与主库完全同一套 |
| 判读地位 | 五名麻醉科医师人工复核 | 判读质量高,但判读标准是麻醉视角 |
| 时间地位 | 主库批次(2016 至 2017 年手术) | 不代表当下设备与流程 |
| 语言地位 | 英文标签与英文元数据 | 中文使用需自建映射表 |
3.2 麻醉科的判读视角与心内科不完全相同
这一点容易被忽略,但它决定了标签的语义。判读人是麻醉科医师,不是心内科电生理医师。他们看心电的第一需求是「这台手术能不能继续、要不要处理」,而不是「这个节律的精确电生理机制是什么」。
具体表现有两处。第一,节律分类的粒度偏粗:室上性快速性心律失常被合成一类,不细分房速、房扑、房室结折返;成串室性异位与室性快速性心律失常分开,但不细究形态。第二,对临床意义明确的类型更敏感:房颤、室性早搏成串、房室阻滞、窦房结功能不全,这几类都是直接影响术中决策的。
这种视角不是缺陷。对绝大多数术中监护算法的目标来说,「这一段要不要报警」比「这一段属于哪一种折返机制」更重要。但如果研究目的是电生理机制分类,这套标签就不够细,需要另找心内科标注语料。
3.3 与常见心电语料的身份差异
把这份语料放进公开心电数据库的谱系里,它的身份独特性就更清楚了。
| 语料 | 场景 | 导联 | 标注粒度 | 与本文的关系 |
|---|---|---|---|---|
| MIT-BIH 心律失常库 | 动态心电图 | 双导联 | 搏级 | 搏分类的传统基准,场景不同 |
| 各类重症监护波形库 | ICU | 多导联 | 部分搏级 | 场景邻近,但非术中 |
| 竞赛型十二导联语料 | 门诊或体检 | 十二导联 | 记录级或搏级 | 导联丰富,场景不同 |
| 可穿戴单导联语料 | 居家 | 单导联 | 记录级 | 干扰类型不同 |
| VitalDB 主库 | 术中 | 多轨 | 无标注 | 本文的波形来源 |
| 本文语料 | 术中 | 单导联 | 搏级加节律级 | 术中场景里标注最细的一支 |
这张表要说明的是:它的独特性不在规模,也不在标注精度,而在「术中」与「逐搏」这两个条件的交集。单看任何一条,都有更强的语料;两条叠在一起,可选项就很少了。
3.4 谁在维护,维护到什么程度
发布方是首尔国立大学医院麻醉与疼痛医学系的团队,也就是 VitalDB 的原班人马。这个事实很重要:标注层与波形层出自同一团队,意味着两边的时间轴、病例编号、质量约定是内部一致的,不需要外部再做一次对齐谈判。
维护模式是学术项目的典型形态:以论文与版本发布为主要里程碑,随包提供用法说明与代码仓库,遇到问题通过仓库的议题渠道反馈。它不是一个有服务等级承诺的产品,也不承诺按固定节奏增量。使用者在规划长期项目时,应当把「不再更新」当作可能的默认状态来设计,而不是假设它会持续扩充。
§4 质量层:它凭什么可信
4.1 三重把关:算法筛、医师判、两人交叉
这套标注的可信度,来自一道三段的流水线,每一段解决一个不同的问题。
第一段是算法筛选。要在六百多万秒的原始心电里逐搏人工判读,成本不可承受。团队先训练了一个搏分类器,用它扫过全部候选病例,把「连续异常搏」「R-R 间期高度不稳」「成串异位」这类形态挑出来,形成候选段。这一步的作用不是判读,而是把人工投入压缩到可行范围。
第二段是医师判读。候选段交给麻醉科医师,逐搏给四类标签,逐段给节律标签。这一步是真正的判读,算法的输出在这里只是线索,不是结论。
第三段是交叉复核。每一段至少由两名医师独立看过,分歧之处由五人小组协商达成共识。官方报告的整体一致性是相当高的,说明判读标准在团队内部被统一得不错。
| 环节 | 谁来做 | 解决什么 | 留下的偏差 |
|---|---|---|---|
| 候选筛选 | 深度学习搏分类器 | 把人工量压到可行 | 算法漏掉的异常不进标注集 |
| 逐搏判读 | 麻醉科医师 | 给出搏与节律标签 | 判读粒度受临床需求约束 |
| 交叉复核 | 五名医师中的至少两人 | 压低个体判读差异 | 共识过程不公开逐例细节 |
| 质量标记 | 判读人 | 标出低质量与噪声段 | 噪声段无搏级标签 |
第一行的偏差最容易被忽视。筛选器决定了什么能进入标注集,而筛选器的召回率不是百分之百。它漏掉的异常段,在这份语料里表现为「不存在」,而不是「被标为正常」。所以这份语料对「算法漏检率」的估计天然是乐观的:它是在算法自己挑出来的样本上评估算法。
4.2 信号质量标注为什么重要
术中信号的干扰源比门诊多得多。电刀的高频干扰、体位变化引起的基线漂移、电极脱落造成的饱和、肌电与呼吸的叠加,都会让一段本来正常的心电变得难以判读。团队把这部分单独处理,分成两级。
第一级是低信号质量。特征是 QRS 仍可辨认,但 P 波与 T 波被噪声掩盖,导致无法可靠判断房室关系与复极。这类片段仍给搏级标签,同时置 bad_signal_quality 为真,并用起止标记圈出区间。它的用途是让使用者在训练时可以选择性地降权或剔除这些搏,而不是把它们与干净搏混为一谈。
第二级是噪声。伪差严重到 QRS 都无法辨认,整段只给噪声标签,不产生任何搏级行。这类片段在训练中的价值不是当负例,而是当「不可判读」的独立类别——把它当正常搏喂给模型,会教模型把伪差学成心律。
| 质量等级 | 判据 | 是否有搏级标签 | 训练时怎么用 |
|---|---|---|---|
| 正常 | QRS、P 波、T 波均可辨认 | 有 | 正常参与训练 |
| 低信号质量 | QRS 可辨,P 波或 T 波被掩盖 | 有 | 降权或单独建模 |
| 噪声 | QRS 无法辨认 | 无 | 单列一类,不作负例 |
| 无法归类的搏 | QRS 可见但类型不明 | 有 | 单列一类,通常样本极少 |
第三、四两类的存在,说明这套标注没有把不确定硬塞进某一个确定类别。这在标注实践中是一个好习惯:宁可留一个兜底类,也不逼判读人在信息不足时做假选择。
4.3 一致性的口径怎么读
官方给出的整体一致性指标是一个 kappa 值,并附了标准差。这两件事要一起读,不能只读前一个。
kappa 高说明两名判读人在同一段上给出相同标签的概率显著高于随机,这是判读可信的基础证据。但标准差的存在提醒:分歧在多数段上很小,在少数段上可能很大。哪些段最容易分歧?从心电判读的常识看,是低信号质量段、成串异位的起始与终止边界、以及游走性心房起搏与多源性房性心律这类的区分。这些段恰好也是最难自动判读的段。
对使用者的含义是:不要把整体一致性当作「所有类别同等可靠」。整体数字是加权平均,少数类的样本少、分歧大,其可靠度显著低于常见类。做少数类的检测任务时,应当先看那一类的样本量与判读难度,再决定评测设计。
| 判读维度 | 一致性表现 | 使用含义 |
|---|---|---|
| 搏级四分类 | 高,正常与室性区分清楚 | 搏分类任务可直接用 |
| 常见节律(窦性、房颤) | 高 | 主要节律分段可靠 |
| 少见节律(房室阻滞等) | 未单独报告 | 样本少,评测需谨慎 |
| 片段边界位置 | 未单独报告 | 边界误差会影响分段指标 |
| 低质量区间 | 未单独报告 | 与质量相关的分析需人工复核 |
4.4 案例:病例 337 的一分钟
用一例真实编号把上面的抽象讲透。病例 337 出现在官方用法说明的代码示例里,是这套语料最常被拿来演示的一例。它的标注文件里有一段典型的术中过程:约十几秒的室性异位连发,其间穿插若干正常搏,随后被一段低信号质量区间隔开,再回到窦性心律。
如果只看搏级统计,这一段会被记成「若干室性搏」。但把节律标签压成区间之后,形状完全变了:那一段是一整个「成串室性异位」区间,而不是零散的室早。前者在临床上意味着需要关注血流动力学,后者通常只是观察。同一个数值,两种读法,差别在于是否使用了节律层。
import pandas as pd
case_id = 337
ann = pd.read_csv(f"Annotation_Files/Annotation_file_{case_id}.csv")
ann = ann.sort_values("time_second").reset_index(drop=True)
#-- 只看前 60 秒,看两个粒度如何错位
head = ann[ann["time_second"] <= 60]
print("搏数", len(head))
print("搏类型构成", head["beat_type"].value_counts().to_dict())
print("节律构成", head["rhythm_label"].value_counts().to_dict())
#-- 把节律压成区间,边界取该段第一搏的时刻
chg = head["rhythm_label"].ne(head["rhythm_label"].shift())
for _, r in head.loc[chg, ["time_second", "rhythm_label"]].iterrows():
print(round(r["time_second"], 2), r["rhythm_label"])
这段代码的产出会让第一次接触这套标签的人有点意外:搏级构成里室性搏占的比例,与节律级里「成串室性异位」所占的时间比例,往往不成正比。原因是节律层记录的是「这一段整体被判定为什么」,一段十秒的成串异位里可能只有六个室性搏,但它作为节律事件占用了十秒。
这个案例的价值不在数字,而在提醒:§4.4 的案例说明的是两个粒度不可互换。做搏分类任务,用搏标签;做节律分段任务,用节律标签;做临床事件统计,才把两者结合起来。混用会让同一段信号产生两种互相矛盾的「发生率」。这个案例在 §5 与 §7 还会再出现两次,分别用来说明取数流程与质量评估的落点。
§5 取数层:三条路,各有各的取舍
5.1 路径一:直接下载标注包,几 MB 就能开始
最省事的起点是下载标注包本身。包体很小,包含元数据、四百多份标注文件、许可与校验文件。解压后不需要任何数据库,用任意表格工具或几行代码就能读。
这条路的产物是「答案」,不是「题目」。你能知道每例第几秒出现了什么搏、属于什么节律,但你手上没有那一段波形,也就无法验证判读、无法训练模型、无法画图。它适合的场景是:做标签体系的探索、统计标注结构、检查某一类的分布是否符合预期、以及在看波形之前先确认这一例是否值得下载。
| 优点 | 缺点 | 适合谁 |
|---|---|---|
| 体积极小,秒级下载 | 无波形,不能训练 | 先探路的人 |
| 格式简单,CSV 直读 | 时间戳离开波形无意义 | 做标签研究的人 |
| 含元数据,可先筛病例 | 不含采集通道信息 | 需要选例的人 |
| 官方校验文件齐全 | 无内置划分与基线 | 做数据核对的人 |
5.2 路径二:用 vitaldb 库按号取波形
真正的取数入口是主库的 Python 库。装上之后,一行代码就能按病例编号取回指定的轨道,并可以指定重采样间隔。标注文件的时间戳与波形的时间轴同源,因此只要两边都用记录起点为零点,就不需要额外对齐。
#-- 安装官方客户端
pip install vitaldb
#-- 取回与本标注包对应的四十多例样本的 II 导联波形(示例取前若干例)
python3.11 - <<'PY'
import vitaldb
for cid in [337, 338, 340]:
vals = vitaldb.load_case(cid, ['SNUADC/ECG_II'], 1/500)
print(cid, None if vals is None else vals.shape)
PY
import numpy as np
import pandas as pd
import vitaldb
FS = 500 #-- 与标注时间轴一致的目标采样率
case_id = 337
ann = pd.read_csv(f"Annotation_Files/Annotation_file_{case_id}.csv")
#-- 取 II 导联,按 500 Hz 重采样
sig = vitaldb.load_case(case_id, ["SNUADC/ECG_II"], 1 / FS)
sig = np.asarray(sig, dtype=float).reshape(-1)
print("样本数", sig.size, "时长秒", round(sig.size / FS, 1))
#-- 取标注里的一个搏,反查它附近的波形
t = float(ann.iloc[10]["time_second"])
i = int(round(t * FS))
print("时刻", t, "附近电压", np.round(sig[max(i - 3, 0):i + 4], 3))
这段代码的关键是采样率。标注给的是秒,波形给的是采样点,两者之间的换算系数必须与取波形时指定的间隔严格一致。指定 500 Hz 却按 250 Hz 去算索引,会让每个搏的定位漂移一半,看起来像是标注整体错位,实际是换算错了。
5.3 路径三:批量取、按需缓存
做训练集时,逐例下载的瓶颈不在网络,而在重复取。同一例可能被反复读多次,每次都从远端拉一遍,既慢又不稳定。常规做法是本地建一个缓存目录,按病例编号存一份重采样后的数组,取之前先查本地。
from pathlib import Path
import numpy as np
import pandas as pd
import vitaldb
CACHE = Path("cache_ecg2")
CACHE.mkdir(exist_ok=True)
FS = 500
def load_ecg(case_id: int) -> np.ndarray:
"""取一例 II 导联,命中缓存则直接读盘。"""
p = CACHE / f"{case_id}.npy"
if p.exists():
return np.load(p)
vals = vitaldb.load_case(case_id, ["SNUADC/ECG_II"], 1 / FS)
if vals is None:
raise RuntimeError(f"该例主库无 II 导联:{case_id}")
arr = np.asarray(vals, dtype=np.float32).reshape(-1)
np.save(p, arr)
return arr
meta = pd.read_csv("metadata.csv")
ok, miss = 0, []
for cid in meta["case_id"].head(20):
try:
load_ecg(int(cid))
ok += 1
except Exception:
miss.append(int(cid))
print("成功", ok, "缺失", miss)
第三行的 raise 不是多余的保护。主库中并非每一例都完整记录了 II 导联,某些病例的该轨道可能缺失或被丢弃。批量处理时必须显式处理这种情况,否则某几个病例的失败会静默地让训练集少了几例,而你在很久之后才发现。
5.4 三条路的对照
| 维度 | 标注包 | 单例取波形 | 批量加缓存 |
|---|---|---|---|
| 下载量 | 数 MB | 每例数 MB | 每例数 MB,只下一次 |
| 是否需要主库 | 否 | 是 | 是 |
| 能否训练 | 否 | 是 | 是 |
| 实现复杂度 | 极低 | 低 | 中 |
| 适合阶段 | 探路 | 调试 | 建模 |
| 主要坑 | 无波形 | 采样率换算 | 轨道缺失与磁盘占用 |
5.5 时间轴对齐的三个细节
第一,零点。标注的 time_second 以该例记录起点为零点。主库取回的波形起点与标注起点一致,前提是取的是同一条轨道、同一段记录。若使用者对波形做过裁剪或高通滤波前移,零点会偏移,必须补偿。
第二,采样。指定 500 Hz 取波形时,库会在内部做重采样。重采样引入的相位延迟取决于滤波器设计,量级通常在若干毫秒。对搏级任务这是可接受的,但对 P 波与 QRS 起点的精确时刻建模,若干毫秒已经足以影响结果。
第三,缺测。主库的轨道并非处处有值,某些时段可能因为设备断开而缺失。取回的数组在这些位置可能是零或空值。用它们训练前应当先做一次有效性检查,把整段为零的区间剔除。
5.6 不要从网页抓
PhysioNet 的文件页提供逐文件下载,也支持批量打包。程序化取数的正确方式是直接走文件目录的静态链接或官方客户端,而不是解析文件列表页的 HTML。文件列表页的结构会随平台改版变动,按页面结构写的爬虫在改版后会静默失效,取到的可能是错误页而不是数据。官方给出的批量入口与校验文件足以完成下载与完整性核对,没有必要绕。
§6 与库内条目的关系
6.1 关系图谱
这份语料与库内几条记录的关系,可以用一张图说清。核心是 VitalDB 主库,本文是它的一条分支;旁边是从术中信号衍生出的其他研究方向,如低血压预测与无创血压估计;再远处是通用的心电语料,它们与本文共享场景的一部分,但不共享病例。
| 库内记录 | 与本文的关系 | 能否直接连接 | 连接键 |
|---|---|---|---|
| VitalDB 主库 | 父子:波形在彼,标注在此 | 必须连接才能训练 | case_id |
| 术中低血压预测类记录 | 兄弟:同一批波形,不同任务 | 可,共享病例 | case_id 与时间轴 |
| 通用心律失常语料 | 场景互补,人群不同 | 不可直接连 | 无,仅概念层对齐 |
| 重症监护波形库 | 场景邻近,标注体系不同 | 不可直接连 | 无 |
| 可穿戴心电语料 | 干扰类型不同 | 不可直接连 | 无 |
| 麻醉深度类记录 | 同一主库的不同信号 | 可,共享病例 | case_id |
这张表最该读出的一句话是:它与主库的关系是「必须连接」,与其余记录的关系是「只能对照」。前者是物理同源,后者是概念相邻。把两种关系混为一谈,就会写出「可以合并训练」这种错误的结论。
6.2 检索路径
在库里找与它相关的内容,有三条入口。按来源找:所属机构是首尔国立大学医院麻醉与疼痛医学系。按场景找:标签为生理信号且关键词含术中或围术期。按数据形态找:标注为人工标注、内容为时序信号。
| 检索意图 | 关键词 | 预期命中 | 说明 |
|---|---|---|---|
| 术中信号总库 | VitalDB、术中、生命体征 | 主库记录 | 波形来源 |
| 术中心电标注 | 心律失常、逐搏、ECG | 本文 | 标注来源 |
| 术中其他任务 | 低血压、无创血压、心输出量 | 主库派生的任务记录 | 同批病例 |
| 通用心电语料 | MIT-BIH、动态心电图 | 通用心电记录 | 场景不同 |
| 监护设备算法 | 信号质量、伪差 | 相关方法记录 | 可作负例来源 |
6.3 与主库的分工
分工可以一句话概括:主库负责「记录」,本文负责「判读」。主库的强项是多参数、全程、高采样;本文的强项是逐搏、有医师背书、开箱即用。任何需要「信号加解释」的研究,都必须两边一起用。
这个分工也解释了两者的引用关系。官方明确要求同时引用主库,原因不是礼貌,而是方法学上的必要:本文的结论只有在波形可复现的前提下才成立,而波形在另一边。
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
在打分之前,必须先纠正一个常见的错位:很多人拿「竞赛数据集」的尺子来量它,期待它给出标准的训练测试划分、现成的基线分数、以及均衡的类别分布。这三样它都没有。这是误判,因为它从一开始就不是按竞赛数据集设计的。
它是按「临床判读记录」设计的。这意味着它保留了真实判读中的不均衡、不确定与边界模糊,而这些恰恰是临床场景的真实形态。评价它的正确尺子,是「在术中节律这个切面上,它的判读有多可信、覆盖有多完整」,而不是「它有多像一个可以直接打榜的基准」。
同一个错位还有一个变体:拿「全量覆盖」去要求它,说标注只覆盖二十分钟太短。这也是误判。全量覆盖意味着要对数百小时的信号逐搏判读,成本高出一个数量级;团队选择在候选段上做深,是在成本与价值之间的取舍。§4.4 的案例里那段十几秒的成串异位,就是在候选段内部被完整读出来的——覆盖短,但读得深。
7.1 五维评分
| 维度 | 分数(5 分制) | 依据 |
|---|---|---|
| 完整性 Completeness | 3.0 | 只覆盖候选段,非全程;单导联 |
| 准确性 Accuracy | 4.5 | 五名医师交叉复核,一致性好 |
| 一致性 Consistency | 4.0 | 标签体系清晰,两层粒度定义明确 |
| 时效性 Timeliness | 2.5 | 采集于数年前,设备与流程已变化 |
| 可用性 Usability | 4.0 | 开放、免申请、格式简单,但需配主库 |
| 可链接性 Linkability | 4.5 | 与主库多参数同轴,多模态潜力大 |
准确性与可链接性给高分,是因为这两项确实是它的强项:判读有医师背书,时间轴与主库共享。完整性与时效性给低分,同样有据:覆盖不全程,采集年代较早。可用性扣的一分不在开放程度,而在「必须有另一个数据集才能用」这个门槛。
7.2 DAIMS 六维评估
DAIMS 是一套面向数据供给方与使用方之间契约的框架,六个维度分别问:数据是否被描述清楚、质量是否被声明、访问是否受限、使用条款是否清楚、标识是否稳定、供给是否可持续。
| DAIMS 维度 | 评分(5 分制) | 具体表现 |
|---|---|---|
| 数据描述 | 5 | 字段、节律类别、质量定义、用法示例齐备 |
| 数据质量 | 4 | 交叉复核流程公开;未见逐类一致性报告 |
| 数据访问 | 5 | 开放获取,无需申请,静态链接稳定 |
| 数据使用 | 5 | CC BY 4.0,允许商用,条款清晰 |
| 数据标识 | 4 | 有 DOI 与版本号;依赖主库版本,需并列记录 |
| 数据供给 | 3 | 学术项目,无更新承诺,扩展节奏未知 |
供给维度给三分是有理由的:四百多例、单一版本,没有看到明确的增量路线图。这不构成缺陷,但它意味着规划长期项目时,应当假设这是静态语料,把扩展性建立在自己的补充计划上。
7.3 已知的、可枚举的偏差
把偏差逐条列出,比说「存在偏差」有用。下面每一条都能在官方说明里找到依据,或者能从数据设计逻辑推出来。
| 偏差 | 机制 | 方向 | 影响谁 |
|---|---|---|---|
| 候选门控偏差 | 只有被算法判为可能的段才入选 | 异常富集,正常被压低 | 发生率估计 |
| 算法召回偏差 | 筛选器漏掉的异常不进入语料 | 对漏检率的估计偏乐观 | 算法评测 |
| 候选段截断 | 只读每例约二十分钟 | 长时段演变被切掉 | 趋势类任务 |
| 单导联限制 | 仅 II 导联 | 空间信息缺失 | 形态学任务 |
| 单中心限制 | 一家医院、一套设备 | 泛化被高估 | 外部验证 |
| 人群限制 | 仅非心脏手术、成人 | 心脏手术与儿科缺席 | 适用范围 |
| 判读视角 | 麻醉科医师而非电生理医师 | 节律分类偏粗 | 机制类研究 |
| 噪声段无标签 | 严重伪差段不产生搏级行 | 有效时长被高估 | 时长统计 |
第一行与第二行要合起来看。筛选与召回共同决定了语料的选择性:它既偏向异常的段落,又偏向算法能认出的异常。这两重偏向叠加,使得在这份语料上训练和评测的模型,其表现不能直接外推到「全部术中信号」。这是最需要在使用者心里留下印记的一条。
第三行的后果常被低估。术中节律的演变往往是分钟级的:一次体位改变引起的迷走反射、一次快速输血引起的电解质波动,都可能在一两分钟内完成从窦性到异位再回到窦性的循环。候选段截断之后,这些「过程」在语料里变成了「片段」,模型学到的是片段分类,不是过程追踪。
7.4 外部验证矩阵
| 验证类型 | 具体证据 | 结论 |
|---|---|---|
| 判读人间验证 | 五名麻醉科医师交叉复核 | 标签可信度有直接证据 |
| 一致性量化 | 官方报告整体 kappa 与标准差 | 总体一致性好,少数类未单列 |
| 来源一致性 | 波形与标注同源同轴 | 时间对齐无需外部校准 |
| 方法可复现 | 随包提供用法示例与代码仓库 | 取数与对齐路径明确 |
| 多中心验证 | 未见公开报告 | 泛化能力未知 |
| 跨导联验证 | 未见,语料本身单导联 | 不可评估 |
| 任务级基准 | 官方未给标准划分与基线 | 复现需自建协议 |
七类里有四类成立,三类缺失。缺失的三类恰好是外部效度的三个方向:跨中心、跨导联、跨任务协议。这说明它在内部效度上做得很扎实,在外部效度上留白明显。
7.5 它为何能持续:波形已经存在,缺的只是判读
一份标注语料要活下来,通常需要两条腿:可持续的数据来源,与可持续的判读投入。它的特殊之处在于第一条腿是现成的。
第一层是波形的零成本复用。VitalDB 主库已经存在、已经脱标识、已经开放、已经被大量研究引用。本项目不需要重新采集,也不需要重新走伦理与数据治理流程,只需要在主库上叠加一层判读。这让它的边际成本主要落在医师时间上,而不是采集与合规上。
第二层是临床需求的持续性。术中监护设备每年出货量巨大,算法从「阈值报警」向「节律识别」迁移是确定的趋势。任何做这条路线的团队都需要术中场景的标注语料,而公开选项极少。需求在,语料就有被引用的理由。
第三层是判读标准的可传承。五名医师、明确的节律类别定义、两级质量标记,这套标准一旦写下来,就可以被后来的标注工作沿用甚至扩展。扩充不需要从零定义标签体系,只需要按同一套规则继续读。
三层叠起来,就是它的生存逻辑:主库供波形,需求供动机,标准供扩展。§4.4 的案例里的那一分钟,之所以能被反复引用,正因为它同时展示了这三层——波形来自主库,判读来自医师,标签体系让这一段可以被别人复用。
§8 生态位与历史
8.1 从主库到标注层的三年
时间线要从 VitalDB 主库说起。主库在 2022 年以论文与开放数据的形式发布,覆盖数年间在一家医院手术室采集的数千例非心脏手术。它的出现填补了「术中多参数波形开放」这个空白,随后被大量用于低血压预测、无创血压估计、心输出量估计等任务。
| 时间 | 事件 | 意义 |
|---|---|---|
| 2022 年 | VitalDB 主库论文与数据发布 | 术中波形开放 |
| 2022 至 2025 年 | 主库被大量用于术中监护任务研究 | 波形层形成生态 |
| 2025 年前后 | 心律失常标注工作启动 | 标注层开始 |
| 2026 年 2 月 | 本标注集 1.0.0 发布 | 术中逐搏标注首次公开 |
| 后续 | 未见明确的扩展路线图 | 静态语料 |
这段历史说明一件事:标注层不是凭空出现的,它是主库生态成熟之后的自然延伸。先用起来,再发现缺标注,再补标注,这是开源数据常见的演化路径。
8.2 为什么是心律失常,而不是别的
主库可以派生的标注方向很多:低血压事件、血氧下降、心律失常、机械通气事件。团队先做了心律失常,有几个可解释的原因。
其一是判读可行性。心电判读有成熟的类别体系与相对明确的边界,医师之间的分歧可以被压到较低水平。相比之下,低血压事件的边界取决于定义阈值与基线选择,标注一致性天然更低。
其二是自动化筛选的可行性。搏分类在算法上已经相对成熟,用一个分类器做候选筛选的召回率可以做得比较高,从而把人工量压下来。别的任务未必有同样好用的筛选器。
其三是临床价值明确。术中房颤、室性心律失常、房室阻滞都会直接影响血流动力学与手术进程,是麻醉科最关心的心电问题。
8.3 在公开心电语料谱系里的位置
| 谱系位置 | 代表语料 | 本文的差异 |
|---|---|---|
| 门诊十二导联 | 各类竞赛语料 | 单导联、术中、无标准划分 |
| 动态心电图 | MIT-BIH 系列 | 场景不同,标注传统更久 |
| 重症监护 | 各类 ICU 波形库 | 场景邻近,标注体系不同 |
| 术中 | VitalDB 主库(无标注) | 本文是唯一有逐搏标注的术中支 |
| 可穿戴 | 单导联长程记录 | 干扰类型与人群不同 |
这个位置有一个副作用:它既是「术中」,又是「单导联」,因此既不能被十二导联语料替代,也不能被可穿戴语料替代。它填补的是两个维度交叉处的一个小格子,格子小,但别处没有。
8.4 生态位的两面
一面是不可替代。术中加逐搏的组合,公开语料里目前只有它。任何做术中节律识别的团队,绕不开它。
另一面是不可扩张。单中心、单导联、单批病例,决定了它无法通过简单扩充变成「通用的术中节律语料」。要扩张,必须引入新的中心、新的设备、新的导联配置,那是另一项工程的规模。
这两面并存,就是它的生态位:小而必用,用而不够。理解这一点,才不会对它提出超出设计的目标。
§9 使用指引
9.1 三种角色的路径
| 角色 | 目标 | 最短路径 | 主要风险 |
|---|---|---|---|
| 算法工程师 | 训练并评测搏分类器 | 下载标注、批量取波形、自建划分 | 抽样偏倚导致过优估计 |
| 临床研究者 | 描述术中节律现象 | 用标注做探索,回波形核对 | 误用候选段算发生率 |
| 设备开发者 | 评估产品在术中的表现 | 作为外部测试集之一 | 单中心结果不足以支撑声明 |
第二类角色最需要克制。用这份语料做「术中房颤有多少」这类描述,看起来顺手,但抽样已经破坏了分母。正确做法是用它描述「房颤在术中的形态特征」,而不是「房颤在术中的频度」。
9.2 一条最短的可用流程
从零到跑通一个搏分类实验,最短的路径是四步:下载标注、批量取波形、切窗、训练。下面的脚本把前两步串起来,并给出切窗的基本形态。
import numpy as np
import pandas as pd
import vitaldb
FS = 500
WIN_L, WIN_R = 0.3, 0.4 #-- 取 R 波前 300 毫秒、后 400 毫秒
LABEL_MAP = {"Normal": 0, "Supraventricular": 1, "Ventricular": 2, "Unclassifiable": 3}
meta = pd.read_csv("metadata.csv")
case_ids = [int(c) for c in meta["case_id"]][:5]
X, y = [], []
for cid in case_ids:
ann = pd.read_csv(f"Annotation_Files/Annotation_file_{cid}.csv")
sig = vitaldb.load_case(cid, ["SNUADC/ECG_II"], 1 / FS)
if sig is None:
continue
sig = np.asarray(sig, dtype=np.float32).reshape(-1)
for _, r in ann.iterrows():
c = int(round(float(r["time_second"]) * FS))
a, b = c - int(WIN_L * FS), c + int(WIN_R * FS)
if a < 0 or b > sig.size:
continue
X.append(sig[a:b])
y.append(LABEL_MAP.get(str(r["beat_type"]).strip(), 3))
X = np.stack(X)
y = np.asarray(y)
print("样本", X.shape, "类别", np.bincount(y))
这段代码刻意留了两处可改。第一处是窗宽,三百与四百毫秒是一个够用的默认值,做节律判别时可以放宽到前后各一秒。第二处是噪声与低质量段的处理,示例里没有剔除,正式训练时应当用 §2.2 的布尔列把它们筛掉或降权。
9.3 训练集划分的三条建议
第一条,按病例划分,不按搏划分。同一例内的相邻搏高度相关,按搏随机划分会把同一段信号拆到训练与测试两侧,导致测试分数虚高。这是心电任务里最常见的划分错误。
第二条,把低质量段单列。它们要么剔除,要么单独作为一个评测子集,用来观察模型在噪声下的退化。混进主集会让「总体准确率」掩盖掉这个退化。
第三条,报表要给类别分布。这里只有四类,但极少类(无法归类)的样本量很小,用一个总体准确率会严重误导。至少给出每类的样本量与每类的指标。
9.4 引用方式
正式引用要两件一起做:引用本文语料,并引用主库。前者给出版本与 DOI,后者给出波形的来源与原始描述。只在正文提一句「数据来自 VitalDB」而不引主库,在方法学上是不完整的。
Eun D, Shim K, Lee H, Lim Y, Lim H, Lee H, Lee H-C.
VitalDB Arrhythmia Database (version 1.0.0). PhysioNet. 2026.
doi:10.13026/axd6-wm13
Lee H-C, Park Y, Yoon SB, Yang SM, Park D, Jung C-W.
VitalDB, a high-fidelity multi-parameter vital signs database in surgical patients.
Scientific Data. 2022;9:279. doi:10.1038/s41597-022-01411-5
第二条是主库的文献引用,具体卷期与页码以期刊页面为准。使用方法上,引用时还应当说明本文用的是哪个版本、用了哪些病例、以及是否做过筛选——这些信息决定了别人能不能复现。
§10 AI 使用声明
| 事项 | 声明内容 |
|---|---|
| 写作方式 | 由 AI 辅助起草,事实性数字经人工对照官方页面核对 |
| 数据获取方式 | 全部数字来自 PhysioNet 项目主页及其说明、文件、引用子页 |
| 未覆盖的部分 | 未下载全量标注包做逐条统计,未运行官方代码 |
| 数字口径 | 规模类数字取官方摘要表述,未做二次核算 |
| 可复算性 | 附录 A 标注每项数字的来源层级 |
| 已知局限 | 官方内部若存在口径差异,本文按单一来源处理 |
| 使用建议 | 引用前请对照官方页面当前版本复核 |
| 责任边界 | 本文不构成对任何算法的性能评价 |
常见误读
| 常见说法 | 实际 | 证据 |
|---|---|---|
| 「这是 VitalDB 主库的新版本」 | 是主库之上的标注派生层,波形仍在主库 | 官方说明包内不含波形 |
| 「下载就能训练」 | 必须回主库按编号取波形 | 包内只有标注 CSV 与元数据 |
| 「覆盖整台手术」 | 只覆盖每例约二十分钟候选段 | 官方在局限部分明确写出 |
| 「可以算术中房颤发生率」 | 候选段抽样,分母被破坏 | 进入语料的前提是被算法筛出 |
| 「有多导联波形」 | 只有 II 导联 | 官方用法示例仅取该轨道 |
| 「噪声段是正常搏的负例」 | 噪声段无搏级标签,单列为节律类 | 官方对噪声的定义 |
| 「低质量段不可用」 | QRS 仍可辨,可降权使用 | 官方对低质量的定义 |
| 「四类搏标签可以细分成十几种」 | 搏级只有四类,细分在节律层 | 两级标签体系 |
| 「标注未经医师确认」 | 五名麻醉科医师交叉复核 | 官方描述判读流程 |
| 「可以直接拿来打榜」 | 无标准划分、无官方基线 | 包内不含实验协议 |
FAQ
Q1:VitalDB Arrhythmia 与 VitalDB 主库是什么关系?
它是主库的标注衍生层。四百多例病例全部来自主库,波形仍存放在主库,本包只给标注与元数据。两者必须配合使用,引用时也要同时给出。
Q2:数据包里为什么没有波形文件?
官方为了分发效率把标注与波形分开。波形体量大得多,放在主库里由使用者按需取;标注很小,单独发一个包更便于快速分发与版本管理。
Q3:标注是否覆盖整台手术?
不覆盖。标注集中在每例约二十分钟的候选段,是筛选后的人工判读结果。不能当作全程连续的搏级记录,也不能用它算术中某类心律失常的发生率。
Q4:可以直接拿它训练多导联心电模型吗?
不能直接拿。它只给 II 导联单通道标注。回主库取其他通道是可以的,但那些通道没有对应标注,标签无法平移过去。
Q5:许可允许商用吗?
允许。CC BY 4.0 允许商用与改编,条件是署名、注明版本与 DOI、说明是否修改。同时引用主库是官方明确要求,否则方法学链条不完整。
Q6:能否用它证明某个算法的临床可用性?
只能作为术中场景的证据之一。单中心、单导联、候选段抽样三重限制叠加,外部验证仍须另有队列,不能仅凭此集下结论。
Q7:五名医师的判读一定比一名更可靠吗?
在分歧可协商的前提下通常是。多名独立判读能压低个体偏差,但代价是少数类的分歧可能被多数意见抹平。官方报告的整体一致性指标是高,但未逐类给出。
Q8:为什么只有非心脏手术?
主库本身以非心脏手术为主,因为这类手术的术中监护更依赖常规多参数记录,且伦理与数据开放的边界更清楚。心脏手术的体外循环与特殊监护不在其中。
Q9:时间戳与主库波形对不上怎么办?
先查采样率换算是否一致,再查是否对波形做过裁剪或滤波。前两步都对上,且仍有整体偏移,则应检查取的是否为同一条轨道、同一段记录。
Q10:能不能用它做信号质量算法?
可以,但只到粗粒度。它把质量分成正常、低质量、噪声三级,足够做三分类或二分类,不足以训练精细的伪差类型识别。
Q11:为什么不能按搏随机划分训练测试?
同一例内的相邻搏高度相关。按搏随机划分会把同一段信号的邻域拆到两侧,测试分数会虚高。正确做法是按病例划分。
Q12:这份语料会继续扩充吗?
官方未给出明确路线图。规划长期项目时,应当把它当作静态语料,扩展性建立在自己的补充计划上,而不是假设它会持续增量。
术语表
| 术语 | 英文 | 含义 |
|---|---|---|
| 搏级标签 | Beat-level label | 对单个心搏的类别判定,本文为四类 |
| 节律标签 | Rhythm label | 对一段连续心电的整体心律判定,本文为十类 |
| 室上性搏 | Supraventricular beat | 起源在心室以上的异位搏 |
| 室性搏 | Ventricular beat | 起源于心室的异位搏 |
| 成串室性异位 | Patterned ventricular ectopy | 连续出现的室性异位搏 |
| 成串房性异位 | Patterned atrial ectopy | 连续出现的房性异位搏 |
| 窦房结功能不全 | Sinus node dysfunction | 窦房结起搏或传导功能异常 |
| 房室阻滞 | Atrioventricular block | 房室传导延迟或中断 |
| 游走性心房起搏 | Wandering atrial pacemaker | 起搏点在心房内游走 |
| 多源性房性心律 | Multifocal atrial rhythm | 多个心房起搏点交替 |
| 室上性快速性心律失常 | Supraventricular tachyarrhythmia | 心室以上的快速心律 |
| 室性快速性心律失常 | Ventricular tachyarrhythmia | 心室来源的快速心律 |
| 低信号质量 | Bad signal quality | QRS 可辨但 P 波或 T 波被噪声掩盖 |
| 噪声段 | Noise | 伪差严重到 QRS 无法辨认的片段 |
| 候选段 | Candidate segment | 被算法筛出、交由医师判读的片段 |
| 判读人间一致性 | Inter-rater reliability | 不同判读人之间结论的一致程度 |
| 一致性系数 | Cohen’s kappa | 扣除随机一致后的一致性度量 |
| 主库 | Parent database | 存放原始波形的 VitalDB |
| 派生标注层 | Annotation layer | 在主库之上叠加的人工判读结果 |
| II 导联 | Lead II | 术中常用的单导联心电配置 |
| 重采样 | Resampling | 把波形转换到目标采样率的过程 |
| 时间轴零点 | Time zero | 标注与波形共同采用的时间起点 |
| 心跳零基线 | Baseline | 电压参考水平,用于判断波形偏移 |
| 逐搏标注 | Beat-wise annotation | 每个心搏都有独立标签的标注方式 |
| 节律分段 | Rhythm segmentation | 把连续记录切分为等节律区间的任务 |
| 病例编号 | case_id | 主库与标注层共享的唯一标识 |
| 心脏手术 | Cardiac surgery | 本文不覆盖的一类手术 |
| 围术期 | Perioperative period | 手术前中后的整体时间段 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 病例数 | 482 例 | 官方摘要与页面概览 | 官方页面 |
| 标注总时长 | 734,528 秒 | 官方摘要 | 官方页面 |
| 逐搏标注数 | 逾六十六万个 | 官方摘要 | 官方页面 |
| 搏级类别数 | 4 类 | 官方摘要 | 官方页面 |
| 节律类别数 | 10 类 | 官方摘要 | 官方页面 |
| 每例覆盖时长 | 约二十分钟 | 官方局限说明 | 官方页面 |
| 导联配置 | II 导联单通道 | 官方用法示例 | 官方页面 |
| 标注采样时间轴 | 500 Hz | 官方用法示例 | 官方页面 |
| 判读人数 | 5 名麻醉科医师 | 官方摘要 | 官方页面 |
| 每段判读人数 | 至少 2 人 | 官方摘要 | 官方页面 |
| 整体一致性 | 官方报告的 kappa 值 | 官方摘要 | 官方页面 |
| 包体大小 | 未压缩约二十兆字节量级 | 官方文件页 | 官方页面 |
| 许可 | CC BY 4.0 | 官方许可页 | 官方页面 |
| 版本与日期 | 1.0.0,2026 年 2 月 | 官方页面 | 官方页面 |
| 病例来源年份 | 与主库同批,数年前采集 | 主库描述 | 官方页面 |
附录 B:数字的来源分层
| 层级 | 说明 | 本文中的例子 |
|---|---|---|
| 官方页面 | 直接取自 PhysioNet 项目页、说明页、文件页、引用页 | 病例数、时长、类别数、许可、版本 |
| 论文摘要 | 官方未在页面给出、仅见于相关工作摘要 | 未见本文采用此类数字 |
| 未核实 | 官方未说明、本文仅作量级描述 | 包体精确字节数、各节律类别的病例分布 |
凡属第三层的表述,本文一律用「数十兆字节量级」「数十个区间」这类概数,不写具体到个位的数字。这样做不是回避,而是因为这类数字随版本变动,写死反而会误导。
附录 C:完整参考文献
| 序号 | 文献 | 用途 |
|---|---|---|
| 1 | Eun D, Shim K, Lee H 等. VitalDB Arrhythmia Database. PhysioNet, 2026. doi:10.13026/axd6-wm13 | 本文语料的正式引用 |
| 2 | Lee H-C, Park Y, Yoon SB 等. VitalDB. Scientific Data, 2022;9:279 | 波形的正式引用 |
| 3 | PhysioNet 平台自身的方法学文章 | 平台层面的引用 |
| 4 | 术中低血压预测相关工作 | 说明主库的派生方向 |
| 5 | 动态心电图搏分类的经典工作 | 说明搏级标注的传统 |
| 6 | 心电信号质量评估相关工作 | 说明质量标记的意义 |
附录 D:任务代码
把一个完整的最小实验跑通,需要把标注、波形、切窗、划分四件事串起来。下面的脚本给出按病例划分的基本形态,可以直接改为正式训练。
import numpy as np
import pandas as pd
FS = 500
WIN = (int(0.3 * FS), int(0.4 * FS))
MAP = {"Normal": 0, "Supraventricular": 1, "Ventricular": 2}
def build(meta_path, ann_dir, loader):
"""按病例聚合样本,返回 (X, y, case_of_row)。"""
meta = pd.read_csv(meta_path)
X, y, case = [], [], []
for cid in meta["case_id"]:
cid = int(cid)
ann = pd.read_csv(f"{ann_dir}/Annotation_file_{cid}.csv")
sig = loader(cid)
if sig is None:
continue
for t, bt, bad in zip(ann["time_second"], ann["beat_type"], ann["bad_signal_quality"]):
if str(bad).strip().lower() == "true":
continue
lab = MAP.get(str(bt).strip())
if lab is None:
continue
c = int(round(float(t) * FS))
a, b = c - WIN[0], c + WIN[1]
if a < 0 or b > sig.size:
continue
X.append(sig[a:b])
y.append(lab)
case.append(cid)
return np.stack(X), np.asarray(y), np.asarray(case)
def split_by_case(case_ids, seed=0):
"""按病例划分,避免同例相邻搏同时落入训练与测试。"""
rng = np.random.default_rng(seed)
uniq = np.unique(case_ids)
rng.shuffle(uniq)
cut = int(len(uniq) * 0.8)
train, test = set(uniq[:cut]), set(uniq[cut:])
return train, test
#-- loader 由使用者替换成基于 vitaldb 的取数函数
附录 E:如果只记五件事
第一,它是标注层,不是波形层。波形在主库,标注在这里,两者用病例编号连接,引用要两份一起给。
第二,它的覆盖是候选段,不是全程。每例约二十分钟,且进段门槛是算法筛出异常,所以不能用它算发生率。
第三,它的独特性在「术中」与「逐搏」的交集。单看任何一条都有更强的语料,两条叠起来可选的就很少了。
第四,两级标签不能混用。搏级四类回答「这一次除极来自哪里」,节律级十类回答「这一段整体是什么」,任务不同,取标签的层级就不同。
第五,划分一定按病例。按搏随机划分会让同例相邻搏分落两侧,测试分数虚高,这是这类语料最常见的错误。
编辑说明
核验时间:2026 年 10 月 28 日。核对方式:访问 PhysioNet 的项目主页面、数据说明子页、文件子页与引用子页,逐页读取官方表述;未下载全量标注包做逐条统计,也未运行官方示例代码,因此文中凡涉及包内文件内部结构、各节律类别的病例构成、包体精确字节数等内容,均按官方文字描述转述而不给出逐项统计值。规模类数字(病例数、总时长、逐搏标注数、类别数)取自官方摘要,未做二次核算。文中出现的一致性系数只以「官方报告的 kappa 值」表述,未复述具体数值与标准差,原因是该指标随版本与统计口径可能调整,写死数值对使用者的决策没有增量。病例 337 的一段标注用于结构示意,其中时间戳与标签组合用于说明两个粒度的并置方式,不作为该例的真实判读结果引用。若官方将来调整字段命名或节律类别定义,以官方页面当前版本为准。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- ucddb — 共享标签:生理信号 / 多模态
- neurovault — 共享标签:多模态 / 医学问答与基准
- rnacentral — 共享标签:多模态 / 医学问答与基准
- rfam — 共享标签:多模态 / 医学问答与基准
- seed — 共享标签:生理信号 / 医学问答与基准
- cded — 共享标签:生理信号 / 多模态
- kiel-cardio — 共享标签:生理信号 / 多模态
- eye-tracking-ecg — 共享标签:生理信号 / 多模态
- wesad — 共享标签:生理信号 / 多模态
- qt-database — 共享标签:生理信号 / 医学问答与基准
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

