正常窦性心律的十八个整天 — MIT-BIH NSRDB

18 条 23–26 小时 / 128 Hz 双导联 / 18 名受试者

来源 https://physionet.org/content/nsrdb/1.0.0/发布时间: 2026-10-28最后更新: 2026-10-28 阅读 13
正常窦性心律的十八个整天 — MIT-BIH NSRDB

信息速览

数据集名称正常窦性心律的十八个整天 — MIT-BIH NSRDB
数据类型时序信号,波形,人工标注,元数据
规模18 名受试者 / 18 条记录
接入方式https://physionet.org/content/nsrdb/1.0.0/
AI 就绪度

正常窦性心律这几个字,很容易让人以为是一份健康人样本库。它确实叫 MIT-BIH Normal Sinus Rhythm Database,1999 年 8 月 3 日由 PhysioNet 以 1.0.0 版发布,提交者是 MIT 计算生理实验室的 George Moody,DOI 为 10.13026/C2NK5R,整包未压缩 582.7 MB,按 ODC-BY 1.0 开放。但十八名受试者的来历并不是招募来的志愿者:他们先被转诊到波士顿贝斯以色列医院的心律失常实验室,做完动态心电判读之后,才被认定为没有显著心律失常。

每条记录是一昼夜量级的连续双导联心电,两路信号在头文件里一律写成 ECG1 与 ECG2,采样率 128 Hz,12 位量化,采用 WFDB 的 format 212。十八名受试者中五名男性二十六至四十五岁、十三名女性二十至五十岁。数据体之外还附一份 atr 注释,官方清单对它的说明是「参考心搏与信号质量标注」,也就是说标注里既有心搏位置,也有对信号能不能用的判断。

它最合适的角色是参照系,而不是样本库:当你需要一段真实生活状态下、没有显著心律失常、又长到能覆盖昼夜的连续心电时,公开可选的并不多。一屏速览见下表。

维度 内容
官方全名 MIT-BIH Normal Sinus Rhythm Database
常用缩写 NSRDB
中文名 MIT-BIH 正常窦性心律数据库
提交者 George Moody,MIT Laboratory for Computational Physiology
采集机构 波士顿 Beth Israel Hospital(今 BIDMC)心律失常实验室
发布方与版本 PhysioNet,1999 年 8 月 3 日,v1.0.0
DOI 10.13026/C2NK5R
受试者 18 名,5 男 13 女
年龄范围 男性 26 至 45 岁,女性 20 至 50 岁
记录数 18 条,记录名为五位数字
单条时长 23.1 至 26.0 小时,合计约 437 小时
导联 2 路,头文件写 ECG1、ECG2,未注明导联位置
采样与量化 128 Hz,12 位,format 212,增益字段为 0
注释 每条一份 atr,含心搏与信号质量标注
整包体量 未压缩 582.7 MB
许可 Open Data Commons Attribution License v1.0

§1 它要解决的具体麻烦

1.1 正常心律的难处不在样本,在「被确认过没问题」的长记录

心律失常检测器缺的从来不是阳性样本。MIT-BIH 心律失常库提供了四十八条半小时记录、约十一万次心搏标注,几十年来一直是检测算法的默认训练场。真正稀缺的是另一头:连续二十几个小时、覆盖睡眠与活动、病人身上带着真实电极与真实干扰、并且被判读为「没有显著心律失常」的记录。

这类记录难获得,原因在临床流程本身。动态心电不是体检项目,医生开它是因为怀疑有问题;做完发现没问题,记录在临床上就失去了后续价值,通常不会再被整理。公开的正常长时程库,多半是实验室顺手留下的副产品。

NSRDB 就是这种副产品。它的价值不在人数,而在于「长」与「被判读过」这两件事同时成立:一天里心率会随睡眠、进食、走动而起伏,这些起伏在半小时的片段里根本看不全;而判读结论又给了你一个可以引用的前提——这批人没有显著心律失常。

把两边的供给摆在一起,缺口一目了然。

供给方 阳性侧 阴性侧
心律失常库 四十八条半小时记录 基本没有
长时程缺血库 缺血与室性事件 少量
本库 没有 十八条一昼夜记录

1.2 三条常见的错误期待

常见期待 实际情况 后果
以为这是健康志愿者库 受试者是转诊后排除诊断的临床人群 把「无显著心律失常」当成「完全健康」,正常值范围会算窄
以为十八人够做人群统计 18 条记录、年龄 20 至 50 岁、女性占 13 人 任何按性别、年龄分层的结论都只有个位数样本
以为 128 Hz 双导联能做形态学 采样上限 64 Hz,导联位置未注明 做 ST 精细测量或高频 QRS 分析会得出不可解释的结果

三条期待有一个共同来源:库名里的 Normal 是形容词,读起来像在描述人。

期待 字面依据 实际指涉
健康志愿者 Normal 一词 判读结论
够做人群统计 Database 一词 平台栏目名
能做形态学 心电库的通用印象 128 Hz 的双导联

第一条最要命。「无显著心律失常」是判读结论,判读人员看的是有没有房颤、有没有成串室早、有没有高度房室阻滞这类会改变处理方案的问题;偶发的房性早搏、室性早搏、轻度的窦性心律不齐,都可能留在记录里。把这条记录当成「心脏完全正常」的金标准,等于把判读阈值当成了生理阈值。

1.3 它能给到的与给不到的

你的需求 它给的 够不够
心律失常检测器的阴性样本 18 条判读为无显著心律失常的长记录 够,是主要用途
昼夜节律与心率变异分析 每条 23 小时以上,覆盖睡眠与活动 够,长时段正是它强项
信号质量算法的训练与评测 atr 中含信号质量标注 够,且是少见的两用标注
可穿戴设备的真实噪声对照 1990 年代 Holter 电极下的真实干扰 勉强,设备形态与今天不同
人群正常心率区间 18 人、女性占多数、年龄集中在 20 至 50 岁 不够,样本太窄
十二导联形态学 只有两路,且未注明导联位置 不够,结构上做不到
高频心电成分研究 128 Hz 采样 不够,带宽上限太低
绝对电压标定 增益字段为 0 不够,只能做相对量
端到端深度学习训练 记录长、无官方划分 勉强,需自建切分协议

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

你的处境 它能帮你什么 下一步该做什么
你的检测器在心律失常库上灵敏度很高,但误报率下不来 提供大量真实正常节律,专门用来压误报 按记录切分,统计每小时误报次数
你在做心率变异性,手上只有五分钟短记录 一天以上的连续 RR 序列,可做长程与昼夜分段 先按 atr 过滤噪声段,再算时域与频域指标
你在训练信号质量分类器 atr 自带质量判断,可当弱标签 先核对标注覆盖范围,再决定抽样粒度
你在给可穿戴心电找外部验证集 真实 Holter 噪声、真实活动干扰 明确写出设备与年代差异,不要混为同分布
你在做睡眠与自主神经的交叉研究 夜间时段完整保留,无需拼接 用活动量与心率低谷定位睡眠窗
你只需要一份标准十二导联心电 不是这份 换库内十二导联词条
你要做临床结局预测 无结局、无用药、无诊断 改用带病历的重症或队列库

1.5 一句话判断

它是一段被判读过、却什么都没查出来的二十四小时:正因为它没有故事,才适合拿来当别人故事的对照组。

1.6 不适合谁:四条边界

不适合拿它算人群正常值。 十八个人、女性十三人、年龄二十到五十岁,这个构成既不均衡也不随机。从这个分布里算出来的平均心率、平均 RR 间期,只能描述这十八个人,不能叫「正常人的正常值」。

不适合做形态学精细测量。 128 Hz 意味着相邻样本间隔约 7.8 毫秒,QRS 波群的上升支只有几个采样点。测 R 波位置够用,测 QRS 时限、ST 段斜率、晚电位这类依赖细节的指标就不够。

不适合假定导联位置。 头文件只写 ECG1 与 ECG2。这两路到底是改良胸导还是肢体导联,官方页面没有交代,逐条记录里也没有。任何依赖导联轴向的推论,在这份数据上都缺少前提。

不适合当作绝对电压来源。 增益与基线字段都写 0,没有毫伏换算系数。能做的是把每段信号标准化之后比较形状与时序,不能做的是报告「这个人的 R 波高多少毫伏」。

边界 触发条件 后果 替代做法
人群推断 想按性别、年龄分层 每组不足十人 换更大规模的队列库
形态测量 需要 QRS 时限、ST 斜率 采样点过少 换 250 Hz 以上的库
导联轴向 需要知道额面电轴 导联位置未知 换注明导联的十二导联库
绝对振幅 需要毫伏数值 无标定系数 只用相对量或换带标定的库

§2 数据构成与规格

2.1 一个扁平目录,四类文件

解压之后没有按人、按年份或按中心分层,十八条记录平铺在同一层。每条记录由四个同名文件组成,扩展名分别是 hea、dat、atr、xws;目录里另有记录清单、注释器清单和一份校验文件。

层级 文件 数量 说明
目录 根目录 1 全部记录平铺,无子目录
头文件 NNNNN.hea 18 纯文本,约 115 字节
数据体 NNNNN.dat 18 二进制,format 212,两路交错
注释 NNNNN.atr 18 心搏与信号质量标注
浏览脚本 NNNNN.xws 18 90 字节,供波形浏览器打开
记录清单 RECORDS 1 十八行记录名
注释器声明 ANNOTATORS 1 声明 atr 的含义
校验 SHA256SUMS.txt 1 逐文件哈希,2019 年补入

xws 这个扩展名容易被忽略。它不是数据,而是一段几十字节的脚本,写着记录名、注释器与服务器地址,作用是让在线波形浏览器直接打开这条记录。它对离线分析没有用处,却说明这批数据从一开始就打算让人先看再下。

记录清单本身只有十八行,取回来一眼就能看完:

16265
16272
16273
16420
16483
16539
16773
16786
16795
17052
17453
18177
18184
19088
19090
19093
19140
19830

2.2 字段与记录的完整字典

这份库没有数据库表,也没有 CSV 字段表。全部结构化信息集中在头文件的第一行与随后每个通道一行,注释文件则只有样本位置与标签。下表把三层信息合起来列。

信息项 存放位置 取值或范围 是否每条都有
记录名 头文件第一行 五位数字,如 16265 全部
通道数 头文件第一行 2 全部
采样率 头文件第一行 128,单位每秒样本 全部
样本总数 头文件第一行 八位数字 全部
起始时刻 头文件第一行末 时:分:秒,无日期 全部
数据文件名 通道行 指向同名 dat 全部
格式码 通道行 212,12 位左对齐存 16 位 全部
增益 通道行 0,未标定 全部
基线 通道行 0 全部
量化解位 通道行 12 全部
初始值 通道行 该通道首样本 全部
校验和 通道行 整数 全部
通道名 通道行末 ECG1、ECG2 全部
心搏位置 atr 注释 以样本序号计 全部
信号质量 atr 注释 标注器定义的标签 官方称有
年龄、性别、诊断 无 头文件里没有 全部缺失
头文件字段 含义 读错会怎样
第一行第 2 字段 通道数 误当导联数以外的含义会错配数组
第一行第 3 字段 采样率 写成 250 或 360 会让时长与心率全部偏移
第一行第 4 字段 样本总数 与数据体长度不符时读出的尾部是填充
通道行第 3 字段 增益 为 0 时不能做毫伏换算
通道行末字段 通道名 只有 ECG1、ECG2 两种,无解剖位置

年龄、性别、诊断这三项在这份库里一条都没有。官方把它们写在项目页的描述段里,只给出总体的男女构成与年龄范围,没有落到逐条记录。这意味着任何按人分层的分析,都要先自己建立一张外部对照表,而且这张表最多只能对上性别与大致年龄段。

三层信息各有分工,缺一层就要靠别处补。

层 承载什么 谁写的 能否替代
头文件首行 路数、采样率、长度 归档人员 不能,必须读
通道行 格式、增益、通道名 归档人员 不能,决定解析
注释文件 心搏与质量 判读人员 不能,决定标签

2.3 一条记录的完整解剖

以 16265 为例。头文件只有三行:第一行说明这条记录有两路信号、采样率 128、样本总数 11730944、起始时刻 8:04:00;后两行分别定义 ECG1 与 ECG2,格式码都是 212,增益与基线都是 0,末尾的整数是校验和。

16265 2 128 11730944  8:04:00
16265.dat 212 0 12 0 -33 15756 0 ECG1
16265.dat 212 0 12 0 -65 -21174 0 ECG2

按样本总数除以采样率换算,这条记录长 91648 秒,约 25.46 小时。数据体 33.6 MB,注释 297.2 KB,浏览脚本 90 字节。头文件末尾在原始文件里还有一行以井号开头的备注,写的是数据体大小的粗略值,解析时可以忽略。

字段 16265 的取值 说明
通道数 2 全库一致
采样率 128 Hz 全库一致
样本总数 11730944 全库第三长
换算时长 约 25.46 小时 样本数除以 128
起始时刻 8:04:00 只有时刻,没有日期
增益 0 无毫伏标定
数据体 33.6 MB 每帧 3 字节,两路交错
注释 297.2 KB atr,含心搏与质量

format 212 是这份数据在读取时最容易出问题的地方。它的含义是每个样本占 12 位、两个样本拼成 3 个字节,配对存放。两路信号因此是「按帧交错」而不是「按通道连续」:第 1 帧的两个样本写在一起,接着是第 2 帧。用现成的 WFDB 库读不会出错,自己按字节偏移解析则很容易把两路弄反。

读法 正确做法 常见错法
定位帧 按帧号乘三字节 按通道连续读
拆位 12 位左对齐,右移还原 直接当 16 位整数
解交错 每帧先 ECG1 后 ECG2 把整块对半切

2.4 十八条记录的长度与文件规模

十八条记录的长度并不整齐,最短 23.1 小时,最长 26.0 小时。下表按记录名列出样本数、换算时长、起始时刻与两个主要文件的体积,全部取自官方目录列表与头文件首行。

记录 样本数 时长(小时) 起始时刻 数据体 注释
16265 11730944 25.46 8:04:00 33.6 MB 297.2 KB
16272 11520000 25.00 10:45:00 33.0 MB 262.1 KB
16273 11354112 24.64 8:00:00 32.5 MB 244.7 KB
16420 11051008 23.98 9:55:00 31.6 MB 307.0 KB
16483 11960320 25.96 9:54:00 34.2 MB 251.5 KB
16539 11327488 24.58 8:40:00 32.4 MB 267.8 KB
16773 11046912 23.97 9:50:00 31.6 MB 450.6 KB
16786 11284480 24.49 11:48:00 32.3 MB 201.6 KB
16795 10866688 23.58 11:15:00 31.1 MB 251.6 KB
17052 10659840 23.13 11:06:00 30.5 MB 213.0 KB
17453 11235328 24.38 9:20:00 32.1 MB 255.3 KB
18177 11960320 25.96 11:30:00 34.2 MB 403.9 KB
18184 10942464 23.74 9:34:00 31.3 MB 226.8 KB
19088 10967040 23.80 10:58:00 31.4 MB 381.7 KB
19090 11143168 24.18 13:50:00 31.9 MB 237.6 KB
19093 10705920 23.23 10:42:00 30.6 MB 230.7 KB
19140 11139072 24.17 11:39:00 31.9 MB 253.6 KB
19830 10701824 23.22 9:56:00 30.6 MB 341.8 KB

十八条的样本数合计约 2.02 亿点,换算约 437 小时,接近十八天半的连续记录。这个总量是本文按头文件样本数相加得到的推导值,官方页面只给出整包体积,没有给出总时长。

记录名是五位数字,但不是连续编号,也无法从中读出顺序:从 16265 排到 19830,中间缺号很多。起始时刻分布在上午八点到下午两点之间,说明记录多在白天装机、戴满一昼夜后摘除。这些时刻只有钟点,没有年月日,跨记录对齐时间轴时不能拿来当日期用。

2.5 与同类资源的规格差异

同样叫「正常心律」或「长时程心电」的资源在库内不止一份,规格差异却很大。下表只比结构,不比质量。

维度 NSRDB nsr2db MIT-BIH 心律失常库 LTSTDB
有无波形 有,两路 无,只有心搏时刻 有,两路 有,三路
记录数 18 54 48 86
单条时长 23 至 26 小时 约 24 小时 约 30 分钟 21 至 24 小时
采样率 128 Hz 128 Hz 360 Hz 250 Hz
心律状态 无显著心律失常 正常窦性心律 以各类心律失常为主 缺血与非缺血事件
标注粒度 心搏与信号质量 仅心搏时刻 心搏、节律、质量、注释 心搏与 ST 事件分层
受试者年龄 20 至 50 岁 28.5 至 76 岁 23 至 89 岁 官方未逐人公布

这张表说明这四份资源是四种取舍:要波形就得放弃人数,要人数就得放弃波形,要高采样率就得放弃时长。本库站在「波形加时长」这一端,代价是人数最少。

取舍 放弃什么 换来什么 谁该承担
波形 人数 可做形态与检测 算法研究
人数 波形 可做统计 人群研究
采样率 时长 可做高频 形态研究
标注密度 规模 可做监督 基准建设

§3 它的身份:一份「排除了心律失常」的转诊记录

3.1 谁做的、为什么做

官方页面署名 George Moody 为提交者,隶属 MIT 计算生理实验室;采集地点是波士顿贝斯以色列医院的心律失常实验室,也就是 MIT-BIH 系列心电库的共同来源。这份库没有单列的数据集论文,官方只要求引用 PhysioNet 平台文献。

项 内容
提交者 George Moody
机构 MIT Laboratory for Computational Physiology
采集地 Beth Israel Hospital 心律失常实验室
发布 PhysioNet,1999 年 8 月 3 日,v1.0.0
论文 官方未单列,按平台文献引用

这条链路值得注意:MIT 的工程团队负责格式与归档,医院的实验室负责采集与判读。这也解释了为什么头文件里几乎没有临床字段——判读结论留在了医院的记录里,进入数据集的只有波形与心搏标注。

环节 承担方 留在数据里的痕迹
转诊与佩戴 医院实验室 受试者来源与记录时刻
判读 医院判读人员 atr 注释与入组结论
数字化与归档 MIT 工程团队 头文件格式与文件时间戳
发布 PhysioNet DOI、版本、许可

3.2 十八个人是谁

官方对这一批人的描述只有一句话:转诊至心律失常实验室、未发现显著心律失常的受试者,其中包括五名二十六至四十五岁的男性与十三名二十至五十岁的女性。

维度 官方表述 使用时的含义
总人数 18 与记录数相同
男性 5 名,26 至 45 岁 只占不到三成
女性 13 名,20 至 50 岁 占七成以上
来源 心律失常实验室转诊 有临床疑诊,非随机抽样
判读结论 无显著心律失常 排除性结论,非健康筛查

十三比五的性别构成,加上二十到五十岁的年龄带,让它更接近「年轻女性为主的门诊人群」,而不是「成年人总体」。静息心率与 RR 间期的分布都受年龄与性别影响,据此算出的基线不能套到老年男性身上。

年龄段 本库覆盖情况 能做的分析
20 至 35 岁 女性为主 年轻成人基线
36 至 50 岁 男女均有 中年基线,仍偏女性
50 岁以上 不覆盖 不可外推
18 岁以下 不覆盖 不可外推

3.3 「正常」是临床判定,不是筛选标准

这份库里最关键的一个词是 normal,但它修饰的不是人,是判读结论。理解这一点,才能理解它为什么既适合当对照,又不能当健康金标准。

口径 含义 对本库的适用性
判读口径的正常 未发现房颤、成串室早、高度阻滞等显著问题 官方明确采用
筛查口径的正常 经体检、影像、实验室检查排除器质性疾病 官方未提及
统计口径的正常 落在同年龄同性别人群的参考区间内 官方未做

偶发早搏、轻度窦性心律不齐、一过性 ST 改变,都可能出现在「无显著心律失常」的记录里,因为判读人员的任务是回答「有没有需要处理的心律问题」,不是「这个人是否绝对健康」。做算法评测时这是好事:真实世界里的正常记录本来就带着这些杂音。

判读结论能承诺的 不能承诺的
没有需要处理的心律问题 没有任何早搏
没有成串室性事件 没有传导变异
没有房颤等持续心律失常 心脏结构正常
记录可用于节律分析 可用于诊断结论

3.4 名字里的三层信息

库名把三个不同层级的东西压在了一起:机构、项目系列、心律状态。拆开看才不会读错。

片段 指什么 容易误读成
MIT-BIH MIT 与 Beth Israel Hospital 的合作系列 某个算法或标准编号
Normal Sinus Rhythm 判读结论为正常窦性心律 健康人群样本
Database PhysioNet 的数据集栏目 某个软件包

「MIT-BIH」这一前缀在 PhysioNet 上至少对应十几个库,包括心律失常库、长时程库、房颤库、噪声应激库等。它们共享同一套格式与同一种注释体系,但人群、场景、标注粒度各不相同。看到前缀相同就以为可以混用,是最常见的错误之一。

同前缀的库 记录形态 与本库的关系
心律失常库 半小时片段 阳性互补
长时程库 十四小时以上 人群不同
房颤库 长时程片段 阳性另一类
噪声应激库 短片段加噪声 鲁棒性测试

3.5 五位数字的记录名说明了什么

记录名形如 16265,落在 16000 到 19999 这个区间。同一区间也被贝斯以色列医院的其它心电库使用,说明这些编号来自院内同一个登记序列,而不是为发布而重编的流水号。

现象 推论 确定程度
编号五位、区间集中 沿用院内登记号 工作假设
编号不连续 只公开了其中一部分 工作假设
编号与年龄性别无关 不能由编号推人群 已确认,头文件无临床字段
起始时刻多在上午 白天装机、次日摘除 由时刻分布推断

编号不表意带来一个直接后果:想按年龄段挑记录,必须自己维护一张外部对照表,而这张表最多只能对上「男性或女性、大致年龄段」,因为官方只给了总体范围。

想从编号得到的 能否得到 原因
年龄 不能 头文件无临床字段
性别 不能 同上
采集顺序 不能 编号不连续
唯一标识 能 记录名全库唯一

§4 它最独特的东西:二十四小时里的正常

4.1 为什么「长」比「多」更难替代

半小时的片段能回答「这一拍是什么」,回答不了「这个人的节律在一整天里怎么变」。心率在睡眠时下落、在清晨上扬,窦性心律不齐随呼吸涨落,这些现象需要至少几个小时才能看出形状。

时间尺度 能观察到的现象 半小时片段是否够
数秒 单个 QRS 形态、单次早搏 够
数分钟 短程心率变异、呼吸性心律不齐 勉强
数小时 睡眠与觉醒的节律切换 不够
一昼夜 昼夜节律、清晨心率上扬 完全不够

这也是为什么长时程库往往人数很少:采集成本按小时计,判读成本按小时计,而一份记录只能来自一个人。十八个人乘二十四小时,换来的是四百多小时的真实信号;同样四百小时如果做成半小时片段,可以覆盖八百多人,但那就失去了连续性。

任务 所需最短时长 本库是否满足
单搏分类 数秒 远超所需
心率变异短程指标 五分钟 满足
昼夜节律 二十小时 满足
睡眠分期 整夜 满足,但无睡眠标注

4.2 案例:16265 这一条 25 小时记录

选 16265 作贯穿案例,因为它的长度排在全库第三,四个文件也齐全。它的头文件只有三行,样本总数 11730944,按 128 Hz 换算约 25.46 小时,数据体 33.6 MB,注释 297.2 KB。

import wfdb

rec = wfdb.rdrecord("16265", pn_dir="nsrdb/1.0.0")
ann = wfdb.rdann("16265", "atr", pn_dir="nsrdb/1.0.0")

print(rec.sig_name)
print(rec.fs, rec.sig_len, round(rec.sig_len / rec.fs / 3600, 2), "h")
print(rec.units)
print(ann.sample[:5], ann.symbol[:5])

这段代码能一次问出四件事:通道名是不是只有 ECG1 与 ECG2,采样率与样本总数是否与头文件一致,单位字段是不是空的,以及注释前几条落在什么位置。第三项尤其值得看,因为增益为 0 时,读出的物理量单位往往退化成空串或默认值,直接拿去和别的库比较会出错。

16265 的属性 值 与全库的关系
通道 ECG1、ECG2 全库一致
采样率 128 Hz 全库一致
样本数 11730944 仅次于 16483 与 18177
时长 约 25.46 小时 落在 23 至 26 小时的区间内
数据体 33.6 MB 属较大一档
注释 297.2 KB 中等偏上

§4.2 的案例在后面还会用到:§5.3 用它演示怎么读头文件,§7.3 用它说明无标定带来的偏差,§9.2 用它跑通从下载到出图的最短流程。

16265 的特点 对本库的代表性 使用时注意
时长居前三 属长记录,非中位 不能当平均长度
文件四件齐全 全库一致 无
增益同为 0 全库一致 振幅不可比
起始 8:04 上午装机 昼夜对齐需自行推定

4.3 注释的两层:心搏与信号质量

官方把 atr 描述为「参考心搏与信号质量标注」。这句话包含两类信息,用途完全不同。

标注层 回答的问题 典型用途 使用注意
心搏 每一次心室激动发生在哪个样本 RR 序列、心率统计、检测器评测 需按标签筛掉非心搏记录
信号质量 这一段信号能不能用 质量分类、噪声段剔除 官方未逐类说明标签定义
节律变化 节律是否切换 分段建模 本库是否包含需自行核对

第三行是有意留白的。官方清单只写了心搏与质量两类,没有逐条列出标签集合;不同库的 atr 内容并不完全一致,心律失常库的 atr 还包含节律与注释文本,本库是否有同样的层次,需要读注释时自己确认。

import collections
import wfdb

ann = wfdb.rdann("16265", "atr", pn_dir="nsrdb/1.0.0")
print(collections.Counter(ann.symbol))
print(len(ann.sample))

把标签计数打印出来,是弄清楚这份注释到底包含什么的最快方式。若计数里只有心搏类符号,说明质量判断可能以别的形式存放;若出现非心搏符号,就要先弄清它们的含义再决定是否纳入训练。

想做的任务 需要哪一层 缺口
心搏检测 心搏层 无,直接可用
噪声段剔除 质量层 需核对标签定义
节律分段 两层都要 官方未列节律标签
心律失常分类 心搏层加诊断 本库无阳性标签

4.4 它能支撑的五类实验

实验类型 需要的数据条件 是否满足 常见做法
心律失常检测的阴性对照 长时段、真实噪声、无显著心律失常 满足 统计每小时误报
心率变异性与昼夜节律 连续二十小时以上 满足 按小时分段算指标
信号质量分类 带质量判断的标注 满足 以段为单位做二分类
可穿戴心电的域适应 真实 Holter 噪声 部分满足 明确写出设备差异
心搏检测器的鲁棒性 长记录、含运动伪迹 满足 按记录划分训练测试

第一类最少被替代。阳性库遍地都是,阴性库很少;而误报率正是筛查场景里最贵的指标——把正常记录判成异常,代价是复检,不是漏诊。

错误类型 临床后果 在筛查场景里的权重
误报 复检、转诊、焦虑 高,量大
漏诊 延误处理 高,但少见
段级漏标 训练信号变弱 中
质量误判 噪声被当成事件 高

4.5 边界条件:什么时候它不再适用

当问题涉及高频成分时。 128 Hz 的可分析带宽上限在 64 Hz 附近,QRS 的高频切迹、晚电位、起搏钉的细节都在这个上限之外。

当问题涉及人群差异时。 十八个人做不出有统计意义的组间比较,哪怕只是男女对比,也只有五对十三。

当问题涉及绝对振幅时。 增益为 0,信号是未标定的数字量。跨记录比较振幅之前,必须先确认两条记录的数字化增益是否一致,而官方没有提供这个信息。

当问题涉及临床结局时。 没有随访、没有诊断、没有用药。能研究波形与波形的关系,研究不了波形与预后的关系。

边界 具体阈值 越界后的表现
频率 高于 64 Hz 的成分 波形被抹平,细节不可辨
人群 需要按性别或年龄分组 每组不足十人
振幅 需要毫伏绝对值 数值随记录漂移
结局 需要任何随访变量 无字段可用

4.6 128 Hz 这个数字的来历与代价

128 Hz 不是随手选的,它是当年 Holter 回放设备的常见档位:既能保住 QRS 检测所需的主要能量,又能把一天的数据压到几十兆。以这份库为例,两路 12 位信号按帧交错,每秒 128 帧、每帧 3 字节,一小时约 1.3 MB,一天约 32 MB,正好对上目录里三十兆出头的文件体积。

采样率 单日数据量(两路 12 位) 适用分析 不适用分析
128 Hz 约 32 MB 心搏检测、RR、节律 QRS 时限、晚电位
250 Hz 约 62 MB 上述加 ST 趋势 高频切迹
360 Hz 约 89 MB 上述加较细形态 仍不足做晚电位
1000 Hz 约 247 MB 高频成分 存储与算力成本高

这张表是按位深与路数推算的,不是官方数字;换算结果与目录里的文件大小一致,可当量级参考。取舍很清楚:要覆盖一整天,采样率就得让步。

§5 怎么拿到:从 582.7 MB 到可训练张量

5.1 三条取数路径

路径 命令形态 适合场景 代价
整包下载 取 nsrdb.zip 一次要全量 需 582.7 MB 空间
目录递归 wget 递归抓文件 只要部分记录 需自己拼目录
对象存储同步 s3 sync 无签名访问 脚本化流水线 需装 AWS CLI
#-- 路径一:整包下载
wget -c https://physionet.org/content/nsrdb/1.0.0/nsrdb.zip

#-- 路径二:只抓头文件与注释,先建索引
wget -r -N -c -np --accept "*.hea,*.atr" https://physionet.org/files/nsrdb/1.0.0/

#-- 路径三:从公开桶同步,无需账号
aws s3 sync --no-sign-request s3://physionet-open/nsrdb/1.0.0/ ./nsrdb

第二条路径在只做结构分析时最省时间:头文件与注释加起来不到十兆,足够建出索引、算出时长、看清标注规模,等确定要用哪几条再拉数据体。

路径 传输量 落地文件 适用阶段
整包 582.7 MB 全部七十二个文件 确定要用全库
递归只取头注释 不足十兆 十八个头文件与注释 摸底与索引
对象存储 按需 自选 流水线

5.2 目录与体积

组成 数量 合计体积 说明
头文件 18 约 2 KB 每个约 115 字节
数据体 18 约 577 MB 每帧 3 字节,两路交错
注释 18 约 4.9 MB 两百到四百多 KB 不等
浏览脚本 18 约 1.6 KB 每个 90 字节
清单与校验 3 约 8 KB RECORDS、ANNOTATORS、哈希

数据体占了整包的绝大部分。按 format 212 的排布,每条记录的字节数等于样本数乘三,十八条相加约 605 兆字节,与官方给出的 582.7 MB 属于同一量级——差额来自单位口径(十进制兆字节与二进制兆字节)与注释、头文件是否计入。

口径 数值 差异来源
官方整包 582.7 MB 未压缩,含全部文件
数据体推算 约 605 兆字节 样本数乘三字节
换算为二进制 约 577 MiB 除以 1048576
注释合计 约 4.9 MB 十八个 atr

5.3 先把头文件读出来

from pathlib import Path

def head(path):
    lines = Path(path).read_text(encoding="utf-8", errors="replace").splitlines()
    f = lines[0].split()
    return {
        "name": f[0],
        "n_sig": int(f[1]),
        "fs": float(f[2].split("/")[0]),
        "n_samples": int(f[3]),
        "start": f[4] if len(f) > 4 else None,
        "channels": [ln.split()[-1] for ln in lines[1:1 + int(f[1])]],
    }

h = head("nsrdb/16265.hea")
print(h["channels"], round(h["n_samples"] / h["fs"] / 3600, 2))

这段解析不用装 WFDB 也能跑,适合在只有文件、没有环境的机器上先摸底。它返回的五个字段,正好覆盖后面建索引要用的全部信息。

字段 来源 后续用途
记录名 第一行第 1 段 主键,切分单位
通道数 第一行第 2 段 决定数组形状
采样率 第一行第 3 段 换算时长与心率
样本数 第一行第 4 段 换算时长
起始时刻 第一行第 5 段 昼夜对齐的粗略锚点

§4.2 的案例在这里第二次出现:16265 的五个字段读出来是 2、128、11730944、8:04:00 与两个通道名,与官方目录一致,可以当作解析是否正确的自检点。

字段缺失或读错 后果 自检方式
采样率读错 时长与心率成比例偏移 与目录文件大小交叉核对
通道名读错 两路互换 比对首样本值正负
起始时刻缺失 昼夜对齐无锚点 用记录名与时长排序
样本数不符 尾部读到填充 与数据体字节数比值核对

5.4 建索引

import re
from pathlib import Path

rows = []
for p in sorted(Path("nsrdb").glob("*.hea")):
    txt = p.read_text(encoding="utf-8", errors="replace")
    f = txt.splitlines()[0].split()
    rows.append({
        "name": f[0],
        "fs": float(f[2].split("/")[0]),
        "n": int(f[3]),
        "hours": round(int(f[3]) / float(f[2].split("/")[0]) / 3600, 2),
        "start": f[4] if len(f) > 4 else "",
        "leads": len([l for l in txt.splitlines()[1:] if l.strip()]),
    })

print(len(rows), rows[0])
索引列 类型 为什么需要
name 字符串 唯一的切分单位
fs 浮点 时长与心率的换算基数
n 整数 与数据体字节数交叉校验
hours 浮点 按长度分层抽样
start 字符串 昼夜对齐,仅钟点
leads 整数 确认两路都在

索引里最该保留的是 hours 与 name。前者决定哪些记录适合做长程分析,后者是唯一不会泄漏的切分单位——同一条记录切成几百个窗,如果按窗随机分配,训练集和测试集会共享绝大部分相邻样本。

索引列 缺失时的影响 是否必需
name 无法按记录切分 必需
fs 所有时长与心率失真 必需
hours 无法按长度分层 建议
start 昼夜对齐失去锚点 可选
leads 无法确认两路齐全 建议

5.5 切窗与标准化

import numpy as np

def windows(x, fs, win_sec=30, step_sec=15):
    L, S = int(win_sec * fs), int(step_sec * fs)
    out = []
    for i in range(0, x.shape[0] - L + 1, S):
        w = x[i:i + L].astype("float32")
        if not np.isfinite(w).all():
            continue
        out.append((w - w.mean(axis=0)) / (w.std(axis=0) + 1e-6))
    return np.stack(out) if out else np.zeros((0, L, x.shape[1]))

标准化用的是每个窗自己的均值与标准差,而不是全库统计量。原因很直接:增益为 0 意味着不同记录的数字化尺度可能不同,用全库统计量会把记录间的尺度差异当成信号差异。按窗标准化牺牲了绝对幅度信息,换来的是跨记录可比。

窗长 覆盖的心搏数 适用任务 代价
5 秒 五到八次 单搏与噪声分类 长程结构被切碎
30 秒 三十余次 节律与质量 一般
5 分钟 三百余次 短程心率变异 边界效应明显
1 小时 四千次量级 昼夜趋势 样本数骤减

5.6 按记录切分的评测协议

分层依据 分层方式 目的 代价
记录号 按十八条划训练与测试 避免同人泄漏 测试集方差大
时长 长记录与短记录各占一半 检验长度敏感性 分组不均
时段 昼间与夜间分开 检验昼夜泛化 需先定义昼夜
质量 按 atr 质量标注分层 检验噪声鲁棒性 依赖标注覆盖

十八条记录做切分,最实际的做法是留出法而不是交叉验证:留四到六条做测试,其余做训练或调参。十八这个数字太小,五折交叉验证的每一折只有三四条,折间方差会大到让结论失去意义。

import random

names = [f.name.split(".")[0] for f in __import__("pathlib").Path("nsrdb").glob("*.hea")]
names.sort()
random.Random(0).shuffle(names)

test = names[:4]
train = names[4:]
print(len(train), len(test), test)

固定随机种子是这段代码唯一重要的细节。十八条记录的划分结果只有有限几种,换一个种子就可能换掉整个测试集,结论随之变化;把种子写进方法段,别人才可能复现同一组数字。

划分方案 测试集规模 方差 建议
留出四条 四条 大 十八人规模下最实际
留出六条 六条 中 想稳一点时用
五折交叉 每折三四条 极大 不建议
留一记录 一条 极大 只适合演示

5.7 六个最容易出错的地方

错误 表现 后果 处理
按 360 Hz 算时长 时长算成九小时 昼夜对齐全错 一律从 fs 字段取
把增益 0 当 1 振幅差几百倍 阈值型算法全部失效 只做相对量或按窗标准化
混入非心搏标注 RR 序列出现毫秒级间期 心率变异性指标失真 先按符号过滤
按窗随机切分 测试集与训练集相邻 指标虚高 按记录切分
假定导联位置 当成 II 导联做电轴 结论无前提 只描述 ECG1、ECG2
忽略两路交错 通道错位或半样本偏移 波形看起来像噪声 用成熟库读,不手写解析

第三条最隐蔽。atr 里除了心搏,还可能有质量或节律标记,位置落在两次心搏之间;若不加筛选地当成心搏算 RR,会出现一串短到几十毫秒的假间期,而任何基于 RR 的指标都会被这类假间期带偏。

自查项 通过标准 不通过时先查
采样率 一律 128 是否手写了默认值
时长 落在 23 至 26 小时 是否用错采样率
通道 只有两路 是否读到了别的库
单位 标为未标定 是否误当毫伏
注释 心搏占多数 是否混入质量标记
切分 按记录名 是否按窗随机

§6 与库内词条的关系

6.1 关系图谱

这份库在库内占「正常对照」这一格:上游是同院同系列的心律失常库,下游是所有需要阴性样本的检测与筛查任务。它是用来定义「没有异常」的那把尺。

关系类型 相关词条方向 具体关系
同院同系列 MIT-BIH 心律失常库 同一采集地、同一注释体系,阳性与阴性互补
同名前缀 MIT-BIH 长时程库、长时程 ST 库 同为长时程,但人群与标注目标不同
同心律主题 正常窦性心律 RR 间期库 同一判读口径,一个有波形一个只有时刻
同生理主题 Fantasia 健康窦性心律库 都以健康或正常为卖点,时长与场景不同
同平台 PhysioNet 其它开放库 同格式、同许可、同取数方式
同任务 房颤检测、室性心律失常类库 那些给阳性,这份给阴性
同格式 全部 WFDB 库 读写工具通用,注释结构一致
谱系位置 代表资源 波形 人数 时长 心律
阳性短片段 MIT-BIH 心律失常库 有 47 30 分钟 各类心律失常
阳性长时程 长时程 ST 库、CUDB 有 80 上下 21 至 24 小时 缺血、室性事件
阴性长时程 本库 有 18 23 至 26 小时 无显著心律失常
阴性仅时刻 nsr2db 无 54 约 24 小时 正常窦性心律
阴性短时程 Fantasia 有 40 120 分钟 严格筛查健康

这张谱系表的价值在于看出空白:阴性侧的长时程波形只有这一份,人数还最少。阳性侧从半小时到一天都有,阴性侧要么短、要么没有波形。

6.2 与 nsr2db 的区隔:一个有波形,一个只有时刻

这两个名字只差一个 2,是库内最容易混淆的一对。它们不是版本关系,而是两份独立的数据集:本库由 George Moody 提交、1999 年发布、18 条带完整波形的记录;nsr2db 全名 Normal Sinus Rhythm RR Interval Database,2003 年发布,提交者是华盛顿大学的 Phyllis Stein。

维度 NSRDB nsr2db
全名 MIT-BIH Normal Sinus Rhythm Database Normal Sinus Rhythm RR Interval Database
发布年份 1999 2003
提交者 George Moody,MIT Phyllis Stein,华盛顿大学
记录数 18 54
波形 有,两路 128 Hz 无,原始心电未公开
内容 数据体加心搏与质量标注 只有心搏时刻,即注释
受试者 5 男 13 女,20 至 50 岁 30 男 24 女,28.5 至 76 岁
能做的分析 波形、节律、质量、RR 只有 RR 及其派生指标

差异的根源在用途。nsr2db 为心率变异性研究准备,只要心搏时刻就能算出全部时域与频域指标;本库保留波形,代价是记录数只有三分之一,年龄也更窄。

选择规则:要看波形、做检测、做质量分析,用本库;只要 RR 序列、要更多人、要更宽的年龄带,用 nsr2db 并接受没有波形。

排查项 本库 nsr2db
打开有没有 dat 有 没有
目录里是不是只有 atr 一类 不是 是
记录数是不是十八 是 不是
DOI 末尾是不是 C2NK5R 是 不是

6.3 与 MIT-BIH 心律失常库的区隔:正常与异常

维度 NSRDB MIT-BIH 心律失常库
心律状态 无显著心律失常 以各类心律失常为主
记录数 18 48
受试者 18 47,其中两条来自同一人
单条时长 23 至 26 小时 约 30 分钟
采样率 128 Hz 360 Hz
导联 2 路,未注明位置 2 路,多数为 MLII 与 V1 一类
标注 心搏与信号质量 心搏、节律、质量、注释文本
典型用途 阴性对照、误报压制 阳性训练、分类基准

两者最实质的差别不是人数或采样率,而是「一小时里发生多少次异常」这个密度。心律失常库的每条半小时记录都经过挑选,确保包含值得标注的事件;本库的每条记录则被期望「什么都没有」。把两者拼成一个训练集,正负比例会极端失衡,必须显式做重采样或损失加权。

混用方式 正负比例 后果 补救
按窗直接拼 阴性占绝大多数 模型偏向判正常 按窗数配平
按小时拼 仍偏阴性 偏置减弱 按心搏数配平
按记录拼 接近一比一 记录过少 需阳性侧补量
只做评测 不涉及训练 无偏置 直接可用

6.4 与长时程库、Fantasia 的分工

资源 人数 时长 采样率 与本案的分工
本库 18 23 至 26 小时 128 Hz 阴性侧的长时程波形
MIT-BIH 长时程库 官方未公布人数,7 条记录 14 至 24 小时 128 Hz 更早的长时程,受试者年龄更大
长时程 ST 库 80 21 至 24 小时 250 Hz 缺血事件为主,采样率更高
Fantasia 40 120 分钟 250 Hz 严格筛查的健康人,含呼吸信号
nsr2db 54 约 24 小时 128 Hz 只有 RR,没有波形

Fantasia 与本库的差别最能说明「正常」的两种含义:Fantasia 的受试者经过严格筛查、在仰卧静息状态下看两小时电影,是实验室条件下的健康;本库的受试者是日常活动中的转诊人群,是真实世界里的「查不出问题」。前者干净,后者真实。

哪种正常 代表库 用时该注意
筛查后的健康 Fantasia 不能代表日常活动
判读后的阴性 本库 不能代表人群
只有间期的正常 nsr2db 无法回看波形

6.5 组合使用的三条路线

路线 组合方式 解决的问题 注意
阳性加阴性 心律失常库训练,本库压误报 误报率过高 需重采样,正负极不平衡
长短互补 本库看昼夜,心律失常库看形态 单一尺度看不全 采样率不同,需重采样
波形加时刻 本库出波形,nsr2db 扩人数 人数不足 两者受试者不重叠,不能当同一队列

第一条路线最常用,也最容易被写错。把本库整段切窗后与心律失常库的片段混在一起,会出现「阴性样本时长是阳性样本几十倍」的隐式加权,模型会倾向于判正常。正确做法是按小时或按心搏数对齐两侧的采样量。

组合后的检查 合格线 不合格的迹象
两侧采样量 同一量级 训练损失长期不动
采样率 统一重采样 波形出现锯齿
振幅尺度 各自标准化 阈值全部失效
评价指标 误报与漏诊并列 只报准确率

6.6 检索路径

你想找的 检索词 会落到 看什么
正常长时程波形 normal sinus rhythm、Holter 本库 波形与质量标注
只要 RR 序列 RR interval、normal nsr2db 人数与年龄带
心律失常基准 arrhythmia、MIT-BIH 心律失常库 标签体系与划分
缺血事件 ST、ischemia 长时程 ST 库 事件分层
严格健康对照 healthy、Fantasia Fantasia 筛查标准与呼吸信号

检索时值得同时用三组词:心律状态(normal、sinus)、记录形态(Holter、long-term)、平台或格式(PhysioNet、WFDB)。只用第一组会混进大量短片段正常库,只用第二组会混进重症长时程库。

检索陷阱 会搜到什么 规避方式
只搜 normal 大批短片段库 加上 long-term
只搜 MIT-BIH 十几个库 加上 sinus
只搜 nsr 同时命中 nsr2db 核对是否有波形
只搜 Holter 器械与综述 加 PhysioNet 限定

§7 质量评估与局限性

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

打分之前要先纠正一个常见误判:把它当「健康人群数据库」来评。若按人群库的标准衡量,结论必然是人数太少、年龄太窄、性别失衡、没有随访——这些都对,但都不构成缺陷,因为它们不是这份数据想做的事。

它的设计目标只有一个:留下一批被判读为没有显著心律失常的长时程真实波形。按这个目标衡量,评价的落点就变成三件事——长度够不够覆盖昼夜,判读结论是否可引用,标注是否支持按段筛选。三项都成立,短板就只剩规模,而这正是这类资源付不起的成本。

7.1 五维评分

若用数据交换标准(DAIMS)常被追问的五个维度——可发现、可访问、可互操作、可复用、可追溯——来衡量,长短分布得很清楚。

维度 评分 依据
可发现 高 有 DOI、有平台收录、有稳定引用锚点
可访问 高 无需登录,整包可下,许可宽松
可互操作 中高 格式标准,但导联名与标定缺失
可复用 中 需自建切分与清洗,人数限制复用深度
可追溯 中 可追到机构与判读结论,追不到个人病历

DAIMS 关心的正是「这份数据在交换与复用时会不会掉信息」。本库在可发现与可访问两项上表现稳定,原因是它挂在被广泛引用的平台上、许可足够宽松;在中后三项上则显出老库的典型特征:格式已经标准化,语义却留在了平台页面的几句话里。

维度 常见失分场景 使用者的补救
可发现 只搜「正常心律」 加 DOI 或记录名
可访问 网络受限 走对象存储镜像
可互操作 手写字节解析 改用 WFDB 库
可复用 当主训练集用 只取阴性侧
可追溯 想回溯病历 换带病历的库

7.2 分数背后的取舍

维度 加分项 减分项 净效果
可互操作 WFDB 全生态通用 导联未命名、增益为 0 能读,但语义要自己补
可复用 许可允许商用与再分发 18 人限制结论强度 适合当组件,不适合当主集
可追溯 机构、判读标准、DOI 齐全 无逐人年龄性别、无病历 可引用,不可回溯
可发现 PhysioNet 收录、引用量大 与 nsr2db 名称近似 搜得到,但容易搜错

第三行最能说明老库的处境:它知道自己从哪来,却说不清每一条记录对应谁。这种「机构级可追溯、个体级不可追溯」的组合,在信号研究里够用,在临床研究里不够。

7.3 已知的、可枚举的偏差

偏差 表现 影响 应对
规模偏差 仅 18 人 无法做组间比较 只做单组描述
性别偏差 13 女 5 男 基线偏女性 不套用男性参考值
年龄偏差 20 至 50 岁 缺少年与老年 不外推到两端
判读偏差 正常由判读人员认定 阈值影响入组 引用判读口径而非「健康」
标定缺失 增益字段为 0 无绝对电压 只用相对量
采样偏差 128 Hz 高频信息丢失 只做节律与低频形态
导联偏差 位置未注明 轴向分析无前提 只描述通道序号
设备偏差 1990 年代 Holter 噪声谱与今天不同 明确写设备差异

前四条是设计取向,改不了;后四条是使用层面的坑,可以在流程里处理。前者写进方法段的限制说明,后者写成清洗步骤。

§4.2 的案例在这里第三次出现:16265 的增益字段是 0,若按常见的「除以增益得毫伏」流程处理,会得到除以零或直接跳过换算的结果,两种情况都会让振幅变成一个无法解释的数值。

7.4 外部验证矩阵

验证方式 是否可行 说明
与现代 Holter 库对照噪声 部分可行 只能比噪声类型,不能比幅度
与十二导联库对照形态 不可行 导联不同,无法对齐
重复测量检验 不可行 每人一条,无重复
专家重新判读 可行 波形完整,可重做判读
与 nsr2db 对照心率 部分可行 同一判读口径,年龄带不同
与可穿戴设备对照 可行 需先解决采样率与标定差异

第四行是它少见的优势:心电判读可以请现代医师重做一遍,与当年的入组结论对照,得到一份「三十年前后判读差异」的研究素材。这类研究不需要额外采集,只需要重新读图。

重判设计要素 本库能否满足 说明
原始波形 满足 十八条完整保留
既往判读结论 部分满足 只有总体描述
判读人员盲法 满足 库内无逐人诊断
一致性统计 满足 可按记录算

7.5 它为何能持续:阴性样本的供给一直没跟上

二十多年来,公开的心律失常库越积越多,正常长时程库却没有相应增长。原因不在技术,在动机:采集阳性数据有明确的科研产出,采集阴性数据只是「什么都没发生」,很难立项,也很难写成论文。于是这份 1999 年发布的副产品,成了不少人唯一能找到的阴性长时程来源。

它能持续存在,靠三点。许可足够宽松,可下载、可再分发、可商用;格式足够标准,WFDB 的读取工具没有断代;定位足够清楚,它从不声称自己是人群样本,只提供「被判读为正常的一昼夜」。

7.6 与替代方案的取舍

替代方案 优势 劣势 何时选它
nsr2db 54 人,年龄带宽 无波形 只做 RR 分析
Fantasia 严格筛查,含呼吸 仅两小时,仰卧 做静息基线
长时程 ST 库 250 Hz,80 人 以缺血病例为主 做 ST 相关任务
自采数据 设备与人群可控 成本高,需伦理审批 有明确临床问题
合成信号 标签精确、量可调 缺少真实噪声 做预训练或增广

选择的关键是问自己一句:我需要的是「正常」这个标签,还是「真实」这个质地。要标签,nsr2db 与 Fantasia 都更整齐;要质地,只有带波形的长记录能提供。

§8 生态位与历史

8.1 时间沿革

时间 事件 依据
1990 年代 受试者在贝斯以色列医院心律失常实验室完成记录 官方描述
1990 至 2003 年 各记录注释文件的文件时间戳分布区间 目录列表
1997 年 6 月 各数据体的文件时间戳集中在两日 目录列表
1999 年 8 月 3 日 PhysioNet 以 v1.0.0 发布 官方页面
2000 年 3 月 记录清单文件的文件时间戳 目录列表
2012 年 2 月 全部头文件的文件时间戳同日 目录列表
2019 年 2 月 20 日 补入 SHA256 校验文件 目录列表

时间戳只能说明文件何时被写过,不能直接当成采集日期。数据体集中在 1997 年 6 月,说明那段时间做过一次统一的格式整理;头文件集中在 2012 年 2 月,说明后来又有过一次批量修订。采集本身发生在更早的年份,官方只笼统写作 1990 年代。

文件 时间戳区间 能说明什么
数据体 1997 年 6 月 一次批量转换
头文件 2012 年 2 月 一次批量修订
注释 1991 至 2003 年 分批生成
校验文件 2019 年 2 月 后补

8.2 在 PhysioNet 心律谱系里的位置

谱系分支 代表库 与本库的关系
心律失常分类 MIT-BIH 心律失常库 阳性对照,与本库互补
长时程 Holter 长时程库、长时程 ST 库 同为长记录,人群不同
正常心律 本库、nsr2db、Fantasia 同一判读口径的三种形态
房颤 房颤库、房颤 RR 库 阳性侧的另一大类
室性事件 CUDB、VF 类库 极端阳性,用于急救算法
可穿戴 单导联挑战赛数据 现代设备,采样率更高

这张表说明一件事:PhysioNet 的心律谱系是按「事件类型 × 记录形态」铺开的二维网格,本库占据的是「无事件 × 长时程」这一格,且是这一格里唯一带波形的。

8.3 谁在用它,用来做什么

使用者类型 典型用途 需要额外准备
检测算法工程师 误报压制、阈值校准 自建阴性样本池
心率变异性研究者 长程指标与昼夜分段 先做质量过滤
信号质量研究者 质量分类的标注来源 核对标签覆盖
教学人员 演示正常节律与真实噪声 挑一段含伪迹的片段
数据平台建设者 WFDB 格式的样例 无,工具链现成

第一类最依赖它,也最容易误用它:拿十八条记录切出几万个窗,随机划分训练测试,报出一个很高的准确率,再在真实数据上失效。问题不在数据,在切分。

引用场景 该引到哪一层 常见漏引
论文数据来源 数据集加 DOI 只写 PhysioNet
方法段的格式说明 平台文献 漏掉格式来源
许可声明 许可名称与版本 漏写版本
复现包 下载日期 只写版本号

8.4 二十七年里它剩下什么

时间点 它当时的作用 今天的作用
1999 年 正常心律的长时程参照 仍是主要阴性来源
2010 年前后 心率变异性研究的标准素材之一 被更大规模库部分替代
今天 阴性对照与质量标注来源 定位收窄,但未失效

它的价值在收窄,而不是消失。可穿戴数据里已经有一批采样率更高、人数更多的正常记录,但往往没有逐搏标注,也没有判读结论。本库的不可替代性,正转向「少数带判读与逐搏标注的长记录」。

§9 使用指引

9.1 三种角色的路径

角色 起点 第一个产出 常见卡点
算法工程师 先读 §2.2 字段字典与 §5.4 索引脚本 一张带时长的记录清单 忽略增益为 0
心率变异性研究者 先读 §4.3 注释两层 一条可用的 RR 序列 未过滤非心搏标注
教学人员 先读 §4.2 的案例 一张二十四小时概览图 按 360 Hz 算时长

三条路径的共同第一步是确认采样率与标定状态;这两项一错,后面所有换算跟着错,往往到画图时才暴露。

9.2 一条最短的可用流程

#-- 装工具
pip install wfdb numpy matplotlib

#-- 取一条记录的头文件,先看结构
curl -s https://physionet.org/files/nsrdb/1.0.0/16265.hea
import numpy as np
import wfdb
import matplotlib.pyplot as plt

rec = wfdb.rdrecord("16265", pn_dir="nsrdb/1.0.0")
fs = rec.fs
x = rec.p_signal

hour = fs * 3600
prof = [np.std(x[i:i + hour, 0]) for i in range(0, len(x) - hour, hour)]

fig, ax = plt.subplots(2, 1, figsize=(11, 6), sharex=False)
ax[0].plot(np.arange(len(x[:hour * 6])) / fs / 3600, x[:hour * 6, 0], lw=0.3)
ax[0].set_xlabel("hours")
ax[0].set_ylabel(rec.sig_name[0])
ax[1].plot(np.arange(len(prof)), prof, marker="o", lw=0.8)
ax[1].set_xlabel("hour index")
ax[1].set_ylabel("std per hour")
fig.tight_layout()
fig.savefig("16265_overview.png", dpi=150)

这段流程的目标不是建模,而是建立直觉:前六小时画出来看波形与噪声的变化,再按小时算一个粗粒度统计量,看夜间与白天是否有系统差异。§4.2 的案例用同一套读法即可复现,只是它把重点放在头文件的三行结构上。

9.3 引用方式

字段 内容 用途
数据集 MIT-BIH Normal Sinus Rhythm Database v1.0.0,PhysioNet,1999 数据来源
标识 DOI 10.13026/C2NK5R 精确解析
平台 Pollard T 等,PhysioNet as a global platform for biomedical research,Nature Health,2026 平台引用
背景 Goldberger A 等,PhysioBank、PhysioToolkit 与 PhysioNet,Circulation,2000 格式与平台沿革
许可 ODC-BY 1.0 署名要求

官方页面没有单列数据集论文,只提供平台文献的引用格式。写论文时通常是一行数据来源加一行平台文献;若方法段需要说明格式来源,再补 2000 年那篇 PhysioBank 的文章。

9.4 复现一份最小报告的四步检查

检查点 预期 不符时的常见原因 处理
通道数 2 头文件被截断 重新取头文件
采样率 128 手写了 360 或 250 一律从 fs 字段取
单位 空或未标定 误当毫伏使用 改为相对量
注释 以心搏为主 混入质量标记 按符号过滤后再算 RR

第三步最容易被跳过。多数心电库的增益是 200 或 1000,读出来就是毫伏;这份库写 0,数值没有物理单位。两类数据混在一条流水线里,直接比较就会出问题。

9.5 三类人群的最短路径

只想要一张图。 装 WFDB,读一条记录,取前六小时画出来。二十分钟内可以完成,适合第一次接触这份数据的人建立直觉。

要一份可用的 RR 序列。 先读 atr,滤掉非心搏标注,再换算成秒并按小时切段。关键不在算法,在过滤规则。

要一个阴性评测集。 按记录切分,留四到六条做测试,其余做训练或调参;再按小时对齐阳性样本的采样量,避免阴性侧因时长过长而隐式加权。这条路径的关键是切分单位,不是窗长。

路径 最少步骤 主要风险
只看图 读一条记录,画六小时 采样率写错导致时间轴失真
做 RR 读注释、过滤、换算、分段 混入质量标记
做评测 按记录切分、按小时配平 按窗随机切分造成泄漏

9.6 复现性清单:别人能不能照你的描述重建

必写项 为什么必须写 常见缺漏
使用的记录名 编号不表意,无法从描述反推 只写「选取若干条」
采样率来源 128 容易被写成别的值 未说明取自头文件
标定处理方式 增益为 0 影响所有振幅结论 默认按毫伏处理
注释过滤规则 影响 RR 序列的干净程度 未交代
切窗长度与步长 直接决定样本数与泄漏风险 只给窗长不给步长
切分单位 按记录切与按窗切结论不同 只写「随机划分」
阳性数据配比 决定阴性侧的隐式权重 未说明如何配平
下载日期 官方可能补入新文件 只写版本号

八项里最容易被忽略的是第七项。阴性样本往往比阳性样本长得多,若不配平,模型学到的第一件事是「长记录多半正常」。把这个比例写清楚,比多报一个指标更有价值。

§10 AI 使用声明

项目 内容
写作方式 由人工智能辅助撰写,人工校核事实与表述
事实来源 官方项目页、RECORDS 与 ANNOTATORS 清单、十八条头文件首行、目录文件列表
未使用的手段 未下载全量数据做分布统计,未做标签频次、空值率或逐条样本明细分析
数字口径 官方给出什么就写什么;时长与总量为按头文件样本数换算的推导值,已标注
不确定项处理 导联位置、注释标签集合等官方未说明处,写作「未注明」而非补全
表格中的预期值 单日数据量等按位深与路数推算,明确标为几何推算
封面图 由生成模型按风格提示词产出,不含真实数据
更新责任 若官方页面修订版本或文件列表,以官方为准

常见误读(避坑清单)

说法 实际 证据
这是健康志愿者库 受试者为转诊后排除诊断者 官方描述写 referred、no significant arrhythmias
它和 nsr2db 是同一份数据的两版 两份独立数据集,一份有波形一份没有 两个 DOI、两个提交者、两个发布年份
十八个人代表成年人总体 13 女 5 男,年龄 20 至 50 岁 官方描述
每条记录一小时 23 至 26 小时 头文件样本数除以 128
采样率是 360 Hz 128 Hz 头文件第一行
有十二导联 只有两路,且未注明导联位置 头文件通道名 ECG1、ECG2
振幅可以直接读成毫伏 增益字段为 0,无标定 头文件通道行
注释只有心搏 官方写心搏与信号质量两类 ANNOTATORS 清单
可以直接当训练集 只有 18 条,无官方划分 目录与清单
正常意味着没有任何早搏 判读阈值是「显著」而非「任何」 官方用词 significant

FAQ

问:NSRDB 和 nsr2db 是同一个库吗?
答:不是。NSRDB 是 MIT-BIH Normal Sinus Rhythm Database,18 条带完整波形的长记录;nsr2db 是 Normal Sinus Rhythm RR Interval Database,54 条记录只保留心搏时刻,原始波形没有公开。两者发布时间、提交者、DOI 都不同,唯一相同的是判读口径(§6.2)。

问:这 18 个人是完全健康的志愿者吗?
答:不是。官方写的是转诊至心律失常实验室、判读后未发现显著心律失常的受试者。他们先有做动态心电的临床理由,之后才被排除出显著心律失常,所以更准确的说法是「阴性者」而不是「健康人」(§3.3)。

问:采样率和导联数是多少?
答:每条记录两路心电,头文件命名为 ECG1 与 ECG2,采样率 128 Hz,12 位量化,format 212。官方没有说明两路的导联位置,因此不能假定它等价于某个标准导联组合。

问:有逐搏标注吗?
答:有。ANNOTATORS 把注释器写为 atr,说明是「参考心搏与信号质量标注」。心搏位置可直接用于 RR 序列,质量标注可用于筛掉不可用段;具体标签集合需要读注释时自行确认。

问:为什么振幅不能直接当毫伏用?
答:头文件的增益与基线字段都写 0,官方没有给出数字量与毫伏的换算系数。读出的数值只能做相对比较;若论文要写绝对电压,必须换带标定的数据源(§7.3)。

问:能用来训练心律失常检测模型吗?
答:适合做阴性样本与外部验证,不适合单独做训练集。它提供长时段、真实噪声下的正常节律,正好补上阳性库缺少的对照;但只有 18 人,且没有官方划分,直接报泛化性能会被样本量限制(§5.6)。

问:每条记录到底多长?
答:23.1 至 26.0 小时,按头文件样本数除以 128 Hz 换算。最短的是 17052,最长的是 16483 与 18177。官方页面没有给出时长范围,这个区间是逐个读头文件得到的。

问:总共有多少小时?
答:十八条合计约 437 小时,接近十八天半。这是按样本数相加的推导值,官方只给出整包体积,没有给出总时长。

问:为什么记录名是五位数字?
答:这些编号沿用院内登记序列,与同院其它心电库共享同一编号空间,所以不连续、也不表意。不能从编号推出年龄、性别或采集日期(§3.5)。

问:两路信号是哪个导联?
答:官方未注明。头文件只写 ECG1 与 ECG2,既没有电极位置,也没有导联名。做依赖导联轴向的分析之前,需要先承认这个前提缺失。

问:可以商用吗?
答:可以。许可为 ODC-BY 1.0,允许包括商用在内的使用,条件是署名。署名应写到数据集、DOI 与 PhysioNet 平台三层。

问:它和 Fantasia 怎么选?
答:要严格筛查的健康人与呼吸信号,选 Fantasia;要日常活动中的长时程正常波形,选本库。前者干净但只有两小时,后者真实但只有十八人(§6.4)。

术语表

术语 英文 在本库中的含义
正常窦性心律 normal sinus rhythm 判读结论,指未见显著心律失常
动态心电 Holter monitoring 连续佩戴一昼夜以上的心电记录
长时程 long-term 本库指 23 小时以上的单条记录
心搏 beat 一次心室激动,注释的基本单位
逐搏标注 beat annotation 每个心搏的样本位置
信号质量 signal quality 对一段信号可用性的判断
注释器 annotator 注释类型,本库为 atr
头文件 header file WFDB 文本描述,后缀 hea
数据体 data file 二进制样本,后缀 dat
注释文件 annotation file 心搏与质量标签,后缀 atr
浏览脚本 xws script 供在线浏览器打开记录的小脚本
格式码 212 format 212 12 位样本两两打包成 3 字节
交错存放 interleaved 同一帧的多路样本相邻存放
增益 gain 数字量到物理量的换算系数,本库为 0
基线 baseline 零电平对应的数字量,本库为 0
标定 calibration 确定增益与基线的过程,本库缺失
采样率 sampling rate 每秒样本数,本库 128
奈奎斯特频率 Nyquist frequency 可分析带宽上限,本库约 64 Hz
RR 间期 RR interval 相邻两次心搏的间隔
心率变异性 heart rate variability 由 RR 序列派生的波动指标
误报 false positive 把正常判为异常
阴性样本 negative sample 无目标事件的样本
阳性样本 positive sample 含目标事件的样本
记录级切分 record-wise split 以整条记录为单位划分数据集
窗级切分 window-wise split 以切出的窗为单位划分,易泄漏
域适应 domain adaptation 跨设备或跨人群迁移模型
开放许可 ODC-BY 1.0 允许商用,需署名

附录 A:核心数字核对表

项 值 来源 来源层级
受试者数 18 官方描述 官方
男性 5 名,26 至 45 岁 官方描述 官方
女性 13 名,20 至 50 岁 官方描述 官方
记录数 18 RECORDS 清单 官方
通道数 2 头文件首行 官方文件
采样率 128 Hz 头文件首行 官方文件
量化解位 12 位 通道行格式码 官方文件
增益 0 通道行 官方文件
单条最短 23.13 小时 17052 头文件换算 推导
单条最长 25.96 小时 16483、18177 头文件换算 推导
总时长 约 437 小时 十八条样本数相加 推导
总样本数 约 2.02 亿点 十八条样本数相加 推导
整包体积 582.7 MB 官方页面 官方
版本 1.0.0 官方页面 官方
发布日期 1999-08-03 官方页面 官方
DOI 10.13026/C2NK5R 官方页面 官方
许可 ODC-BY 1.0 官方页面 官方
注释类型 atr,心搏与信号质量 ANNOTATORS 清单 官方文件

附录 B:数字的来源分层

层级 含义 本页涉及的数字
官方页面 PhysioNet 项目页直接给出 人数、性别年龄构成、记录数、体积、版本、日期、DOI、许可
官方文件 头文件、清单、目录列表 采样率、通道数、位深、增益、样本数、文件体积、注释类型
论文摘要 平台文献与背景文献 不作规模数字来源,仅用于引用与沿革
推导 由官方数字换算 单条时长、总时长、总样本数、单日数据量
工作假设 依据文件推断、官方未确认 编号沿用院内序列、时段分布对应装机习惯

前两层可直接引用;第三层只用于说明生态位;第四层可复算,论文引用时应自行计算;第五层必须写明是推断。

附录 C:完整参考文献

序号 文献 用途
1 PhysioNet. MIT-BIH Normal Sinus Rhythm Database v1.0.0. 1999-08-03. DOI 10.13026/C2NK5R. 官方数据页
2 Pollard T, Moody BE, Lehman L, Gow B, Fernandes C, Xie C, Johnson A, Mark RG, Heldt T. PhysioNet as a global platform for biomedical research. Nature Health, 2026. 平台引用
3 Goldberger A, Amaral L, Glass L, Hausdorff J, Ivanov P, Mark R, Mietus J, Moody G, Peng CK, Stanley H. PhysioBank, PhysioToolkit, and PhysioNet. Circulation 101(23):e215-e220, 2000. 格式与平台沿革
4 Moody GB, Mark RG. The impact of the MIT-BIH Arrhythmia Database. IEEE Eng in Med and Biol 20(3):45-50, 2001. 同系列注释体系背景
5 PhysioNet. Normal Sinus Rhythm RR Interval Database v1.0.0. 2003-03-03. 对照库,用于区隔说明
6 Open Data Commons. Attribution License v1.0. 许可文本

附录 D:任务代码

一段把全库读成索引、按长度分层、并按记录切分的脚本。

import re
from pathlib import Path

def read_head(p):
    lines = Path(p).read_text(encoding="utf-8", errors="replace").splitlines()
    f = lines[0].split()
    fs = float(f[2].split("/")[0])
    return {
        "name": f[0],
        "fs": fs,
        "n": int(f[3]),
        "hours": int(f[3]) / fs / 3600,
        "start": f[4] if len(f) > 4 else "",
        "leads": [ln.split()[-1] for ln in lines[1:1 + int(f[1])]],
    }

rows = [read_head(p) for p in sorted(Path("nsrdb").glob("*.hea"))]
rows.sort(key=lambda r: r["hours"])

long_half = rows[len(rows) // 2:]
short_half = rows[:len(rows) // 2]
test = long_half[:2] + short_half[:2]
train = [r for r in rows if r not in test]

print(len(rows), len(train), len(test))
print([r["name"] for r in test])
print(sum(r["hours"] for r in rows))

脚本里有两处刻意的设计。第一,按 hours 排序后再分层抽样,保证测试集里长短记录各占一半,避免测试集全落在某一档长度上。第二,切分单位是记录名,不是窗;同一条记录的任何片段只能出现在一侧。

这套划分只有四条测试记录,统计功效很弱,它的作用不是给出可信指标,而是让流程可复现。若要用它做正式评测,应把阳性库一并纳入,并按小时配平两侧的采样量。

附录 E:如果只记五件事

序号 要点
一 18 名受试者、18 条 23 至 26 小时的双导联动态心电,合计约 437 小时
二 「正常」是判读结论,指未发现显著心律失常,不等于健康人样本
三 128 Hz、12 位、增益字段为 0,能测节律不能测绝对电压与高频形态
四 atr 注释含心搏与信号质量两类,是本库少见的双用途标注
五 与 nsr2db 的区别是「有没有波形」,与心律失常库的区别是「正常与异常」

编辑说明

本页按 v4 编辑纪律撰写:只写规模、结构、边界三类数字,不做分布统计与逐条样本明细;官方未说明处写「未注明」,不代为补全。单条时长、总时长、总样本数与单日数据量为按头文件样本数换算的推导值,已在附录 B 单独分层。若 PhysioNet 修订版本或文件列表,以官方为准,本页随之更新。


相关数据集导航

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

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

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

返回 AI-Ready 数据集