七段记录,最长一天 — MIT-BIH LTDB 长时程心电库

7 条记录 / 14–24 小时 / 128 Hz 双导联

来源 https://physionet.org/content/ltdb/1.0.0/发布时间: 2026-10-28最后更新: 2026-10-28 阅读 15
七段记录,最长一天 — MIT-BIH LTDB 长时程心电库

信息速览

数据集名称七段记录,最长一天 — MIT-BIH LTDB 长时程心电库
数据类型时序信号,波形,人工标注,元数据
规模官方未公布受试者数;7 条记录 / 7 组年龄性别
接入方式https://physionet.org/content/ltdb/1.0.0/
AI 就绪度

心电公开数据集里,绝大多数资源的选择题只有两道:要导联多,就得接受每段只有十秒;要时间长,就得接受只有一两个导联。长时程这一类里,真正把「整天」当基本单位的库并不多,而其中最早、最小、也最容易被误认的那个,就是 MIT-BIH 长时程心电数据库(ltdb)。

它只有七条记录,每条从十四个小时到将近一整天,采样率 128 Hz,六条双导联、一条三导联,标注只有心搏与信号质量两层,整库未压缩两百零五兆。这几个数字放在今天的语境里近乎寒酸,却恰好构成一个别人很难复制的组合:足够长,长到能覆盖一次完整的睡眠与清醒周期;足够小,小到可以在十分钟内下完、在笔记本上跑通全流程。

它的历史位置比它的体量更重要。它是 PhysioNet 长时程家族里第一个上线的库,比带 ST 事件标注的 ltstdb 早一年,比房颤长时程库早了近十年。理解它,等于理解这一族库共同的技术底座——同一套 WFDB 格式、同一套注释码、同一批来自波士顿的磁带。一屏速览见下表。

维度 内容
全名 MIT-BIH Long-Term ECG Database
常用缩写 ltdb
建设机构 麻省理工学院(MIT)与波士顿贝斯以色列医院(Beth Israel Hospital)合作
提交者 George B. Moody(Harvard-MIT 健康科学与技术部)
上线时间 1999 年 8 月 3 日,版本 1.0.0
DOI 10.13026/C2KS3F
记录数 7 条
每条时长 官方称 14–22 小时;头文件换算为 13.9–23.9 小时
导联 6 条双导联、1 条三导联
采样率 128 Hz
量化与增益 12 位(三导联记录为 10 位),每毫伏 200 单位
标注内容 心搏类型 + 信号质量变化标记,经人工复核
标注总量 约六十七万条参考注释
文件格式 WFDB:.hea / .dat / .atr,另有 .hea- 与 .xws
整库体积 未压缩 205.4 MB
许可 ODC-BY 1.0,无需注册
典型用途 长时程心搏检测的快速验证、低采样率鲁棒性对照、教学演示

§1 它要解决的具体麻烦

1.1 一整天的心跳,需要多细的采样才够

心电算法在实验室里的默认假设是「信号很干净、导联很清楚、片段很短」。真实场景恰好相反:设备贴在人身上一整天,电极会干、会松、会被翻身压出伪迹,而算法要在这堆东西里找出每一次心跳。这类问题没法用十秒的片段回答,因为十秒里几乎不会出现电极脱落,也不会出现连续几小时的基线漂移。

ltdb 就是为这个问题准备的早期材料。它的七条记录全部是真实的体表长时程监护,不是拼接、不是仿真、不是从短记录循环复制出来的。每条记录都带着完整的一天:入睡、醒来、走动、静坐。心搏标注覆盖全程,信号质量的变化也被单独标出来。这两件事放在一起,才构成「检测器在真实长时程里表现如何」的完整证据。

它的另一个价值在于采样率。128 Hz 是这一族库里最低的一档,每两个采样点间隔约 7.8 毫秒。对 R 峰定位来说这够用,对 QRS 形态、ST 段水平这类需要更细时间分辨率的测量来说就不够。这个限制不是缺陷,而是一个明确的边界条件:想研究低采样率可穿戴设备的人,正好需要一个「原生长时程、原生低采样」的参照。

1.2 三条常见的错误期待

第一条,把它当成 ltstdb 的旧版本。两个库名字都带 long-term,都出自波士顿同一家医院,都用同一套格式,很容易被当成同一件事的前后两版。实际上它们的记录名体系完全不同,标注内容差了一整层:ltstdb 有 ST 事件、节律变化、信号质量三类附加标注,ltdb 只有心搏与信号质量。

第二条,把它当成房颤或缺血的数据集。它的注释文件里没有任何节律段标记,也没有 ST 偏移的时间序列。想拿它做房颤,只能从心搏间隔的序列统计里间接构造标签;想拿它做缺血,连构造的原材料都没有。这一点在文献里被反复踩到,因为库名里的 ECG 二字太容易被泛化。

第三条,把它当成可以训练的数据。七条记录、最多七个人,任何带参数的模型都会在第二轮就把它记住。它的正确位置是验证端,不是训练端。把它混进训练集,得到的指标只反映记忆能力。

1.3 它能给到的与给不到的

你的需求 它给的 够不够
长时程心搏检测的全流程演练 七条完整记录,逐搏标注覆盖全程 够,且是全库中最省事的一个
低采样率下的 R 峰定位评估 原生 128 Hz,无重采样 够,这是它最独特的用法
信号质量变化对检测的影响 注释内单独标出质量变化点 够做定性分析,样本量很小
房颤检测的训练与测试 无节律标注 不够,只能二次构造标签
心肌缺血事件研究 无 ST 标注 不够,需改用 ltstdb
形态学精细测量(QRS 宽度、QT) 128 Hz 时间分辨率 勉强,误差会进入结论
患者级泛化的统计结论 最多七个人 不够,只能做案例级陈述
跨库外部验证 与 MIT-BIH 系列同注释码 够,常被当作外测目标

1.4 你的处境与它能帮到的事

你的处境 它能帮你什么 下一步该做什么
你刚写好一个心搏检测器,想找个小库先跑通端到端流程 两百兆、七个文件、无需注册,十分钟内可完成下载到评估 先跑通 §9.2 的最短流程,再换大库
你在做可穿戴设备的低采样率算法 提供原生 128 Hz 的长时程真值 把同一段信号降采样到 64 Hz 与 32 Hz,观察召回如何衰减
你想验证模型在电极脱落、长时间噪声下是否稳定 注释里带信号质量变化标记,可作为噪声区段的近似索引 用质量标记切出噪声段,单独报告该段性能
你要给模型做跨库外测,需要一个与训练库不同源的集 与 MIT-BIH 心律失常库同注释码、不同人群与设备 固定映射表后零样本测试,记录掉分幅度
你在教心电信号处理,需要一条能讲完的完整记录 单条近二十四小时,可截取任意时段做教学 用 §2.3 的读取流程导出,注意标注在末尾可能缺失
你在核对某篇论文的长时程结论能否复现 体量小,可快速重建对方的评测条件 先对齐采样率与注释映射,再比较数值

1.5 一句话判断

它不是用来把模型训强的,而是用来把流程走通的:七条记录足够暴露管线里的每一个错误,又小到让你愿意反复重跑。

1.6 不适合谁:四条边界

不适合拿来做训练集。 七条记录、最多七个人,任何深度模型都会在极短时间内过拟合。用它做训练,得到的不是能力,是记忆。

不适合拿来做节律或缺血任务。 没有节律段标注,没有 ST 事件标注,连辅助注释字符串都是空的。所有节律类标签都得自己造,而造标签的规则一旦写不清,结论就无法复现。

不适合拿来做精确形态学测量。 128 Hz 的采样间隔约 7.8 毫秒,QRS 起点与终点的判定误差会直接进入宽度、QT 间期这类指标。要做形态学,应该换到采样率更高的库。

不适合拿来做人群层面的统计推断。 官方没有公布受试者数,也没有诊断、用药、随访。七组年龄性别不足以支撑任何关于人群分布的结论。

§2 数据构成与规格

2.1 一个记录由三个文件组成

数据库沿用 WFDB 格式,这是 PhysioNet 从 1980 年代沿用至今的物理信号存储规范。每条记录对应三个同名文件:.hea 是纯文本头文件,第一行写记录名、信号条数、采样率与采样点总数,随后每条信号一行,声明存储格式、增益、位宽、基线、初始值、校验和与信号名;.dat 是二进制信号本体,按采样点交错存放各路信号的整数值;.atr 是二进制注释文件,存放事件位置与类型。

三者缺一不可。只拿 .dat 无法还原毫伏值,因为增益写在头文件里;只拿 .atr 不知道这些时刻对应什么波形。把数据转成 CSV 或 NumPy 数组是有损操作,头文件里的增益、基线、信号名会被压进列名,注释里的类型码会被压成字符串,想回到原始语义就得靠映射表。

目录里还有三类附属物。RECORDS 是七行纯文本,按行列出记录名;ANNOTATORS 只有一行,原文是「atr reference beat and signal quality annotations」,明确说明注释文件里同时含心搏与信号质量两类内容;SHA256SUMS.txt 是整库的校验和清单。另外每个记录还带一个 .hea- 与一个 .xws:前者是 2012 年改写之前的旧版头文件,信号名写的是「record 14046, signal 0」这类机械描述;后者是 WaveBox 网页工具的会话文件,内容只有三行,其中一行还残留着服务器端模板占位符,指向的是一个早已失效的地址。

2.2 字段与记录的完整字典

位置 字段 含义 取值示例
.hea 第 1 行 记录名 五位数字,同时是文件名 14046
.hea 第 1 行 信号条数 2 或 3 2
.hea 第 1 行 采样率 每秒采样点数 128
.hea 第 1 行 采样点总数 每条信号的采样点数 10828800
.hea 信号行 存储格式 212 为双信号 12 位,310 为三信号 10 位 212 / 310
.hea 信号行 增益 每毫伏的整数单位数,0 表示按缺省 200 0
.hea 信号行 位宽 量化位数 12 / 10
.hea 信号行 基线 零电平对应的整数值 0
.hea 信号行 初始值 第一个采样点的整数值 32
.hea 信号行 校验和 全段采样点累加和,用于完整性检查 -13462
.hea 信号行 信号名 只写 ECG1 至 ECG3,不含解剖位置 ECG1
.hea 注释行 年龄 受检者年龄,整数 46
.hea 注释行 性别 M 或 F M
.atr 注释位置 采样点序号,除以 128 得秒 600
.atr 心搏类型码 沿用 MIT-BIH 标准注释码 N V F J S a
.atr 信号质量标记 波浪号,表示该处信号质量发生变化 ~
RECORDS 记录清单 七行,每行一个记录名 14046
ANNOTATORS 注释角色 一行说明 atr reference beat and signal quality annotations
SHA256SUMS.txt 校验和 逐文件 SHA256 64 位十六进制串

2.3 一条记录的完整解剖

以 14046 为例,头文件只有四行,全部信息都在里面:

14046 2 128 10828800
14046.dat 212 0 12 0 32 -13462 0 ECG1
14046.dat 212 0 12 0 -58 -28804 0 ECG2
#Age: 46  Sex: M

第一行的四个数依次是记录名、信号条数、采样率、采样点总数。用采样点总数除以采样率,得到 84600 秒,即 23.5 小时。第二、三行是两路信号,存储格式 212 表示两个 12 位采样点压进三个字节,增益字段写 0,按 WFDB 约定取缺省值 200,所以一个整数单位等于 5 微伏。第四行是唯一的临床信息:46 岁,男性。

把这条记录读进内存只需要几行代码:

import wfdb
import numpy as np

rec = wfdb.rdrecord('14046', pn_dir='ltdb')
print(rec.fs, rec.sig_len, rec.sig_name, rec.adc_gain, rec.units)
#-- 128 10828800 ['ECG1', 'ECG2'] [200.0, 200.0] ['mV', 'mV']

x = rec.p_signal[:128 * 60]        #-- 取第一分钟
print(x.shape, float(np.ptp(x[:, 0])), float(np.std(np.diff(x[:, 0]))))

这段代码里最容易忽略的是 physical=True 这个缺省行为:p_signal 已经按增益换算成毫伏,用 d_signal 拿到的才是原始整数。两种口径混用会得到相差两百倍的结果,而且不会报错。注释文件则要用 rdann 单独读:

import wfdb

ann = wfdb.rdann('14046', 'atr', pn_dir='ltdb')
print(len(ann.sample), ann.symbol[:10], set(ann.symbol))
print('first beat at %.1f s, last at %.1f h' % (ann.sample[0] / 128, ann.sample[-1] / 128 / 3600))

读出来的 symbol 是字符列表,aux_note 全是空串——这意味着这个库没有任何节律段标注。这一点用一行代码就能确认,也应该是每个使用者在动手前做的第一件事。

2.4 七条记录的逐项参数

记录 时长(小时) 采样点 导联 格式 年龄 性别 参考注释(条)
14046 23.50 10828800 2 212 46 M 115278
14134 13.93 6420480 2 212 71 F 49769
14149 23.87 10997760 2 212 47 M 145139
14157 20.52 9454080 2 212 88 M 88298
14172 21.17 9753600 2 212 75 M 66413
14184 22.25 10252800 2 212 71 M 101567
15814 22.22 10237440 3 310 58 M 103388

表里的时长是把采样点数除以 128 得到的,不是官方公布值;注释条数是逐个读取注释文件后的合计,七条相加约六十七万条。这两列都标注了来源,与官方页面并列时可对照阅读(§7.3)。

七条记录里,14134 最短,不足十四小时;14149 最长,接近二十四小时。年龄跨度从 46 岁到 88 岁,六男一女,没有一条来自年轻受试者。这个分布不是抽样设计的结果,而是当时能拿到的监护记录的实际情况,官方没有对此做任何说明。表中唯一的三导联记录是 15814,它与其余六条在格式与形状上的差别,见 §4.3 的案例。

2.5 与同类资源的字段差异

维度 ltdb ltstdb ltafdb afdb incartdb
记录数 7 86 84 25 75
每条时长 14–24 小时 21–24 小时 24–25 小时 10 小时 30 分钟
导联数 2(一条 3) 2–3 2 2 12
采样率 128 Hz 250 Hz 128 Hz 250 Hz 257 Hz
心搏标注 有 有 有 有 有
节律段标注 无 有 有 有 无
ST 事件标注 无 有 无 无 无
信号质量标注 有 有 部分 部分 无
整库体积 205.4 MB 数 GB 级 数 GB 级 数百 MB 数百 MB
上线年份 1999 2000 2008 2000 2008

这张表回答的是「同族长时程库里该挑哪一个」。如果任务是节律分类,ltdb 直接出局;如果任务是缺血,只有 ltstdb 可用;如果任务是长时程心搏检测的快速验证,ltdb 的体量与完整度是最优组合。对照库的数字取自各自的官方页面,个别字段(ltstdb 的采样率)取自其方法学论文,不是推算值。

2.6 导联命名的空白

头文件里的信号名是 ECG1、ECG2、ECG3,不是 II、V1、V5 这类解剖位置。官方页面没有说明这三路信号对应体表的哪两个或三个位置,也没有说明电极贴法。2012 年之前,这些字段甚至只写「record 14046, signal 0」,连 ECG 这个词都没有。

这个空白带来的后果很实际:任何声称「本库的 ECG1 相当于 II 导联」的说法都没有官方依据。它可能来自某篇论文的约定俗成,也可能是从波形形态上反推的猜测。做跨库迁移时,导联语义不清会直接影响结论——如果训练库用的是 II 导联、测试库的 ECG1 实际是改良胸导联,性能下降里就混进了导联错配的成分,而不只是人群差异。

实践上的处理办法有两条:一是明确声明「按信号序号对齐,不做解剖学假设」,二是在做跨库实验时,把导联语义不确定当作一个独立的误差源写进限制段落。两条都不难,难的是记得写。

还有一层更隐蔽的影响:导联语义不清会让人误判信号质量。Holter 的两路电极通常一路接近 II 导联、一路接近 V5 或 V1,不同位置对肌电与电极位移的敏感度不同。如果按「ECG1 是肢体导联、ECG2 是胸导联」的假设去设计降噪策略,而实际贴法相反,滤波器的通带选择就失去了依据。稳妥的做法是把两路信号各自的质量特征先算出来,再决定处理策略,而不是先假定再验证。

§3 它是谁的七段心跳:一家医院的磁带存档

3.1 贡献者与机构

数据库由麻省理工学院与波士顿贝斯以色列医院合作建设,PhysioNet 页面上标注的提交者是 George B. Moody,所属单位为 Harvard-MIT 健康科学与技术部。这个组合在 1990 年代的心电数据史上出现过很多次:医院提供临床记录,实验室提供数字化与标注的工程能力,两边共同把磁带上的模拟信号变成可计算的文件。

理解这个分工很重要。它意味着数据的采集场景由医院决定,标注规范由实验室决定,两者之间没有第三方审计。库里的每一条记录都是临床监护的副产品,不是为研究专门设计的采集方案。这也解释了为什么元数据只有年龄和性别两行——临床上顺手能拿到的就这些,其余的要去翻病历,而病历不在公开范围内。

3.2 时间线

时间 事件 依据
1999-08-03 v1.0.0 上线,七条记录开放下载 官方页面版本信息
2000-03-29 RECORDS 文件最后修改 目录文件时间戳
2000-10-13 ANNOTATORS 文件最后修改 目录文件时间戳
2000-11-29 旧版头文件 .hea- 最后修改 目录文件时间戳
2012-02-14 头文件重写,信号名改为 ECG1 至 ECG3 目录文件时间戳与新旧头文件对照
2019-02-20 增补 SHA256SUMS.txt 校验和清单 目录文件时间戳

这条时间线说明一件事:这个库在 1999 年上线之后就基本冻结了。2012 年的改动只动了头文件的信号名,信号与注释没有变化;2019 年补的只是校验和。二十多年里没有新增记录,也没有修订标注。对使用者来说,这既是好事也是坏事:好处是任何年份下载到的数据都一致,坏处是它的标注水平停留在 1999 年。

3.3 采集场景:一整天,两个电极

七条记录都是体表长时程监护,通俗说就是 Holter。受检者身上贴两到三个电极,便携记录仪挂在腰间,记录一整天的心电。这种记录方式的特点是自由活动带来的噪声:走路时的肌电、翻身时的电极位移、出汗导致的阻抗变化,全都会进到信号里。

这也正是它的价值所在。实验室里的心电信号是躺着不动录的,噪声可控;Holter 信号是生活状态录的,噪声不可控。检测算法在后者上的表现,才是它上线后真正会遇到的表现。库里的信号质量标记,恰好给这些噪声时段留了索引——标注者认为某处信号质量发生显著变化时,会在那个位置打一个波浪号。

3.4 数据来源的三个层次

层次 内容 是否公开 可信度
信号层 128 Hz 数字化后的两路或三路电压 公开,完整 高,可用校验和验证
标注层 心搏位置与类型、信号质量变化点 公开,完整 中,人工复核但无一致性报告
元数据层 年龄、性别、记录时间戳 部分公开,只有两行 中,无诊断、无用药、无随访

三层的信息量依次递减。信号层是完整的、可验证的;标注层是人工产物,质量取决于当时的复核流程;元数据层几乎为空。很多使用者在读完官方页面后会误以为这是一个「信息齐全的小库」,实际上它只有信号和标注齐全,临床上下文基本为零。

3.5 缺失的临床上下文值多少

对算法研究来说,诊断、用药、预后这三类信息通常用不上——检测器只关心波形与真值。但对另外两类工作,它们的缺失是硬伤。

第一类是临床相关性研究。想问「这个库里的室性异位负荷与年龄是否相关」,只有七组年龄、六男一女,连分组都做不了。想问「用药是否影响心率」,连用药字段都没有。这类问题必须换到带电子病历的库,比如 MIMIC 系的波形库。

第二类是弱监督与多任务学习。近几年的做法是把诊断文本当作弱标签,让模型同时学波形与报告。ltdb 没有报告、没有诊断、没有节律描述,这条路直接走不通。它的元数据只有两行,连最基本的「这条记录属于哪一类病人」都答不上来。

所以它的定位应该说得更准确一点:它是一个纯信号加逐搏真值的库,而不是一个临床数据集。把它当临床数据集用,会在第一步就卡住;把它当纯信号的基准用,它的完整度反而比很多新库更高,因为新库常常有大量字段是空的或不可靠的。

§4 它最独特的东西:128 Hz 下的一整天

4.1 为什么这个组合少见

长时程与低采样率的组合,在今天反而变少了。新采的长时程记录普遍用 250 Hz 甚至更高,因为存储便宜了;老记录的 128 Hz 是当年磁带容量与数字化成本的折中。结果是:想要「原生低采样 + 原生长时程」的公开数据,可选的范围很窄,ltdb 与 ltafdb 是其中最主要的两处。

这个组合对应一类具体的工程问题:可穿戴设备的功耗预算。采样率减半,模数转换与无线传输的功耗都跟着降,但 R 峰定位的精度也会降。想量化这个折中的代价,最干净的做法是拿一条原生 128 Hz 的长时程记录当基准,再把它降采样到 64 Hz、32 Hz,看检测器在每一档上的表现如何衰减。用 250 Hz 的记录降采样也能做同样的事,但那多了一层重采样滤波的影响,结论不再纯粹。

4.2 标注只有两层:心搏与信号质量

官方在 ANNOTATORS 里把注释文件的内容写成一句话:参考的心搏标注与信号质量标注。逐个读取七条记录的注释后可以确认,符号集合就是 N、V、F、J、S、a 六类心搏,外加波浪号这一类质量标记;辅助注释字符串全部为空。

标注层次 ltdb 是否提供 对应任务
心搏位置 提供 检测、R 峰定位、心率变异性
心搏类型 提供,六类为主 心搏分类、异位搏动筛查
信号质量变化 提供,波浪号标记 噪声区段定位、质量感知建模
节律段(如房颤、窦性停搏) 不提供 节律分类、事件检测
ST 段偏移与缺血事件 不提供 缺血检测、动态 ST 分析
逐段诊断文本 不提供 弱监督、多任务学习

这张表可以直接当决策依据用:需求落在前三行,它够;落在后三行,它不够。很多人拿到库之后先写模型再想标签,结果在节律任务上折腾很久才发现标注里根本没有这一层。

4.3 案例:15814 这一条为什么特殊

七条记录里,15814 是唯一的三导联记录,也是唯一的 310 存储格式。它的头文件第一行写三个信号,每个信号行结尾是 310 0 10——三路 10 位量化,与其余六条的 212 0 12 不同。这个差异会直接打穿一批粗糙的读取脚本。

第一层影响在读文件。按 212 格式写的解析器假定每三个字节装两个 12 位采样点,遇到三路 10 位打包就会读出乱码,而且不会抛异常,只会得到一条幅度离谱的波形。用 wfdb 这类成熟库不会出问题,因为它按头文件里的格式码分派解析器;自己写二进制解析的人则必须按格式码分支。

第二层影响在内存布局。三导联记录的数组形状是「采样点 × 3」,其余是「采样点 × 2」。任何把七条记录 np.concatenate 成大矩阵的做法都会在这一条上失败,或者更糟——静默地把三列压成两列。

第三层影响在统计口径。15814 的受检者是 58 岁男性,记录时长 22.22 小时,注释约十万条。它单独构成了「三导联」这个子集,而这个子集只有一个样本。任何关于「三导联比双导联好多少」的结论,在这个库上都无法成立,因为对照组只有一条记录。

§4.3 的案例在后续章节还会出现:§5.3 会用它说明流式读取时的形状处理,§7.3 会用它说明「子集方差」这类偏差。它的意义不在于它多特殊,而在于它证明了「七条记录里就有一条不符合默认假设」,而这个比例在真实数据里从来不低。

4.4 人工复核意味着什么

官方页面用的词是 manually reviewed beat annotations,即经人工复核的心搏标注。这句话包含的信息比看起来多:标注不是纯自动生成的,有人看过;但也没有说明复核了几遍、几个人、一致性如何。

对比一下同族的其他库就能看出差别。ltstdb 的文档里明确写了标注由有经验的心电技师完成,并有复核流程;incartdb 明确写了自动初标加人工修正,且位置未逐条校正。ltdb 只有「人工复核」四个字,没有更多。

这对使用者的实际影响是:可以假定心搏类型大体可靠,但不能假定位置精确到采样点,也不能假定七条记录的复核标准完全一致。做 RR 间期类分析时,建议先用自己的检测器重新定位 R 峰,再把官方标注当作类型参考而不是时刻真值。

4.5 边界条件:什么情况下它不再适用

第一,需要节律标签的任务。没有就是没有,构造出来的标签必须自己承担可复现性的责任。

第二,需要人群统计的任务。七组年龄,六个男性,全部来自 1990 年代初的波士顿。任何「在一般人群中如何」的表述都超出了它的证据范围。

第三,需要高时间分辨率的任务。128 Hz 决定了 7.8 毫秒的量化台阶,QRS 宽度这类几十毫秒量级的测量会带上可观的相对误差。

第四,需要训练数据的任务。七条记录不足以支撑任何带参数的模型,除非做的是少样本或元学习,而那类研究本身也需要更大的元训练集。

§5 怎么拿到:两百兆之内的完整闭环

5.1 目录结构与下载面

整个库是一个平铺目录,没有子文件夹。七个记录各三个文件,加上七个旧版头文件、七个会话文件,再加快照清单与校验和,一共不到四十个文件。官方页面提供三种获取方式:网页逐文件下载、整库 ZIP、以及从开放存储桶同步。

路径 内容 大小
/files/ltdb/1.0.0/RECORDS 七行记录名 42 字节
/files/ltdb/1.0.0/ANNOTATORS 一行注释角色说明 50 字节
/files/ltdb/1.0.0/SHA256SUMS.txt 逐文件校验和 2.7 KB
/files/ltdb/1.0.0/<记录>.hea 头文件 约 120 字节
/files/ltdb/1.0.0/<记录>.dat 信号本体 18 至 39 MB
/files/ltdb/1.0.0/<记录>.atr 注释 97 至 290 KB
/files/ltdb/1.0.0/<记录>.hea- 2012 年前的旧头文件 约 150 字节
/files/ltdb/1.0.0/<记录>.xws WaveBox 会话文件 90 字节

5.2 批量下载

#-- 整库拉取,保留目录结构;两百兆,普通带宽几分钟
wget -r -N -c -np https://physionet.org/files/ltdb/1.0.0/

#-- 或者只取记录清单与头文件,先看清结构再决定下哪些
for f in RECORDS ANNOTATORS; do
  curl -sL "https://physionet.org/files/ltdb/1.0.0/$f" -O
done
for r in $(cat RECORDS); do
  curl -sL "https://physionet.org/files/ltdb/1.0.0/$r.hea" -O
done

#-- 下完核对完整性,避免半截文件
sha256sum -c SHA256SUMS.txt

第三条命令会逐个文件比对校验和。整库只有两百兆,这个检查几乎不花时间,却能挡住最常见的失败模式:.dat 下到一半连接断了,文件大小看起来正常,读出来的信号尾部全是零。

5.3 用 wfdb 直接流式读取

不想落盘时,可以让 wfdb 直接从 PhysioNet 读取。它对 .dat 是按需拉取的,取一段就只下一段:

import wfdb

#-- pn_dir 指向 PhysioNet 上的库名,无需本地副本
rec = wfdb.rdrecord('15814', pn_dir='ltdb', sampto=128 * 600)
print(rec.sig_name, rec.p_signal.shape, rec.fs)
#-- ['ECG1', 'ECG2', 'ECG3'] (76800, 3) 128

注意这里的形状是「采样点 × 3」,与其余六条记录的「采样点 × 2」不同。写批处理循环时,正确做法是按记录逐条处理并在末尾拼接统计结果,而不是先把所有记录堆成一个数组。§4.3 的案例说的就是这件事:形状不一致在七条记录里出现了一次,比例是七分之一。

5.4 转成通用的表结构

把 WFDB 转成 Parquet 或 NumPy 归档是常见需求,转换时最容易丢的是三样东西:增益、采样率、注释类型码的原始字符。

import wfdb
import numpy as np
import pandas as pd

rows = []
for name in wfdb.get_record_list('ltdb'):
    rec = wfdb.rdrecord(name, pn_dir='ltdb')
    for i, lead in enumerate(rec.sig_name):
        rows.append({
            'record': name,
            'lead': lead,
            'fs': rec.fs,
            'n_samples': rec.sig_len,
            'gain': rec.adc_gain[i],
            'units': rec.units[i],
            'v_min': float(rec.p_signal[:, i].min()),
            'v_max': float(rec.p_signal[:, i].max()),
        })

df = pd.DataFrame(rows)
print(df.groupby('record').size())
df.to_parquet('ltdb_index.parquet', index=False)

这段代码只导出索引,不导出波形——波形留在 .dat 里,需要时按段读取。这样做的好处是索引只有几十行,可以随项目一起版本管理,而信号本体不必进仓库。

5.5 心搏注释的读取与 AAMI 映射

把六类符号映射到 AAMI 五分类是心电算法的通行做法,映射表本身不长,但要注意符号的边界:

import wfdb

AAMI = {'N': 'N', 'L': 'N', 'R': 'N', 'B': 'N', 'A': 'S', 'a': 'S',
        'J': 'S', 'S': 'S', 'V': 'V', 'r': 'V', 'F': 'F', 'f': 'F'}

for name in wfdb.get_record_list('ltdb'):
    ann = wfdb.rdann(name, 'atr', pn_dir='ltdb')
    beats = [(s, AAMI.get(sym, 'Q')) for s, sym in zip(ann.sample, ann.symbol)]
    quality = sum(1 for sym in ann.symbol if sym == '~')
    print(name, len(beats), quality)

映射里有一个坑:波浪号不是心搏,若把它一起映射进 Q 类,会把信号质量标记当成无法分类的心搏,多算一批样本。上面的代码把 ~ 单独计数,正是为了避免这件事。另一个坑是 a 与 A 是两个不同的码,前者是差异性房性早搏,后者是房性早搏,二者都归入 S 类,但混用时统计会失真。

5.6 五个最容易出错的地方

出错点 表现 处理
假设所有记录都是双导联 15814 读成两列,第三路丢失 按头文件信号条数分支
假设格式码都是 212 310 记录被解析成乱码 按 rec.fmt 分派解析器
直接拿增益字段做除数 增益写 0,除零或全零 0 按缺省 200 处理
把波浪号当心搏 注释总数虚高,Q 类混入非心搏 先按符号过滤再映射
用 d_signal 当毫伏 数值差两百倍,不报错 显式用 p_signal

这五条都不是理论问题,而是初次接触这个库时最常见的失败点。它们的共同特征是「不抛异常」——脚本能跑完,结果看着也像样,只是数字错了。

5.7 本地缓存与远程读取的取舍

wfdb 支持两种拿到数据的方式:远程直读与本地缓存。远程直读的写法最省事,pn_dir='ltdb' 一行就能取到;它的代价是每次读取都会重新建立连接,训练循环里逐样本调用会把时间全花在网络上。本地缓存的代价是占盘,但整库只有两百兆,这点代价可以忽略。

方式 适合场景 代价 注意
远程直读 探索性分析、一次性核对结构 每次读取要建连接,慢 断网即失败,不适合长跑
整库下载 训练、批量评估、离线环境 占盘两百兆 下完必须校验
按记录下载 只关心其中几条 需要自己拼列表 容易漏掉 .atr
存储桶同步 需要与上游保持同步 需要对象存储命令行 路径前缀固定

一个实用的折中做法是:先用远程直读把七条记录的头文件全部读一遍,确认结构,再把整库一次下到本地,之后所有批量任务都在本地跑。这样既避免了反复下载,也不会在还没弄清结构时先花时间下数据。

还有一个细节值得注意:pn_dir 的参数可以直接写库名,wfdb 会自动解析到最新版本;如果结果需要长期复现,建议写成带版本号的路径,避免上游更新后数据悄悄变了。本库自 1999 年以来只有头文件在 2012 年改过一次,风险很小,但这个习惯对同族的其他库是必要的。

§6 与库内条目的关系

6.1 关系图谱

关系 库 连接点 差异
同机构同期 ltstdb 同一家医院、同一套格式、同一批磁带来源 86 条记录、250 Hz、另有 ST 与节律标注
同格式同注释码 mitdb WFDB 格式与 MIT-BIH 注释码完全一致 48 段半小时、双导联、采样率 360 Hz
同为长时程房颤 ltafdb 都是 128 Hz、二十余小时 84 条、有节律标注、专为房颤设计
同为长时程房颤 afdb 都是双导联 Holter 25 条、每条 10 小时、250 Hz、有节律标注
同为多导联短段 incartdb 都可用于心搏分类 12 导联、每段 30 分钟、257 Hz
同为低采样率 ecgrdvq 采样率低、记录较长 侧重 QT 与药物复极,标注体系不同

6.2 检索路径

在站内找同族库,最直接的办法是按标签与关键词检索,而不是按名称。名称里的 long-term、LT、Holter 三种写法混用,按名称匹配必然漏。

#-- 按关键词粗筛库内词条,注意 long-term 与 holter 是两种写法
bash scripts/qf_psql.sh "select record_id, url_name, left(title,60)
  from ai_ready_dataset
  where url_name ilike '%lt%' or title ilike '%长时程%' or title ilike '%Holter%'
  order by record_id;"
import wfdb

#-- 按官方清单确认本库的七个记录名,避免凭记忆写错
print(wfdb.get_record_list('ltdb'))
#-- ['14046', '14134', '14149', '14157', '14172', '14184', '15814']

检索时的一个经验:PhysioNet 上叫 long-term 的库至少有四个(ltdb、ltstdb、ltafdb,以及记录时长同样很长的挑战赛数据),它们的区别不在名字,而在标注层。判断一个库能不能做你的任务,先看 ANNOTATORS 那一行写了什么,比看简介快得多。

6.3 与其他长时程库的分工判据

你的任务 首选 次选 判据
长时程心搏检测的快速验证 ltdb incartdb 体量最小、全流程最快
低采样率鲁棒性 ltdb ltafdb 原生 128 Hz,双导联
房颤负荷量化 ltafdb afdb 有节律标注,24 小时级
心肌缺血事件检测 ltstdb 无 只有它标了 ST 事件
十二导联形态学 incartdb 无 只有它给满十二导联
跨库外部验证 任一异源库 — 关键在来源不同,不在规模

6.4 三张库的规模差背后是什么

同族长时程库里,三个数字最容易被拿来比:七条、八十六条、八十四条。差别不在采集能力,而在各自要回答的问题。

ltdb 的七条是最早的一次尝试,目标是证明「长时程逐搏标注」这件事在工程上可行。它不需要多,只需要完整——完整到能跑通从信号到评估的每一步。ltstdb 的八十六条是为了做缺血检测器的验证:缺血事件稀疏,需要有足够多的记录才可能积累出足够的事件数,所以规模必须上去,采样率也必须提到 250 Hz 才能测 ST 段的毫伏级偏移。ltafdb 的八十四条是为了房颤负荷:阵发性房颤的发作本身就是稀疏事件,同样需要长时程与足够多的受试者。

库 规模动因 由此决定的采样率 由此决定的标注层
ltdb 证明流程可行 128 Hz,够定位 R 峰即可 心搏与质量两层
ltstdb 积累缺血事件 250 Hz,需测 ST 偏移 四层,含 ST 与节律
ltafdb 积累房颤发作 128 Hz,节律判定不依赖高采样 心搏与节律两层

这张表解释了一个常被忽略的因果:采样率不是随便定的,而是被任务倒推出来的。理解这一点,就不会拿 ltdb 去做 ST 分析,也不会抱怨它为什么没有 250 Hz。

6.5 什么时候该放弃它

有三种情形,越早放弃越省时间。第一种是任务需要节律或 ST 标签,这在前面已经说过。第二种是需要统计显著性——七条记录做不出置信区间,硬做只会得到看似严谨实则无意义的数字。第三种是需要与临床变量联动,因为它没有临床变量。

反过来,有三种情形它几乎是最优解:需要在半天内跑通一条完整长时程链路;需要验证低采样率对检测的影响;需要一个与训练库完全不同源的小型外部集。前两种是工程需求,第三种是方法学需求,三者都不依赖规模。

§7 质量评估与局限性

7.0 阅读本节前的一个前置校正

先纠正一个容易发生的误判:把「小」直接读成「差」。七条记录在规模维度上确实拿不到分,但这不等于它在自己的用途上也差。规模小是这个库的设计前提,不是执行失误——1999 年的存储与带宽决定了它只能这么大,而它的用途从第一天起就是「完整流程的最小可用集」,不是「训练语料」。

第二个需要校正的误判是「老」。1999 年的标注流程放到今天看确实粗糙,没有一致性系数、没有双人复核记录、没有仲裁机制。但它的信号是真实的临床长时程记录,这一点不会因为年代久远而失效。评价它的时候,尺度应该是「在它能回答的问题上,证据够不够硬」,而不是「它比新库少了哪些字段」。

第三个小一点的误判是「只有七条所以不能做统计」。七条记录当然不能做人群推断,但可以做逐条的方法对比——同一批记录上比较两个检测器,结论是有效的,只是不能外推到人群。这两件事经常被混为一谈。

7.1 五维评分

按 DAIMS 的常用维度打分,每项 1 至 5 分,针对「作为长时程心电算法研究数据」这个用途:

维度 分数 理由
数据规模 1 七条记录,最多七人,无法支撑训练
标注质量 3 经人工复核,但无一致性报告,位置精度未知
任务适配 3 心搏检测与质量感知适配好,节律与缺血完全不适配
文档完整 2 官方页面只有一段简介,标注协议、导联、人群都未说明
可获取性 5 免注册、两百兆、无依赖,一次下完

五项合计 14 分(满分 25)。这个分布很有辨识度:可获取性拉满,规模与文档垫底,标注与适配居中。它说明这是一个「拿来就能用、但用完别多想」的库。

7.2 标注质量的两层

第一层是类型正确性。六类心搏码都是 MIT-BIH 标准码,含义明确,映射到 AAMI 五分类的路径也是通的。人工复核这一环保证了明显的错标不会太多,这一层可以打到中上。

第二层是位置精度与覆盖完整性。官方没有说明复核是否逐搏、是否校正了 R 峰位置,也没说明质量标记的判定标准。逐条读取注释后还能看到一处覆盖缺口:14149 的最后一条注释落在 23.19 小时,而信号总长 23.87 小时,末尾约四十分钟没有任何标注。这四十分钟是信号丢失、还是标注者提前收工,官方没有说明。

用途 类型层够不够 位置层够不够 建议
心搏检测 够 够 可直接当参考
心搏分类 够 够 注意类别极不均衡
心率变异性 够 勉强 建议自检测重定位
QRS 宽度测量 勉强 不够 128 Hz 误差过大
噪声鲁棒性 够 不适用 用质量标记切段

7.3 已知的、可枚举的偏差

偏差 表现 影响
规模偏差 七条记录,最多七人 任何模型都会过拟合,结论不可外推
性别偏差 六男一女 女性样本只有一条,性别相关分析不可做
年龄偏差 46 至 88 岁,无年轻人 不代表一般人群,尤其不代表青年
地域与年代偏差 1990 年代初波士顿单中心 设备、贴电极习惯、判读标准都单一
采样率偏差 128 Hz 形态学指标精度受限
导联语义缺失 只写 ECG1 至 ECG3 跨库对齐时导联错配无法排除
标注覆盖缺口 14149 末尾约四十分钟无标注 该段不能计入任何逐搏统计
官方口径不一致 官方称 14 至 22 小时,头文件换算 13.9 至 23.9 小时 规划存储与切片时以头文件为准
子集方差 三导联子集只有一条记录 「三导联 vs 双导联」类结论不成立

关于官方口径的那一条,需要说清两个数各自的来处:官方简介写的是每条 14 到 22 小时,而头文件里的采样点数除以 128 给出了 13.9 到 23.9 小时的范围,其中 14046 与 14149 都超过了二十二小时。两个口径的差额构成,官方没有解释。用的时候按头文件算,因为下游切片、分窗、批大小都依赖采样点数。

7.4 外部验证矩阵

验证角色 做法 讲得通的地方 风险
跨库心搏分类 在大库训练,本库零样本测试 注释码同源,映射直接 掉分里混了人群、设备、采样率三重差异
低采样率对照 本库原生 128 Hz,与 250 Hz 库对照 变量单一,结论干净 两个库的人群本来就不同
噪声鲁棒性 按质量标记切出噪声段单独评估 质量标记是现成的索引 标记稀疏,切出的段可能很少
少样本学习 用七条记录做 few-shot 目标域 域差异真实 七条不足以做统计检验
教学与演示 单条完整记录走通全流程 体量小,学生能一次跑完 结论不能当研究成果

跨库外测是它最常被引用的用法。这类研究的基本逻辑是:在一个数据量大、来源单一的库上训练,换到这个来自另一家医院、另一套设备的库上测试,掉多少分就代表泛化损失多少。ltdb 在这个位置上有一个天然优势——它的采样率是 128 Hz,比多数训练库低,任何忽略采样率差异的模型都会在这里暴露。

反过来,也要防止把外测成绩当绝对标准。七条记录的样本量太小,一次划分的偶然性足以颠倒两个模型的排名。合理的做法是固定记录集合、固定预处理、只改模型,在同一份数据上比较相对差异。

7.5 它为何能持续:最小的完整样本

它二十多年没有更新,却仍在被下载与引用,原因是它占着一个不会被新库挤掉的位置:能在一个下午走完全流程的最小长时程集。新库可以更大、更干净、标注更细,但只要有人需要「先跑通再说」,两百兆的七条记录就仍然是最省事的选择。这个位置不靠规模支撑,靠的是体量与完整度的比值。

§8 生态位与历史

8.1 历史沿革

1999 年上线时,PhysioNet 上的心电库还以半小时段为主,MIT-BIH 心律失常库是绝对的核心。ltdb 的加入第一次把「整天」这个尺度带进了公开数据集。它的技术底座——WFDB 格式、MIT-BIH 注释码、开放下载——后来被同族的所有库沿用,包括一年后上线的 ltstdb。

这个先后顺序值得记住,因为它解释了很多细节的由来。ltdb 的头文件信息极少,是因为当年的元数据规范还没成形;它的注释只有心搏与质量两层,是因为当时的关注点就是「检测器能不能在长时程里稳定工作」,节律与缺血的分析需求是后来才被提出来的。

8.2 与 ST 库的关系:同一批磁带,不同的野心

ltstdb 于 2000 年 11 月上线,比 ltdb 晚一年,同样是 MIT 与波士顿贝斯以色列医院的合作产物。它把标注扩到了四层:逐搏、ST 事件、节律变化、信号质量,每条记录 21 至 24 小时,带 2 或 3 路信号,采样率 250 Hz,最终扩到 86 条。2003 年先开放一半,2007 年补齐全部。

维度 ltdb ltstdb
上线时间 1999-08-03 2000-11-29
记录数 7 86
每条时长 14–24 小时 21–24 小时
采样率 128 Hz 250 Hz
逐搏标注 有 有
ST 事件标注 无 有
节律变化标注 无 有
信号质量标注 有 有
体量 205.4 MB 数 GB

两个库的关系常被误解成「旧版与新版」。官方的记录名体系完全不同(ltdb 是五位数字,ltstdb 是另一套编号),也没有任何文档说二者共享受试者。更准确的说法是:它们出自同一家医院的不同时期存档,目标不同——一个证明长时程心搏标注可行,一个把缺血事件也纳入标注。

8.3 生态位:入门件而不是主力件

角色 主力件 入门件
典型用途 训练、预训练、大规模评测 流程验证、教学、快速基线
需要的前提 数据量大、标签细 体量小、格式标准、一次下完
代表库 mitdb、ltafdb、mimic 系心电 ltdb、incartdb
失败模式 过拟合、标签噪声累积 结论不可外推、统计不显著

ltdb 坐在右边这一列。把它当主力件用,会在第一轮就过拟合;把它当入门件用,几乎没有替代品——比它更小的库通常不够长,比它更长的库通常要大一个数量级。

8.4 谁在用它,用来做什么

从公开文献的摘要看,使用者集中在三类。第一类是信号处理组,用它验证检测器在长时程、低采样率条件下的稳定性,常与 250 Hz 的库做对照。第二类是可穿戴与嵌入式组,用它做功耗与精度的折中实验,因为原生 128 Hz 正好对应低功耗设备的采样档位。第三类是教学,用它做「一条完整记录从读到用」的演示,因为它小到可以让学生人手一份。

这三类用法有一个共同点:都不指望它提供统计结论,只指望它提供完整链路。这个定位一旦清楚,它的所有局限就都变得可接受。

§9 使用指引

9.1 三种角色的路径

角色 第一天 第一周 注意事项
算法研究者 读官方页面与七个头文件,跑通 §5.3 的读取 建立逐记录基线,做 128/64/32 Hz 三档对照 先确认注释里没有节律层(§4.2)
设备工程师 抽一条记录做端到端推理,测每小时的误检 用质量标记切噪声段,单独报告该段指标 不要假设 ECG1 是 II 导联(§2.6)
教学与临床工程 用 14046 做一次完整演示 让学生自己写解析器,体会格式码分支 14149 末尾有约四十分钟空档

9.2 一条最短的可用流程

#-- 1. 取清单与头文件,先看结构
curl -sL https://physionet.org/files/ltdb/1.0.0/RECORDS -o RECORDS
curl -sL https://physionet.org/files/ltdb/1.0.0/ANNOTATORS -o ANNOTATORS
cat ANNOTATORS

#-- 2. 只下第一条记录,验证读取链路
for ext in hea dat atr; do
  curl -sL "https://physionet.org/files/ltdb/1.0.0/14046.$ext" -O
done

#-- 3. 核对采样点数与时长
awk 'NR==1{printf "%s  %.2f h\n", $1, $4/$3/3600}' 14046.hea
import wfdb

#-- 读信号与注释,确认没有节律层
rec = wfdb.rdrecord('14046')
ann = wfdb.rdann('14046', 'atr')
print(rec.fs, rec.sig_name, rec.p_signal.shape)
print(sorted(set(ann.symbol)), sum(1 for a in ann.aux_note if a.strip()))

跑完这两段,就已经走完了「下载、读取、确认结构」三步。剩下的工作是把同一套代码套到其余六条记录上,并在 15814 那一条上处理三导联分支。

9.3 引用方式

引用对象 内容 说明
数据集 MIT-BIH Long-Term ECG Database, version 1.0.0. PhysioNet. 1999. 必须带版本号
标识符 DOI 10.13026/C2KS3F 指向 v1.0.0
平台 PhysioNet 平台综述论文,按页面 Cite 按钮生成 官方页面唯一给出的引用
许可 ODC-BY 1.0,署名即可,含商业用途 以许可全文为准

需要特别说明:官方页面没有为本库提供专属的论文引用,只有平台层面的标准引用。这意味着写论文时,引用列表里出现的是数据集著录加平台论文,而不是一篇描述该库的方法学文章。这在同族库里并不罕见,但对希望引用「原始采集方法」的人来说是个缺口。

§10 AI 使用声明

项目 声明
文本生成 本文由 AI 辅助撰写,结构与事实由编辑把关
数字来源 规模、结构、边界三类数字来自 PhysioNet 官方页面与库内文件
文件核验 七个头文件、七个注释文件、RECORDS、ANNOTATORS 均经直接访问确认
统计口径 时长由采样点数除以 128 换算,注释总量为逐文件读取后相加
未采用 未做标签频次排序、未做长度分布直方图、未做字段空值交叉表
论文信息 仅检索 Europe PMC 摘要,未读全文
未核验内容 标注者人数与一致性、导联对应的体表位置、14149 末尾空档的成因
免责 本文不构成临床建议;使用须遵守 ODC-BY 1.0 署名要求

常见误读(避坑清单)

说法 实际 证据
「ltdb 就是 ltstdb 的旧名」 是两个独立的库,记录名体系与标注层都不同 官方两个页面并存,DOI 不同
「它有 ST 事件标注」 没有,只有心搏与信号质量 ANNOTATORS 只写 beat 与 signal quality
「它是二十四小时双导联」 六条双导联,一条三导联;时长为 14 至 24 小时 15814.hea 有三个信号行
「它的采样率是 250 Hz」 128 Hz 每个头文件第一行第三字段
「头文件增益是 0,说明数据没标定」 0 是缺省值,实际按每毫伏 200 单位 WFDB 规范;adc_gain 读出 200
「ECG1 就是 II 导联」 官方从未说明导联位置 头文件只写 ECG1 至 ECG3
「七条记录来自七个人」 官方未公布受试者数,也没给映射 官方简介只写七条记录
「注释总数就是心搏数」 里面混着信号质量标记 符号集合含波浪号
「可以直接拿它训练分类器」 七条记录,一两轮即过拟合 记录清单仅七行
「官方说的时长就是头文件时长」 官方 14 至 22 小时,头文件 13.9 至 23.9 小时 采样点数除以 128 的换算结果

FAQ

Q1:ltdb 和 ltstdb 到底差在哪?
差在记录数、采样率与标注层。ltdb 七条、128 Hz、只标心搏与信号质量;ltstdb 八十六条、250 Hz、另标 ST 事件与节律变化。两个库都出自波士顿同一家医院,但记录名体系不同,官方未说明受试者是否重叠。

Q2:它能做房颤检测吗?
不能直接做。注释里没有节律段,只有心搏类型与质量标记。要做房颤,只能从 RR 间期序列间接构造标签,而构造规则必须写清楚,否则结论不可复现。

Q3:为什么只有七条记录还能一直有人用?
因为它是最小的完整长时程样本:下载快、格式标准、注释齐全到心搏级。它适合验证流程与做对照,不适合训练与统计推断。

Q4:头文件里的增益写 0,是不是数据坏了?
不是。WFDB 规定增益字段为 0 时按缺省 200 处理。成熟库读出来就是 200,自己写解析器的人直接拿 0 做除数才会出错。

Q5:七条记录是七个人吗?
官方没有公布受试者数,也没有记录与人的映射。头文件给出七组年龄与性别,数值互不相同,但这不足以证明一一对应。做统计时应把记录当独立单位,并在文中声明。

Q6:ECG1、ECG2 对应哪两个导联?
官方未说明。2012 年之前的头文件甚至只写「signal 0」「signal 1」。任何把 ECG1 当作 II 导联的说法都是外部约定,不是官方信息。

Q7:标注准确吗?
心搏类型的可靠性较高,因为经人工复核;位置精度与覆盖完整性未知,官方没有一致性报告。14149 末尾还有约四十分钟没有标注,那段不能计入逐搏统计。

Q8:128 Hz 够用吗?
对 R 峰检测够用,对形态学测量不够。7.8 毫秒的采样间隔会让 QRS 宽度、QT 间期这类指标带上明显误差。要做形态学,换采样率更高的库。

Q9:能一次下完吗?要注册吗?
能,未压缩两百零五兆,无需注册,ODC-BY 1.0 直接下载。官方提供整库压缩包、逐文件下载与存储桶同步三种方式。

Q10:和 MIT-BIH 心律失常库是什么关系?
格式与注释码同源,都是 WFDB 加 MIT-BIH 标准码,但记录数、时长、采样率、人群都不同。它常被当作该库训练出的模型的外部测试集。

Q11:为什么官方说的时长和头文件对不上?
官方简介写 14 至 22 小时,头文件换算给出 13.9 至 23.9 小时,其中两条超过二十二小时。差额的构成官方没有解释,下游规划应以头文件为准。

术语表

术语 解释
Holter 便携式长时程心电监护,受检者随身携带记录仪
ltdb MIT-BIH Long-Term ECG Database 的官方缩写
ltstdb Long-Term ST Database,同机构带 ST 事件标注的库
WFDB PhysioNet 使用的波形数据库格式
.hea 纯文本头文件,声明采样率、增益、信号名与患者信息
.dat 二进制信号文件,按格式码打包
.atr 二进制注释文件,存事件位置与类型
.hea- 2012 年改写前的旧版头文件,保留在目录中
.xws WaveBox 网页工具的会话文件,仅三行
格式码 212 双信号 12 位,两个采样点压进三个字节
格式码 310 三信号 10 位,三个采样点压进三个字节
增益 每毫伏对应的整数单位数,0 表示缺省 200
基线 零电平对应的整数值,换算时先减
校验和 采样点累加和,用于检测文件完整性
逐搏标注 对每一次心搏标出位置与类型
信号质量标记 波浪号,表示该处信号质量发生变化
AAMI 五分类 N、S、V、F、Q 五组,心电算法评价的通行分组
房颤 心房电活动紊乱,心室率绝对不规则
ST 事件 心电复极段偏移达到判定阈值的持续时段
导联错配 训练与测试用的体表导联位置不同
患者级划分 同一受试者的记录只进训练或只进测试
跨库测试 在一个库训练、另一个库测试,衡量泛化
ODC-BY 开放数据共享署名许可
PhysioNet 由 MIT 等机构维护的生物医学信号平台

附录 A:核心数字核对表

项 值 来源 来源层级
记录数 7 官方页面;RECORDS 逐行 官方页面
受试者数 官方未公布 官方页面 官方页面
每条时长 14–22 小时 官方页面 官方页面
头文件换算时长 13.9–23.9 小时 七个 .hea 采样点除以 128 官方文件
导联数 2 或 3 七个 .hea 第一行 官方文件
三导联记录 15814 15814.hea 官方文件
采样率 128 Hz 七个 .hea 第一行 官方文件
量化位宽 12 位,三导联记录 10 位 .hea 信号行 官方文件
增益 每毫伏 200 单位 .hea 增益字段 0 加缺省规则 官方文件
注释总量 约六十七万条 七个 .atr 逐条读取后相加 本次核对
注释符号 N、V、F、J、S、a、~ 七个 .atr 符号集合 本次核对
年龄范围 46–88 岁 七个 .hea 注释行 官方文件
性别构成 六男一女 七个 .hea 注释行 官方文件
上限单文件 39.1 MB 目录列表 官方页面
整库体积 205.4 MB 官方页面 官方页面
上线日期 1999-08-03 官方页面 官方页面
许可 ODC-BY 1.0 官方页面 官方页面
DOI 10.13026/C2KS3F 官方页面 官方页面

附录 B:数字的来源分层

第一层:官方页面与官方文件。 记录数、时长区间、导联数、采样率、体积、日期、许可、DOI 来自官方页面;每条记录的采样点数、年龄、性别、格式码来自七个头文件;注释角色来自 ANNOTATORS。这一层的数字可以直接引用。

第二层:本次核对。 逐条注释条数、注释符号集合、标注覆盖的首尾位置、换算得到的逐条时长。这些数字不改变官方结论,只是把官方没展开的部分补上。引用时应写明「根据库内文件统计」,不要写成官方口径。

第三层:未核实。 标注者人数与一致性、导联对应的体表位置、14149 末尾空档的成因、记录与受试者的映射关系。这些官方从未公布,正文中凡涉及处只做定性表述或标注为未知。

附录 C:完整参考文献

编号 文献 链接 用途
1 MIT-BIH Long-Term ECG Database v1.0.0 https://physionet.org/content/ltdb/1.0.0/ 规模、结构、边界数据的主来源
2 该库文件目录 https://physionet.org/files/ltdb/1.0.0/ 七组文件、清单、校验和
3 Long-Term ST Database v1.0.0 https://physionet.org/content/ltstdb/1.0.0/ §8.2 的对照事实
4 Jager F 等,Long-term ST database,MBEC 41(2):172-183,2003 https://doi.org/10.1007/BF02344885 ltstdb 的方法学说明
5 PhysioNet 平台综述,Nature Health,2026 https://doi.org/10.1038/s44360-026-00096-z 托管模式与引用规范
6 WFDB 格式与注释码规范 https://physionet.org/physiotools/wag/ 格式码、增益缺省规则
7 Europe PMC 检索结果 https://www.ebi.ac.uk/[europepmc](https://www.qianfanghub.com/ai-ready-dataset/europepmc/1353)/ 外部用法与验证角色
8 库内词条:MIT-BIH 房颤库 https://physionet.org/content/afdb/ §2.5 与 §6.1 的对比

附录 D:任务代码

任务一:七条记录的完整索引

import wfdb
import pandas as pd

rows = []
for name in wfdb.get_record_list('ltdb'):
    h = wfdb.rdheader(name, pn_dir='ltdb')
    rows.append({
        'record': name,
        'leads': h.n_sig,
        'fmt': h.fmt[0],
        'fs': h.fs,
        'samples': h.sig_len,
        'hours': round(h.sig_len / h.fs / 3600, 2),
        'age': h.comments[0].split('Age:')[1].split()[0],
        'sex': h.comments[0].split('Sex:')[1].strip(),
    })

print(pd.DataFrame(rows).to_string(index=False))

任务二:降采样后的检测召回对照

import wfdb
import numpy as np

def resample_decimate(x, factor):
    #-- 简单抽取,不做抗混叠;用于演示采样率对定位的影响
    return x[::factor]

for name in ['14046', '14172']:
    rec = wfdb.rdrecord(name, pn_dir='ltdb', sampto=128 * 3600)
    ann = wfdb.rdann(name, 'atr', pn_dir='ltdb', sampto=128 * 3600)
    truth = set(ann.sample)
    for factor in (1, 2, 4):
        x = resample_decimate(rec.p_signal[:, 0], factor)
        fs = rec.fs // factor
        #-- 以极简阈值法示意:超过三倍标准差的局部极值算一次候选
        thr = 3 * np.std(x)
        cand = np.where(np.abs(x) > thr)[0] * factor
        hit = sum(1 for c in cand if min(abs(c - t) for t in truth) <= fs // 4)
        print(name, 'factor', factor, 'candidates', len(cand), 'matched', hit)

第二段代码的用途是演示,不是评测:它的候选点没有做不应期抑制,也没有做多导联融合,命中判据用的是四分之一秒的宽松窗。把它跑一遍能看到的是「采样率降低时定位误差如何累积」这个趋势,而不是一个可以写进论文的召回率。

附录 E:如果只记五件事

序号 记住什么 为什么
1 七条记录,14–24 小时,128 Hz,双导联为主 这四个数字定义了一切用法与限制
2 只有心搏与信号质量两层标注 节律与缺血任务直接出局
3 它是入门件,不是主力件 用来跑通流程与做对照,不用来训练
4 15814 是三导联 310 格式 批处理脚本必须按格式码分支
5 官方时长口径与头文件换算不一致 下游规划一律以采样点数为准

编辑说明

本篇的核验时间为 2026 年 10 月 28 日。核对方式为直接访问 PhysioNet 项目页与文件目录,逐个确认七个头文件、七个注释文件、RECORDS、ANNOTATORS、SHA256SUMS.txt 的可访问性与内容;注释统计用 wfdb 4.3.1 读取,只用来看符号集合与总量,未做类型频次排序。官方简介的「14 至 22 小时」与头文件换算出的「13.9 至 23.9 小时」并存,两个口径在正文中并列陈述,不做取舍判断。未覆盖的内容包括:标注者人数与一致性、导联对应的体表位置、14149 末尾约四十分钟空档的成因、记录与受试者的映射关系。这些官方从未公布,任何声称掌握的说法都需要另行求证。


相关数据集导航

以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:

  • wctecgdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • ahadb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • chfdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • crisdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • cudb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • ltstdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • iafdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • nsr2db — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • nsrdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • stdb — 共享标签:生理信号 / 心电信号 / 心血管疾病

导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

返回 AI-Ready 数据集