信息速览
一九八〇年代末,一项被写进教科书的心律失常药物试验得出了一反直觉的结论:把心梗后病人的室性早搏压下去,死亡反而增加。试验因此提前终止,两个药物组被叫停。这场试验留下的东西通常被记成一条临床教训,很少有人记得它还留下了几十万小时的磁带——而且是同一批人在用药前与用药中各录了一次的那种。
CAST RR 间期子研究库就是从那批磁带里抢救出来的一小部分。华盛顿大学的 Phyllis Stein 从试验的数据协调中心取得带子,挑出用药确实有效、并且坚持用下去的人,把两次记录都做成逐搏注释,2004 年交给 PhysioNet。它最终的形态相当极端:809 名受试者、1543 条记录、每条约 24 小时、累计约 1.5 亿个 RR 间期,而整库里没有一个采样点。
这意味着它是一件用途很窄但很难替代的工具。窄到什么程度:你想要波形,一点都没有;你想要频域指标,六成记录不可靠;你想拿它代表普通人群,它是心梗后、频发早搏、还对药物有反应的一小撮人。难替代到什么程度:公开数据里,同一个人、同一套生活节律、跨一次长期用药的两次 24 小时逐搏记录,几乎找不出第二份。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 全名 | CAST RR Interval Sub-Study Database |
| 俗称与目录名 | crisdb(易被误读为 CRISPR 相关,实际指 CAST) |
| 发布方 | PhysioNet(原始数据由 NHLBI 支持的 CAST 试验产生) |
| 整理者 | Phyllis Stein,华盛顿大学医学院,圣路易斯 |
| 首次发布 | 2004 年 7 月 2 日,版本 1.0.0 |
| 受试者数 | 809 名 |
| 记录数 | 1,543 条 |
| 配对结构 | 734 人各有用药前与用药中两条;其余仅有单条 |
| 每条时长 | 约 24 小时 |
| 累计心搏 | 约 1.5 亿个 RR 间期 |
| 信号内容 | 无。仅有逐搏注释与头文件 |
| 文件格式 | WFDB:.hea 头文件 + .atr 注释 + RECORDS 清单 |
| 时间基准 | 头文件声明 128 Hz,个别记录重标定为 125.44 Hz |
| 分组 | e=恩卡尼,f=氟卡尼,m=莫雷西嗪 |
| 记录名 | dnnnx:药物字母 + 三位编号 + a(基线)/b(用药中) |
| 许可 | ODC-BY 1.0,免注册 |
| 整库体积 | 未压缩约 615 MB |
| DOI | 10.13026/C25P42 |
§1 它要解决的具体麻烦
1.1 心率变异性研究缺的从来不是算法,是同一个人用药前后的对照
想回答"抗心律失常药会不会改变心率变异性",最干净的设计是同一个人的自身对照:用药前录一天,用药稳定后再录一天,其余条件尽量不变。这个设计在纸面上简单,在现实里几乎无法执行,因为它同时要求三件稀缺事——一批需要长期服这类药的患者、两次各 24 小时的 Holter、以及一次能把药物真正吃下去且确实起效的干预。
前瞻性做这件事在今天已经不可能。恩卡尼与氟卡尼因死亡率问题在 1989 年被叫停,莫雷西嗪在 CAST-II 里同样因死亡率趋势提前终止,这三个药再也没有机会进入这种规模的新试验。也就是说,这个对照设计只存在于历史里,只能靠回溯抢救。
抢救出来的东西就长成了这个库的样子:配对、长时程、逐搏,但没有波形。取舍很明确——当年保存磁带本体的成本高,做注释的成本相对低,而子研究要回答的问题是时间域的心率变异性,用注释就够。于是波形被舍弃,注释被留下。这个取舍决定了今天所有能用与不能用的边界。
1.2 三条常见的错误期待
第一条,期待它是"又一个 Holter 波形库"。它的记录里零条信号通道,头文件第一行就写着 0 个信号、0 个采样点。用 wfdb.rdrecord 去读会直接报错,能读的只有 rdann。很多人第一次下载后以为文件损坏,实际是这份数据本来就只有一层注释。
第二条,期待它是"CAST 全队列的缩影"。CAST 主试验入组三千五百余人,本库只有 809 人,而且是从中再筛过的:用药有效、首次尝试即把早搏压下去八成以上、并且坚持用同一种药。这是疗效筛选之后的人群,不是随机样本,更不是"心梗后人群"的代表样本。
第三条,期待它"既然是 RR 间期,就能直接算 LF/HF"。频域指标要求时间轴足够准,而这批磁带里约六成录制时没有校准定时信号,走带速度的波动会在频谱上留下假峰。官方把这一点写进了局限清单,原论文也只报了时域指标。想算频域,得先按头文件字段筛记录,筛完剩下的样本量会掉一大截。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 长时程 RR 间期序列 | 1543 条近 24 小时逐搏注释,累计约 1.5 亿个间期 | 够,这是它的本体 |
| 同一人用药前后对照 | 734 人各有 a、b 两条记录 | 够,公开数据里罕见 |
| 时域心率变异性(SDNN、SDANN 等) | 注释完整,可直接差分 | 够,原论文就是这么用的 |
| 频域心率变异性(LF、HF、LF/HF) | 约四成记录有校准定时信号 | 部分够,必须先筛 |
| 心搏形态分析 | 无波形 | 不够,完全不可能 |
| 室性早搏负荷统计 | 有 V 类标签,但发生率可能被低估 | 可做趋势,不宜做绝对值 |
| 房颤或起搏心律研究 | 相关受试者被排除在 Stein 的研究之外 | 不够,样本被系统性剔除 |
| 普通人群或健康基线 | 全部为心梗后、频发早搏者 | 不够 |
| 药物疗效的因果推断 | 无随机化后的完整对照臂,无安慰剂组 | 不够,只能做自身前后描述 |
| 训练深度学习模型 | 无波形,只有变长序列 | 可做序列模型,不可做卷积 |
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 你在做心率变异性的纵向研究,需要"干预前后同一人"的数据 | 提供 734 组配对记录,间隔与日期偏移都保留 | 先按受试者编号重建配对(§5.5),再确认两条记录的时长是否齐整 |
| 你手上有一个 RR 序列模型,想找一个跨度以年计的验证集 | 记录跨 1987 至 1991 年,季节跨度真实 | 用头文件日期做时间外推划分,别随机切 |
| 你在研究药物对自主神经的影响,苦于没有人体长时程数据 | 三种药物的分组本身就是天然的三臂 | 注意没有安慰剂臂,结论只能停在"用药前后有差异" |
| 你要做频域算法,需要一个有已知伪影的真实数据集 | 六成记录带未校准时钟,是现成的压力测试材料 | 用头文件字段分层报告,把有/无定时信号当协变量 |
| 你在教 HRV 分析,需要一条 24 小时的真实序列 | 单条记录即可撑起一整节课 | 用 §2.3 的流程导出,注意年龄只有区间 |
| 你在核对某篇 2000 年前后 HRV 论文的复现性 | 原论文用的正是这批数据 | 先对齐人群定义(734 还是 769,见 §3.3) |
1.5 一句话判断
它是一份被时间封存的对照实验:波形没了,只剩心跳的时刻,而恰恰是这个残缺的形态,让"同一个人用药前后"这件事在三十多年后仍然可以被重新计算。
1.6 不适合谁:四条边界
不适合任何需要波形的任务。 形态分类、ST 段分析、QRS 宽度测量、导联定位,一律无法开展。这不是数据质量问题,是数据不存在。
不适合把结论外推到普通人群。 入组要求是两年内急性心梗,且预处理 Holter 上室性早搏每小时不少于六次;九十天内入组者左室射血分数须不高于 55%,之后入组者须不高于 40%。这是一个心功能受损、心律失常负荷高的人群。
不适合做药物疗效的因果结论。 库内只有用药前后,没有安慰剂对照,也没有随机化后的完整随访。早搏抑制率八成以上是入组条件,不是结果变量。任何"某药改善 HRV"的表述都越过了数据能支撑的范围。
不适合当作 CAST 试验的代表样本。 CAST 主试验三千五百余人,这里 809 人,且是疗效筛选后的子集。用它估计 CAST 整体的死亡率或事件率会系统性偏低,因为被排除的正是用药无效者。
§2 数据构成与规格
2.1 一条记录只有一层:注释
WFDB 格式的记录通常由头文件、信号文件、注释文件三件套构成。这个库只有两件:.hea 与 .atr。头文件声明了零条信号通道,因此不存在 .dat,也没有任何采样点可读。
除记录本身,顶层还有三份清单文件:RECORDS 是全库记录名清单,一行一条,带药物目录前缀;ANNOTATORS 声明注释来源与角色;SHA256SUMS.txt 给出全库校验和。逐条比对文件是否存在,是判断一份心电数据能否做形态分析的最快方法——.atr 在而 .dat 不在,就意味着只能做时序分析,不存在第二条路。
头文件第一行的形式是 f004a 0 128 0 10:00:00 27/03/1989。第二个字段 0 表示信号通道数,第三个字段 128 是时间基准(每秒 128 个时间单位),第四个字段 0 是每通道采样点数,其后是起始时刻与日期。这里是注释时间的分辨率基准,不是波形采样率。
这一点值得单独强调,因为它决定了后续所有时间换算。注释里的时刻是整数,单位是 1/128 秒;把它转成秒要除以 128。个别记录的头文件写的是 125.44,那不是笔误,是重标定的结果。
2.2 字段与标签的完整字典
注释符号沿用 PhysioBank 的心搏类型定义。官方页面只描述了其中几类的语义,其余按平台通用码表理解。
| 符号 | 含义 | 官方是否明说 | 在本库中的典型用法 |
|---|---|---|---|
N |
正常心搏 | 是(N-N 间期为分析对象) | 绝大多数搏动 |
V |
室性早搏 | 是 | 官方称几乎肯定是室早,但发生率可能低估 |
A |
室上性早搏 | 是 | 同上,几乎肯定是室上早 |
Q |
未分类 | 是 | 手工插入的搏动、起点测量错误者、超范围间期之后的搏动 |
F |
融合波 | 否 | 按通用码表理解,官方未逐一说明 |
f |
融合波(与正常搏动融合) | 否 | 同上 |
L / R |
左/右束支阻滞型心搏 | 否 | 同上 |
j / e |
交界性逸搏等 | 否 | 同上 |
+ |
节律改变标记 | 否 | 注释文件可能含,官方未展开 |
头文件的注释行是这份数据里信息密度最高的部分。每一行以 # 开头,字段固定。
| 头文件字段 | 示例 | 含义 |
|---|---|---|
<age-range> |
60-64 |
年龄区间,5 岁一档 |
<sex> |
Male |
性别 |
<medication> |
None / Flecainide |
该条记录时的用药状态 |
<RR-low-limit(sec)> |
0.656 |
分析所关注的 NN 间期下限 |
<RR-high-limit(sec)> |
1.164 |
分析所关注的 NN 间期上限 |
Start time |
10:00 |
记录开始时刻 |
First beat |
10:02:37.585 |
首个心搏的相对时刻 |
Note |
recording with a timing signal |
是否含校准定时信号 |
Note |
flutter-compensated |
是否做过扑动补偿 |
Note |
reel-to-reel recording |
记录载体为卷盘式磁带 |
RR-low-limit 与 RR-high-limit 容易被忽略,实际很关键。它们是当年分析者划定的"值得精确测量"的区间,落在区间外的间期没有被认真修正,紧随其后的搏动被标成 Q。所以这两个值不是数据范围,而是标注策略的边界。
2.3 一条记录的完整解剖
以 f/f004a.hea 为例,全部内容只有六行。
f004a 0 128 0 10:00:00 27/03/1989
#-- Start time=10:00
#-- First beat=10:02:37.585
#-- <age-range>: 60-64, <sex>: Male, <medication>: None
#-- <RR-low-limit(sec)>: 0.656, <RR-high-limit(sec)>: 1.164
#-- Note: recording with a timing signal, flutter-compensated
逐行读下来能拿到这些信息:
| 行 | 可读出的事实 | 对下游的影响 |
|---|---|---|
| 第 1 行 | 记录名 f004a;无信号通道;时间基准 128;起始 10:00;日期 1989-03-27 | 时间换算基准,日期可用于季节性分析 |
| 第 2 行 | 记录从上午十点开始 | 无法确定是否跨夜,须配合时长判断 |
| 第 3 行 | 首个心搏在开始后 2 分 37 秒 | 说明前段空白,算小时负荷时要注意分母 |
| 第 4 行 | 年龄 60–64,男性,此刻未用药 | 基线记录,可与其 b 记录配对 |
| 第 5 行 | 有效 NN 区间 0.656–1.164 秒,约合 52–91 次/分 | 超出此范围的心率不被精确测量 |
| 第 6 行 | 有校准定时信号,已做扑动补偿 | 这条记录可用于频域分析 |
同一受试者的另一条记录 f004b 只差几处:日期变成 1989-05-02,用药字段变成 Flecainide,起始时刻变成 12:00,而 Note 变成了 reel-to-reel recording, not flutter-compensated。这一对记录正好展示了这个库最需要小心的地方:同一个人的两条记录,采集条件的可靠性可能完全不同。
f004b 0 128 0 12:00:00 02/05/1989
#-- Start time=12:00
#-- First beat=12:17:20.648
#-- <age-range>: 60-64, <sex>: Male, <medication>: Flecainide
#-- <RR-low-limit(sec)>: 0.617, <RR-high-limit(sec)>: 1.14
#-- Note: reel-to-reel recording, not flutter-compensated
块内的注释行按全篇统一格式写作 #--,头文件原文是单个井号加空格。
两条记录的日期相差三十六天,同一个随机偏移保留了这个间隔,但绝对日期是虚构的。官方特意说明虚构日期足够接近真实日期,因此季节效应研究仍然可以开展。
2.4 三个药物组与配对结构
记录名首字母对应受试者随机分配到的药物。这是 CAST 的原始设计,不是事后分组。
| 首字母 | 药物 | 中文名 | 组内说明 |
|---|---|---|---|
e |
Encainide | 恩卡尼 | 该臂于 1989 年 4 月被叫停 |
f |
Flecainide | 氟卡尼 | 同上,同期叫停 |
m |
Moricizine | 莫雷西嗪 | 延续至 CAST-II,后因死亡率趋势提前终止 |
末位字母表示该条记录所处的治疗阶段。a 是基线、用药前,此处的用药字段写 None,对应自身对照的前一半;b 是用药中,用药字段写着具体的药物名,对应后一半。把这两条放在一起,同一位受试者的"用药前"与"用药中"就成对了。
配对关系靠前四位(dnnn)识别。f004a 与 f004b 属于同一人,f004 是受试者标识。
| 结构 | 人数 | 记录数 | 说明 |
|---|---|---|---|
| 配对完整 | 734 | 1468 | 基线 + 用药中各一条 |
| 仅单条 | 75 | 75 | 只有一条可用记录,其余条件仍满足 |
| 合计 | 809 | 1,543 | 与 RECORDS 清单行数一致 |
这里有一处算术需要点明:734 乘 2 加 75 等于一千五百四十三,与官方给出的记录总数吻合,说明 734 是"有两条记录的人数"、75 是"只有一条的人数",两者相加得到 809。而原论文摘要写的是这个子研究共 769 人,与 734 相差 35,官方未解释差额构成。稳妥的表述是:存在两个口径,页面按记录结构给出 734 加 75,论文按入组条件给出 769,定义不同,差额原因未说明。
2.5 与同类资源的字段差异
把本库放进常见的心电数据里比较,最直观的差异是"有没有波形"这一列。
| 资源 | 波形 | 逐搏注释 | 长时程 | 配对设计 | 规模量级 |
|---|---|---|---|---|---|
| 本库 | 无 | 有 | 近 24 小时 | 有(734 组) | 809 人 |
| MIT-BIH 心律失常库 | 有 | 有 | 30 分钟 | 无 | 47 人 |
| MIT-BIH 恶性室性心律失常库 | 有 | 有 | 30 分钟 | 无 | 35 人 |
| 长期房颤库 | 有 | 有 | 24 小时级 | 无 | 84 条 |
| 正常窦性心律库 | 有 | 有 | 30 分钟 | 无 | 54 条 |
| 十二导联长时程库 | 有 | 有 | 30 分钟 | 无 | 32 人 |
这张表说明它的位置:在"时长"和"配对"两列上它罕见地都占优,在"波形"一列上它是唯一一个空的。这就是它的全部筹码与全部代价。
另一层差异在元数据粒度。多数 PhysioNet 心电库给到年龄的确切值或十岁分组,本库给的是 5 岁一档的区间,比如 60 到 64 被并作一格,想当连续协变量用只能取组中值,误差随之而来。性别是二分类,与多数库一致。真正的差别在另外四项上:它记录用药状态,而且这个字段就是分组的依据;它记录采集起始时刻,精确到分;它记录采集日期,虽经随机偏移但间隔真实;它还记录设备的可靠性标记,包括是否含校准定时信号、是否做过扑动补偿、磁带是卷盘式还是盒式。相比之下,诊断信息反而粗糙,全库统一为心梗后,没有逐条的临床诊断。设备可靠性标记是这份数据最被低估的资产——它把"这条记录能不能做频域"从猜测变成了查表。
§3 核心层 A:它的真实身份
3.1 CAST 是一场被提前终止的试验
心律失常抑制试验由美国国立心肺血液研究所资助,设计目的是检验一个当时被广泛相信的假设:心梗存活者身上的无症状或轻微症状室性早搏如果被压下去,死于室性心律失常的人数会减少。入组门槛是两年内发生过急性心梗,且预处理长时程心电记录上室性早搏不少于每小时六次;心功能门槛随时间收紧,九十天内入组者左室射血分数不高于 55%,此后不高于 40%。
试验共入组 3,549 例,随机分配恩卡尼、氟卡尼、莫雷西嗪或安慰剂。用药后早搏显著被抑制者继续用该药或安慰剂。1989 年 4 月,数据与安全监察委员会建议停用恩卡尼与氟卡尼两个臂,原因是这两个药物组的死亡率过高,死因主要为心律失常、伴休克的急性心梗、以及慢性充血性心衰。
随后进行的 CAST-II 只保留莫雷西嗪与安慰剂,分两个双盲随机阶段:一个是评估心梗后起始用药风险的十四天暴露期,一个是评估长期生存效应的阶段。CAST-II 同样提前终止,长期使用莫雷西嗪与不用药或安慰剂相比呈现死亡率升高的趋势。试验作者的结论是:用莫雷西嗪抑制无症状或轻微症状的室早,不仅无效,而且有害。
3.2 子研究为什么要挑"用药有效"的人
Stein 的研究问题不是"药物有没有害",那已经由主试验回答了。她要问的是:生存与心率变异性的变化之间是什么关系,而这种变化在抗心律失常治疗下如何体现。这个问题要求记录里同时有"用药前"和"用药中"两段,而且两段都可用。
于是她设了三条筛选:有可用的用药前与用药中记录;随机分配到的药物在首次尝试就把室早率压低至少八成;并且继续使用该药。三条都满足的有 734 人,其中 69 人在研究期内死亡。
这个筛选把数据变成了一个非常特殊的样本:它是"药物确实起效"的那部分人。所以任何涉及"药物效果"的分析,用这个库都会得到偏乐观的图景,因为无效者被抽走了。
3.3 809 的三层构成
| 层次 | 人数 | 条件 | 在库中的形态 |
|---|---|---|---|
| 主试验入组 | 三千五百余例 | 心梗后 + 早搏≥6 次/小时 + 心功能门槛 | 不在库内 |
| 子研究合格 | 769(论文口径) | 有可用双记录 + 首次用药即抑制八成 + 持续用药 | 论文分析对象 |
| 双记录齐备 | 734(页面口径) | 同上,且两条记录都可用 | a + b 两条 |
| 单记录 | 75 | 满足其余条件,仅一条可用 | 单条 a 或 b |
| 库内合计 | 809 | 734 + 75 | 一千五百四十三条 |
三个数字之间的关系要这样读:809 是库的规模,734 是有配对的人数,769 是论文的分析样本。它们不是同一个量的三种说法,而是三种不同的纳入标准。写论文时如果引用了 769,就不能同时说"734 组配对",除非把口径讲清楚。
还有一处细节:官方提到有少数被收入本库的受试者,因为出现心房颤动或起搏心律,被排除在 Stein 的研究之外。也就是说,库比论文多了一点东西。这批人仍在库里,但不在论文的分析集里。
3.4 与 CAST 原始数据的关系
这条分界可以从四个方面看清。获取方式上,本库在 PhysioNet 公开、免注册下载,CAST 原始数据要向 NHLBI 申请并经过资格审核。内容上,本库只有逐搏注释与头文件,原始数据包含更完整的试验信息与随访字段。覆盖上,本库是 809 人,主试验是三千五百余人。许可上,本库是 ODC-BY 1.0,原始数据按申请协议走。用途也随之分开:本库适合方法学研究与算法评测,原始数据才支撑临床试验的二次分析。
有人在文献里看到"CAST 数据"就以为能下到全量,实际公开的只有这一个子研究,而且是被剥掉波形之后的版本。想做更广的分析,唯一的路径是走 NHLBI 的申请流程。
3.5 身份的三个易混点
第一,它不是 CRISPR 数据集。 crisdb 这个目录名里的 cris 来自 CAST RR Interval Sub-Study 的缩写组合,与基因编辑毫无关系。搜索引擎上以 crisdb 为关键词,很容易落到 CRISPR 相关的结果上,这是最常见的误判来源。
第二,它不是"CAST 数据库",而是 CAST 的一个子研究。 差别不只在规模,更在纳入标准:子研究只保留药物有效者。
第三,它不是波形库,也不是"RR 间期表格"。 它给的是逐搏注释,RR 间期需要自己差分得到。这个区别在工程上有实际后果:注释里保留了 Q 类搏动,差分时必须决定这些搏动怎么处理,处理方式不同,得到的序列长度与统计量都会变。
§4 核心层 B:质量与特色
4.1 标注是两遍扫描的产物
官方描述的方法很简短:全部记录由一位有经验的研究心律失常分析师按标准 Holter 分析流程扫描;心搏注释文件在第二遍编辑中修订,目的是识别测量错误的 RR 间期并剔除出后续分析。头文件里另记了少量附加信息。
这段话可以拆成三层含义。第一层是第一遍扫描:按标准 Holter 分析流程逐搏标注,得到初始注释。第二层是第二遍编辑:专门识别测量错误的 RR 间期,把它们剔除出后续分析,从而提高间期的可靠性。第三层是附加信息:头文件记下年龄、性别、用药、有效间期区间与设备标记,为后续分层提供依据。
需要强调的是,两遍都是人工。这不是算法初标加人工修正的模式,而是一位分析师从头到尾的工作。这带来两个后果:类型判断的一致性较好,因为出自同一双手、同一套标准;但工作量限制了规模,也意味着不存在"多标注者一致性"这类可以量化信度的指标。
4.2 时间轴:128 与 125.44
时间基准的差异值得单独讲,因为它是这个库里最技术性、也最容易踩的坑。
| 情形 | 头文件时间基准 | 原因 | 处理 |
|---|---|---|---|
| 常规 | 128 | 平台默认的注释时间分辨率 | 时刻除以 128 得秒 |
| 重标定 | 125.44 | 磁带记录速度 1.47 mm/s,扫描速度 1.50 mm/s,按比例折算 | 时刻除以 125.44 得秒 |
m010b 的头文件把这层意思写得很清楚:记录载体是卷盘式磁带,未做扑动补偿,时间已按记录速度与扫描速度之比重标定,即采样率从 128 Hz 调整为 125.44 Hz。
如果一律按 128 换算,这条记录的时间轴会偏大约百分之二。对 24 小时的记录来说,这是近半小时的累计误差;对 RR 间期这种以毫秒计的指标来说,这个偏差足以改变结论。反过来,把 1/128 秒误当成毫秒处理,误差是三个数量级,整个序列完全不可用。所以这里只有一条正确做法:读头文件的第三个字段,不要写死 128。
4.3 案例:f004 的两次记录
这是贯穿全文的例子,因为它把这份数据的优点与陷阱压缩在了同一个受试者身上。
f004a 是基线记录:1989 年 3 月 27 日上午十点开始,男性,年龄 60–64,未用药,有效 NN 区间 0.656 到 1.164 秒,有校准定时信号,做过扑动补偿。f004b 是用药中记录:1989 年 5 月 2 日中午十二点开始,同一位男性,服用氟卡尼,有效 NN 区间 0.617 到 1.14 秒,卷盘式磁带,无校准定时信号。
| 对比项 | f004a(基线) | f004b(用药中) | 含义 |
|---|---|---|---|
| 日期 | 1989-03-27 | 1989-05-02 | 相隔三十六天,偏移已保留间隔 |
| 起始时刻 | 10:00 | 12:00 | 一天中的时段不同 |
| 用药 | None | Flecainide | 配对的核心变量 |
| 有效 NN 下限 | 0.656 秒 | 0.617 秒 | 用药后上限心率提高 |
| 有效 NN 上限 | 1.164 秒 | 1.14 秒 | 下限心率也提高 |
| 定时信号 | 有 | 无 | 频域可用性不同 |
| 扑动补偿 | 已做 | 未做 | 同上 |
这一对记录能说明三件事。
第一,配对是真实的。同一个编号、同一个年龄区间、同一个性别,日期相隔一个多月,这与"用药前评估、开始用药、复查"的临床节奏吻合。
第二,两次采集的条件不对等。基线记录有定时信号且做了扑动补偿,用药中记录两者都没有。如果直接比较两条记录的频域指标,差异里混进了设备因素。这在配对设计里是个隐蔽的坑:配对控制了人,但没有控制设备。
第三,有效区间本身在变。用药后上下限都收紧了一点,说明当年分析者划定的关注区间随记录而调整。做跨记录比较时,用固定区间筛选和用各记录自己的区间筛选,会得到不同的序列。
§4.3 的案例在后面还会被引用两次:一次用来说明频域分析的分层策略,一次用来说明配对重建的实现。
4.4 Q 标签不是垃圾,是设计的一部分
Q 在这个库里出现的密度不低,容易被当成噪声直接丢掉。但官方对它的三条说明合起来,构成了一套明确的标注策略。手工插入的搏动一律标为 Q,也就是未分类;识别出起点测量不准的搏动,同样标为 Q;紧随异常长短 NN 间期的搏动,也标为 Q。至于漏检一个搏动后出现的约两倍长间期,官方只说明它属于噪声,没有讲这类位置的搏动是否改标 Q。
这三条的共同点是:Q 标记的是"这个搏动的时间或类型不可靠",而不是"这个搏动异常"。所以丢掉 Q 不等于丢掉异常搏动,恰恰相反,V 与 A 才是异常搏动,它们被保留了下来。
| 处理策略 | 序列长度 | 适用任务 | 风险 |
|---|---|---|---|
| 只保留 N | 最短 | 时域 HRV | 会丢掉部分真实异常节律 |
| 保留 N、V、A | 中等 | 早搏负荷统计 | 间期序列含异位搏动,需另做校正 |
| 全部保留含 Q | 最长 | 逐搏建模 | Q 的时刻不可靠,污染序列 |
| 丢掉 Q 后重新计算间期 | 中等 | 通用做法 | 跨 Q 段的间期被拉长,需截断 |
官方还提醒了一点:V 与 A 标签几乎肯定对应真实的室性与室上性早搏,但它们的发生率可能被低估,因为超范围的长短间期没有被认真修正,紧随其后的搏动被标成 Q 而不是 V/A。做早搏负荷统计时,这个方向的偏差是单向的——只会少算,不会多算。
4.5 频域可行性的分级
把设备标记与时长结合,可以得到一张实用分级表。§4.3 的案例正好跨两级:基线记录有定时信号且做过扑动补偿,属可用频域的一类;用药中记录是卷盘式磁带、无定时信号,只能做时域。同一位受试者的两条记录分属不同等级,这正是分层必须按记录做、不能按人做的原因。
| 等级 | 记录特征 | 可用指标 | 约占全库 |
|---|---|---|---|
| A | 有校准定时信号 + 已做扑动补偿 | 时域 + 频域 | 少数,官方未给比例 |
| B | 有校准定时信号,未做扑动补偿 | 时域 + 频域(需自查扑动) | 官方未给比例 |
| C | 卷盘式磁带,无定时信号 | 仅时域 | 官方称约六成属"无定时信号"一类 |
| D | 卷盘式 + 已重标定 | 时域,且须按 125.44 换算 | 官方未给比例 |
官方只给了"约六成磁带无校准定时信号"这一个比例,其余分档的具体数量没有公布。写分析计划时,应当把它当成分层变量,而不是当过滤器——先筛掉 C、D 会让样本量骤减,而且筛掉的人未必随机。
§5 核心层 C:取数与读取
5.1 目录结构
库的顶层目录很扁平,三个药物目录加一个历史目录。
| 路径 | 内容 | 数量 |
|---|---|---|
e/ |
恩卡尼组的记录 | 官方未分组公布 |
f/ |
氟卡尼组的记录 | 官方未分组公布 |
m/ |
莫雷西嗪组的记录 | 官方未分组公布 |
old/ |
早期版本遗留 | 官方未说明 |
RECORDS |
全库记录名清单 | 1543 行 |
ANNOTATORS |
注释角色声明 | 1 个文件 |
SHA256SUMS.txt |
校验和 | 全库文件 |
RECORDS 的每一行是带目录前缀的相对路径,例如 e/e001a。这一点与某些同类库不同——那些库只写记录名,路径要自己拼。直接用这份清单循环读取,不需要额外判断。
5.2 取数
整库未压缩约 615 MB,压缩包约 617 MB,一次下完没有压力。三种方式都可。
#-- 1. 只取清单,先看结构
curl -sL https://physionet.org/files/crisdb/1.0.0/RECORDS -o RECORDS
wc -l RECORDS
#-- 2. 取单个受试者的两条记录做试读
for r in f/f004a f/f004b; do
curl -sL "https://physionet.org/files/crisdb/1.0.0/${r}.hea" -o "$(basename $r).hea"
curl -sL "https://physionet.org/files/crisdb/1.0.0/${r}.atr" -o "$(basename $r).atr"
done
#-- 3. 或者整库同步
aws s3 sync --no-sign-request s3://physionet-open/crisdb/1.0.0/ ./crisdb
第二条命令只取两个文件,适合在正式下载前确认联通性。第三条是官方给出的对象存储路径,比递归 wget 稳定,也支持断点续传。
5.3 读头文件
wfdb 读不到信号,但能读头文件。头文件的注释行会原样出现在 comments 字段里。
import wfdb
h = wfdb.rdheader('f004a', pn_dir='crisdb/f')
print(h.fs) #-- 128.0:时间基准
print(h.sig_len) #-- 0:没有采样点
print(h.n_sig) #-- 0:没有信号通道
for line in h.comments:
print(line)
输出的最后几行就是那四条注释。想把它结构化,需要自己按冒号切分,因为平台没有为这些字段定义正式的名称。年龄区间取 <age-range>: 之后到逗号的一段,注意它是区间不是数值;性别取 <sex>: 之后到逗号,值是大写开头;用药取 <medication>: 之后到行尾,None 表示基线;NN 下限与上限分别取两个 RR 区间字段之后的值,都是浮点秒;磁带类型看 reel-to-reel 是否出现,出现即为卷盘式。
定时信号与扑动补偿这两项要特别小心,因为它们是否定式表述。not flutter-compensated 与 flutter-compensated 都包含后者,直接用子串判断会把未补偿的记录全部判成"已补偿";“没有定时信号"也可能写成否定句而不是正句的缺失。最稳的写法是把整行拆成"键: 值”,再在值里检查否定词,而不是对整行做包含判断。
5.4 从注释到 RR 序列
RR 序列由相邻两次心搏的时刻差得到。关键在于先确定哪些符号参与。
import wfdb
def rr_series(rec, subdir, keep=('N',), fs=None):
h = wfdb.rdheader(rec, pn_dir=f'crisdb/{subdir}')
scale = fs or h.fs
ann = wfdb.rdann(rec, 'atr', pn_dir=f'crisdb/{subdir}')
t = [s / scale for s, sym in zip(ann.sample, ann.symbol) if sym in keep]
return [b - a for a, b in zip(t, t[1:])]
rr = rr_series('f004a', 'f')
print(len(rr), rr[:5])
keep 的取值直接决定结果。只留 N 会得到最干净的序列,但跨越被丢弃搏动的间期会被保留成超长值,所以必须配一次区间截断。放行 N、V、A 三类,序列会包含异位搏动,做早搏负荷统计合适,但要把异位间期单独标记出来。全符号保留序列最长,同时把 Q 那些不可靠时刻一起收进来,不适合直接算 HRV。
那个"跨越式长间期"是这个库的已知问题。官方明确说序列里存在少量异常长间期,典型来源是 Holter 分析中的搏动检测错误——漏掉一个搏动,就会出现一个约两倍于正常值的间期。官方也承认罕见的窦性停搏可能贡献了少数几个,但由于原始心电图不可用,无法区分。
因此处理规则应当是:按头文件的上下限截断,而不是按统计量剔除。头文件给出的区间正是当年标注者的分析边界,用它与数据自身的标注策略保持一致;用三倍标准差之类的统计规则,会引入一套与原始设计无关的假设。
5.5 配对重建
配对靠记录名前四位识别,重建后可以按受试者做分组划分。§4.3 的案例恰好可以用来验证重建逻辑:f004 这个前缀下应当同时出现 a 与 b,且两条记录的年龄区间与性别一致,只有用药字段不同。
from collections import defaultdict
pairs = defaultdict(dict)
for line in open('RECORDS'):
path = line.strip()
if not path:
continue
sub, name = path.split('/')
pairs[name[:4]][name[-1]] = (sub, name)
both = {k: v for k, v in pairs.items() if 'a' in v and 'b' in v}
print(len(pairs), len(both))
输出应当是 809 与 734。如果第一个数字对不上,多半是 RECORDS 末尾有空行或换行被吃掉,按非空行计数即可。四个数字可以互相校验:非空行数应为一千五百四十三,也就是记录总数;唯一前缀数应为 809,即受试者总数;同时含 a 与 b 的前缀数应为 734,即配对完整的人数;只含单一后缀的前缀数应为 75,即只有一条记录的人数。任何一个对不上,都说明解析逻辑有问题,而不是数据有问题。
划分训练与测试时按前缀分组,不按记录名分组。同一受试者的两条记录共享年龄、性别、体质、生活节律,随机按记录切分会让同一个人落到两侧。
5.6 五个最容易出错的地方
| 位置 | 错误写法 | 后果 | 正确做法 |
|---|---|---|---|
| 读取 | 用 rdrecord 读信号 |
直接报错或返回空 | 只用 rdheader 与 rdann |
| 时间换算 | 写死除以 128 | 重标定记录偏 2% | 读头文件第三个字段 |
| 设备字段 | 子串判断 flutter-compensated |
not 开头的也被判为已补偿 |
先拆键值再看否定词 |
| 序列清洗 | 用统计规则剔除长间期 | 与原始标注策略冲突 | 按头文件上下限截断 |
| 数据划分 | 按记录随机切分 | 同一受试者泄漏 | 按记录名前四位分组 |
| 人群描述 | 说成"心梗后人群" | 忽略疗效筛选 | 写明"用药有效且持续用药" |
§6 与库内条目的关系
6.1 关系图谱
在心电与生理信号这一类里,本库的位置由两个轴决定:有没有波形、有没有配对。它落在"无波形 + 有配对"这个角上,几乎没有邻居。
| 数据类型 | 波形 | 配对 | 与本库的关系 |
|---|---|---|---|
| MIT-BIH 系列心律失常库 | 有 | 无 | 互补:它们给形态,本库给时长与配对 |
| 长期房颤库 | 有 | 无 | 互补:同为 24 小时级,一个有两导联波形,一个只有注释 |
| 正常窦性心律库 | 有 | 无 | 人群相反:那边是健康人,这边是心梗后 |
| 十二导联长时程库 | 有 | 无 | 维度不同:那边宽而短,本库窄而长 |
| 心率变异性专用库 | 多为有 | 少见 | 直接竞品,但配对设计罕见 |
| 可穿戴单导联库 | 有 | 少见 | 场景不同:那边是自由生活,这边是临床试验 |
| 本库 | 无 | 有 | 唯一角 |
如果你需要的正是"同一人、跨一次长期用药、两次 24 小时",替代品基本不存在;如果你需要的是别的任何组合,一般都有更合适的库。
6.2 检索路径
| 你要找的东西 | 检索词 | 会落到哪里 |
|---|---|---|
| RR 间期分析工具链 | ann2rr、wfdb-python、HRV howto |
§5.4 的读取方式 |
| 长时程注释型数据 | annotation-only、RR interval database |
§2.5 的对比表 |
| 心梗后 HRV 研究 | post-MI HRV、CAST |
§3 的身份说明与 §7.4 |
| 抗心律失常药与自主神经 | encainide、flecainide、moricizine |
§2.4 的分组表 |
| 磁带伪影与频谱失真 | wow and flutter、timing signal |
§4.2 与 §4.5 |
| 配对设计与自身对照 | paired Holter、pre-post |
§5.5 的重建流程 |
6.3 与其他库的分工判据
| 任务 | 主粮仓该用什么 | 本库的位置 | 原因 |
|---|---|---|---|
| 心搏形态分类 | 带波形的标注库 | 不参与 | 无波形 |
| 节律分类 | 带波形与节律标签的库 | 不参与 | 无波形、无节律标签 |
| 时域 HRV 的纵向变化 | 本库 | 主力 | 配对 + 24 小时 + 逐搏 |
| 频域 HRV 的方法验证 | 带定时信号的少量记录 | 辅助 | 六成记录不可用 |
| RR 序列异常检测 | 本库 | 主力之一 | 真实的长序列与真实的长间期噪声 |
| 药物对自主神经的影响 | 本库 | 唯一公开选项 | 三药分组 + 前后配对 |
| 人群基线建模 | 健康人群库 | 不适用 | 人群高度特化 |
| 波形生成或重建 | 带波形的库 | 不适用 | 没有可重建的目标 |
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
先纠正一个最容易发生的误判:把"没有波形"当成"数据质量差"。这两件事在评价体系里不在同一层。没有波形是数据形态的选择,它决定了适用任务的边界;质量差是数据在自身形态内不可靠。本库在自身形态内的可靠性相当高——两遍人工扫描、逐搏标注、设备条件逐条记录在案——但它能承载的任务范围很窄。
这个校正会改变五维评分的读法。如果按"通用心电数据集"打分,它在信号完整性与规模上都拿不到分;如果按"长时程 RR 间期与配对设计"打分,它在任务适配与结构完整性上接近满分。把这两套尺子混用,就会得出"这数据没用"或"这数据万能"两种相反的错判。
7.1 五维评分
按 DAIMS 的常用评价维度打分,每项 1 至 5 分,分数针对"作为长时程心率变异性研究数据"这个用途。
| 维度 | 分数 | 理由 |
|---|---|---|
| 数据规模 | 4 | 809 人、约 1.5 亿个间期,在 HRV 领域属大体量 |
| 标注质量 | 4 | 两遍人工、分析师单人完成,一致性无法量化 |
| 任务适配 | 5 | 配对加 24 小时,公开数据里罕见 |
| 文档完整 | 4 | 页面把人群、方法、五条局限写全,分组数量未公布 |
| 可获取性 | 5 | 免注册、ODC-BY、体量适中 |
| 形态完整性 | 1 | 无波形,是所有依赖形态的任务的硬约束 |
五项合计 22 分(不含形态完整性),加上形态完整性后是 23 分(满分 30)。这个分数结构说明它是一个专用工具:通用维度上缺一块形状,专用维度上接近满格。
7.2 标注质量的三个层次
第一层是类型判断。由一位有经验的研究分析师按标准 Holter 流程完成,第二遍编辑专门修订测量误差。类型标注的可靠性来源于人工与流程,但也因此无法给出标注者间一致性——只有一个人。
第二层是时刻精度。时刻来自注释采样点,单位 1/128 秒,理论上精度约 7.8 毫秒。但这是记录精度,不是生理精度:心搏起点本身的判定有误差,官方明确说测量起点错误的搏动被标成 Q。所以真实的时间误差大于名义精度。
第三层是覆盖完整性。官方承认 V 与 A 的发生率可能被低估,因为超范围间期未修正。这是单向偏差,做负荷统计时要写进局限。
这三个层次对应的可靠性并不相同,要分别交代。类型层的可靠性较高,威胁来自单人标注、没有一致性检验,引用时说明来源即可。时刻层是中等,威胁在于起点测量有误的搏动被标成 Q 而不是被修正,稳妥的做法是剔除 Q 之后按头文件区间截断。覆盖层偏低,威胁在于超范围间期未修正导致 V/A 被低估,所以只宜做趋势,不宜报绝对值。设备层不分高低,只分能否做频域,靠头文件字段分层即可。
7.3 已知的、可枚举的偏差
官方把局限写成了五条,逐条对应到下游影响如下。
| 偏差 | 官方表述要点 | 下游影响 |
|---|---|---|
| 无定时信号 | 约六成磁带为卷盘式或其它无校准定时信号的设备 | 频域分析出现走带速度波动造成的伪影 |
| 手工插入搏动 | 一律标 Q | 序列中混入时刻不可靠点 |
| 起点测量错误 | 同样标 Q | 同上 |
| 超范围间期未修正 | 关注区间外的 NN 未认真修正,其后搏动标 Q | V/A 发生率被低估 |
| 原始信号缺失 | 波形不可用 | 无法验证、无法修正、无法研究形态 |
| 异常长间期 | 多为漏检导致,少数可能是窦性停搏 | RR 序列含噪声,且无法区分来源 |
除官方列举之外,还有几条可以从数据结构直接读出、但不属于"官方局限"的事实,需要在方法学部分自行交代。
除官方列举之外,还有几条能从数据结构直接读出、却不属于"官方局限"的结构性偏差,需要在方法学部分自行交代。最要紧的是疗效筛选:只纳入首次用药即抑制八成以上者,这会让药物效应看起来比真实情况更好。其次是没有安慰剂臂:库内只有用药前后,无法把时间效应与药物效应分开。第三是人群特化:心梗后、频发早搏、心功能受损三者叠加,结论无法外推。第四是时段不匹配:基线多在上午,用药中可以在任意时刻,昼夜节律会混进前后差异。第五是设备不对等:同一人的两条记录可能来自不同设备,配对控制了人,没有控制设备。第六是年龄粗化到 5 岁一档,无法作连续协变量。第七是日期偏移,绝对日期虚构,季节分析可用、具体日期不可用。
第三条值得多讲一句。f004a 从上午十点开始,f004b 从中午十二点开始,这个差异本身就会影响 HRV——人的心率在一天中有明显的昼夜节律。配对设计消除了人与人的差异,但没有消除时段差异。做前后比较时,把起始时刻当作协变量,或者只在时段相近的子集里比较,是必要的稳健性检验。
7.4 外部验证矩阵
这个库在文献中的角色,可以从它的引用方式看出来。
| 验证角色 | 做法 | 讲得通的地方 | 风险 |
|---|---|---|---|
| 原研究的复现 | 按 2000 年论文的纳入标准重建分析集 | 数据就是那篇论文的来源 | 769 与 734 的口径差异会导致样本不一致 |
| HRV 与预后的关联 | 用死亡受试者做结局分组 | 734 人中有 69 人死亡,有结局 | 死亡数少,统计功效有限 |
| 方法学基准 | 在真实长序列上测 RR 清洗算法 | 含真实的长间期噪声 | 无金标准,只能比相对优劣 |
| 频域方法验证 | 只在有定时信号的子集上做 | 条件清楚 | 子集小且非随机 |
| 机器学习外部测试 | 把 RR 序列模型放到本库外测 | 人群与设备都不同 | 只有序列,没有形态特征 |
第一行是最常见的用法,也最容易出问题:原论文的分析集是 769 人,页面描述的结构是 734 组配对加 75 条单记录,想复现论文必须按论文的条件重建。
7.5 它为何能持续:一种无法再生的对照
它没有更新、没有扩版,二十多年只发过一个版本,却仍然是心率变异性研究里被反复取用的数据。原因不在规模,而在于它占着一个无法再生的位置:三种已退市药物、同一批人的用药前后、各 24 小时的逐搏记录。
想复制这个设计,需要重新找到一批需要长期服用这类药的患者,而这三个药已经不在那个适应症上使用;需要重新做两次 24 小时 Holter,成本高且伦理上难以成立;还需要这批患者恰好对药物有反应。三个条件叠加,实际上等于不可能。所以它不是"暂时没有更好的替代品",而是"结构上不会再有第二个"。这个属性让它的价值随时间上升而不是下降。
§8 生态位与历史
8.1 历史沿革
| 时间 | 事件 | 与本库的关系 |
|---|---|---|
| 1980 年代末 | CAST 入组与随访 | 原始磁带产生 |
| 1989 年 4 月 | 恩卡尼与氟卡尼臂被叫停 | e、f 两组的用药期在此前后结束 |
| 1990 年代初 | CAST-II 进行并提前终止 | m 组记录的来源 |
| 2000 年 3 月 | Stein 等发表 HRV 决定因素论文 | 子研究的分析成果 |
| 2004 年 7 月 2 日 | 数据库在 PhysioNet 发布 1.0.0 | 公开可获取的起点 |
| 至今 | 无新版本 | 结构与内容保持稳定 |
e 与 f 两组的"用药中"记录大多落在 1989 年上半年,m 组可以延伸到更晚,分组对应着试验进程。
8.2 与 CAST 及 CAST-II 的关系
三个层级的对应关系是:CAST 的四个臂里,恩卡尼与氟卡尼因死亡率过高被叫停,对应 e、f 两组;CAST-II 只留莫雷西嗪与安慰剂,因死亡率趋势提前终止,对应 m 组;子研究不新设任何臂,只回溯这三种药物的记录。
安慰剂臂不在库里。这是一个关键缺口:库内所有人都在某个时点用过药,没有一组"从未用药但同样随访"的对照。所以库内的"前后比较"只能回答"用药前后有没有变化",不能回答"变化是不是药物造成的"。
8.3 生态位:对照工具而非训练集
把它放在"主力粮仓"与"对照工具"这两个角色的对照里,区别就清楚了。主力粮仓负责大规模训练与预训练,前提是数据量大、标签细、有波形,失败模式是过拟合与标签噪声累积,代表资源是各类带波形的大规模心电库。对照工具负责自身前后比较与方法验证,前提是结构独特、条件清楚,失败模式是样本特化导致结论不可外推,代表资源就是本库这类专题型小库。
本库坐在后一列,而且坐得很稳。把它当训练集用,会立刻遇到"没有波形"这个硬墙;把它当对照工具用,它能提供别处拿不到的自身对照。
8.4 谁在用它,用来做什么
从公开文献的引用方式看,使用者集中在三类。第一类是心率变异性研究者,他们复现或扩展 2000 年论文的结论,关注人群定义、时域指标与结局关联。第二类是信号处理与算法组,他们在真实长序列上验证 RR 清洗与异常检测,关注长间期噪声与 Q 标签的处理方式。第三类是临床试验数据的二次利用者,他们把配对结构当作干预前后设计的模板,关注配对重建与设备分层。
第三类最少,但正是它把这个库与普通心电库区分开。它不只是"一批 RR 间期",它是一份带有干预结构的观察数据。
§9 使用指引
9.1 三种角色的路径
| 角色 | 第一天 | 第一周 | 注意事项 |
|---|---|---|---|
| 心率变异性研究者 | 读官方页面与头文件,跑通 §5.4 的序列提取 | 按受试者重建配对,做时域指标的自身前后比较 | 先定 Q 的处理规则,再算指标 |
| 算法工程师 | 取 §4.3 的案例两条记录,做可视化 | 在整库上测 RR 清洗算法,按设备字段分层报告 | 长间期的来源无法区分,别声称能区分 |
| 教学与临床工程 | 用单条记录演示 24 小时 RR 序列 | 用配对记录讲自身对照设计 | 强调没有安慰剂臂 |
9.2 一条最短的可用流程
#-- 1. 取清单与校验
curl -sL https://physionet.org/files/crisdb/1.0.0/RECORDS -o RECORDS
curl -sL https://physionet.org/files/crisdb/1.0.0/ANNOTATORS -o ANNOTATORS
cat ANNOTATORS
#-- 2. 取一个受试者的配对记录
for r in f/f004a f/f004b; do
curl -sL "https://physionet.org/files/crisdb/1.0.0/${r}.hea" -o "$(basename $r).hea"
curl -sL "https://physionet.org/files/crisdb/1.0.0/${r}.atr" -o "$(basename $r).atr"
done
ls -l f004a.* f004b.*
import wfdb
import numpy as np
def load_pair(sub, sid):
out = {}
for stage in ('a', 'b'):
name = f'{sid}{stage}'
h = wfdb.rdheader(name, pn_dir=f'crisdb/{sub}')
ann = wfdb.rdann(name, 'atr', pn_dir=f'crisdb/{sub}')
t = np.asarray(ann.sample, dtype=float) / h.fs
rr = np.diff(t)
lo = float([c for c in h.comments if 'RR-low-limit' in c][0].split(':')[1].split(',')[0])
hi = float([c for c in h.comments if 'RR-high-limit' in c][0].split(':')[1])
out[stage] = rr[(rr >= lo) & (rr <= hi)]
return out
p = load_pair('f', 'f004')
for k, v in p.items():
print(k, v.size, round(v.mean(), 4), round(v.std(), 4))
这段代码做了三件在别处容易漏的事:按头文件的时间基准换算、按头文件给出的区间截断、把两条记录成对取回。它没有做的事同样重要——没有剔除 Q 类搏动,因此间期序列里包含跨越 Q 的长值,截断会把它们一起切掉。
9.3 引用方式
| 引用对象 | 内容 |
|---|---|
| 数据集 | Stein, P. (2004). CAST RR Interval Sub-Study Database (version 1.0.0). PhysioNet. |
| DOI | 10.13026/C25P42 |
| RRID | SCR_007345 |
| 原始论文 | Stein PK, et al. Clin Cardiol 23(3):187-94, 2000 |
| 平台 | PhysioNet 平台综述论文,按官方页面引用按钮生成 |
| 附加数据 | 需向 NHLBI 申请,不在公开范围 |
写方法学部分时建议同时注明:使用的版本、是否按头文件字段筛掉了无定时信号的记录、Q 类搏动的处理规则、以及划分是否按受试者分组。这四项决定了别人能否复现你的数字。
§10 AI 使用声明
| 项目 | 声明 |
|---|---|
| 文本生成 | 本文由 AI 辅助撰写,编辑把关结构与事实 |
| 数字来源 | 规模、结构、边界三类数字来自 PhysioNet 官方页面与官方文件 |
| 文件核验 | RECORDS、f004a.hea、f004b.hea、e001a.hea、m010b.hea 经直接访问确认 |
| 口径冲突 | 页面 734 与论文摘要 769 的差额,正文按"两个口径"处理,未作判断 |
| 论文信息 | 仅参考 Europe PMC 返回的摘要,未读全文 |
| 未核验内容 | 各药物组的具体记录数、按设备字段分层的比例、各标签的出现频次 |
| 图像 | 无配图;封面为生成式提示词,不含真实心电波形或患者信息 |
| 免责 | 本文不构成临床或用药建议;使用须遵守 ODC-BY 1.0 署名要求 |
常见误读(避坑清单)
| 说法 | 实际 | 证据 |
|---|---|---|
| 「crisdb 是 CRISPR 相关的库」 | 是 CAST RR Interval Sub-Study 的目录名 | 官方标题为 CAST RR Interval Sub-Study Database |
| 「下载坏了,读不出信号」 | 头文件声明零通道、零采样点 | f004a.hea 第一行第二个字段为 0 |
| 「它有一万五千条记录」 | 一千五百余条,受试者八百余人 | RECORDS 行数与官方摘要 |
| 「它是 CAST 全队列」 | 主试验三千五百余人,库内仅 809 人 | 官方页面 Background 段 |
| 「它能算 LF/HF」 | 约六成记录无校准定时信号 | 官方 Usage Notes 第一条 |
| 「Q 是被判为异常的心搏」 | Q 表示时间或类型不可靠,异常搏动用 V/A 表示 | 官方对 Q 的三条说明 |
| 「室早负荷可以直接算绝对值」 | 官方承认 V/A 发生率可能被低估 | 官方 Usage Notes 第三条 |
| 「同一个人两条记录可以当两个样本」 | 同一受试者的 a 与 b 高度相关 | 记录名共前缀,头文件年龄性别一致 |
| 「日期是真的,可以做具体日期分析」 | 日期经随机偏移,仅间隔真实 | 官方 Methods 段 |
| 「年龄是确切值」 | 5 岁一档的区间 | 头文件 <age-range> 字段 |
| 「它是健康人基线库」 | 全部为心梗后、频发早搏者 | 官方入组条件 |
FAQ
Q1:crisdb 是不是 CRISPR 基因编辑数据库?
不是。它是 CAST RR Interval Sub-Study Database 的目录名,CAST 指心律失常抑制试验。库内另有一个 CRISPR 图谱数据集,两者毫无关系。用搜索引警找 crisdb 时最容易撞上 CRISPR 的结果,这是本库最常见的误认来源。
Q2:为什么下载下来只有注释,没有波形?
官方明确写了原始心电信号不可用。这批数据来自 1980 年代末的 Holter 磁带,子研究只保留了逐搏注释与头文件。后果是:无法验证记录的间期、无法修正搏动标签、也无法研究心搏间期以外的任何心电特征。
Q3:能不能用它算频域心率变异性?
要按记录筛。约六成磁带录制时没有校准定时信号,这类记录存在走带速度波动造成的频域伪影。每份头文件都标了是否含定时信号,做频域前必须先按这个字段筛选。原论文本身也只报了时域指标,理由是许多磁带缺少频域分析所需的校准定时信号。
Q4:同一个人有两条记录,能当两个独立样本吗?
不能。a 与 b 是同一位受试者用药前后的两次记录,年龄、性别、体质、生活节律全部共享。划分训练与测试时必须按受试者编号分组,否则同一个人会同时出现在两侧,指标会虚高。
Q5:它和 CAST 原始试验数据是一回事吗?
不是。主试验入组三千五百余人,本库只覆盖 809 人,且是满足用药有效、持续用药等条件的子集。更完整的 CAST 与 CAST-II 数据需要向 NHLBI 申请,不在公开范围内。
Q6:为什么有时看到 734 人,有时看到 769 人?
734 是 PhysioNet 页面按记录结构给出的人数,指同时具备基线与用药中两条记录的人;769 是 2000 年论文摘要里的分析样本量。两者纳入标准不同,差额的构成官方未说明。写论文时选一个口径并讲清楚,不要混用。
Q7:记录名里的 e、f、m 和 a、b 是什么?
首字母是药物:e 对应恩卡尼,f 对应氟卡尼,m 对应莫雷西嗪。末位是阶段:a 为用药前基线,b 为用药中。中间三位是受试者编号。所以 f004a 与 f004b 属于同一位服用氟卡尼的受试者。
Q8:为什么有的记录时间基准是 125.44 而不是 128?
因为磁带记录速度与扫描速度不一致。官方在头文件里说明了:按 1.47 mm/s 记录、1.50 mm/s 扫描的比例重标定,采样率从 128 调整为 125.44。遇到这种记录,时刻要除以 125.44,否则时间轴会偏大约百分之二。
Q9:Q 类搏动能不能直接丢掉?
可以丢,但要理解丢的是什么。Q 标记的是"这个搏动的时刻或类型不可靠",包括手工插入的、起点测量错误的、以及紧随超范围间期的搏动。丢掉 Q 之后,跨越被丢搏动的间期会变成超长值,仍需要按头文件区间截断。
Q10:序列里那些特别长的间期是什么?
官方说主要是 Holter 分析中的搏动检测错误,比如漏掉一个搏动就会产生一个约两倍长的间期。少数也可能是真正的窦性停搏,但因为原始心电图不可用,无法区分。处理时按头文件给出的上下限截断,不要用统计规则。
Q11:它能不能用来研究药物疗效?
只能做"用药前后有没有变化"的描述,不能做因果结论。库内没有安慰剂臂,所有人都在某个时点用过药;而且纳入条件是"药物确实有效",无效者已被筛掉。任何"某药改善 HRV"的表述都超出了数据能支撑的范围。
Q12:许可允许商用吗?
ODC-BY 1.0 允许,包括商业用途,条件是署名。引用时写清数据集名称、版本、DOI 与来源。具体条款以许可全文为准。
术语表
| 术语 | 解释 |
|---|---|
| CAST | 心律失常抑制试验,NHLBI 资助的心梗后抗心律失常药试验 |
| CAST-II | CAST 的后续试验,只保留莫雷西嗪与安慰剂两组 |
| 子研究 | 从主试验中取子集做二次分析的研究,本库即其产物 |
| RR 间期 | 相邻两次心室除极之间的时间间隔 |
| NN 间期 | 相邻两次正常心搏之间的间隔,已排除异位与不可靠搏动 |
| 心率变异性 | 逐搏间期随时间的波动程度,反映自主神经调节 |
| 时域指标 | 直接从间期序列算的统计量,如 SDNN、SDANN |
| 频域指标 | 对间期序列做频谱分析得到的功率,如 LF、HF |
| 室性早搏 | 心室提前除极,形态宽大,简称室早 |
| 室上性早搏 | 起源于心室以上的提前搏动,简称室上早 |
| 扑动补偿 | 对记录设备走带或扫描速度偏差所做的校正 |
| 校准定时信号 | 录制时同步写入的时间基准信号,频域分析的前提 |
| 卷盘式磁带 | reel-to-reel,早期 Holter 常用载体,速度稳定性较差 |
| 走带抖动 | wow and flutter,磁带速度波动造成的频率失真 |
| 注释文件 | .atr,存放逐搏时刻与类型符号的二进制文件 |
| 头文件 | .hea,纯文本,声明时间基准与记录元数据 |
| WFDB | PhysioNet 使用的生理信号数据格式族 |
| 时间基准 | 头文件声明的每秒时间单位数,本库多为 128 |
| 分析集 | 论文实际纳入统计的样本,本库论文口径为 769 人 |
| 自身对照 | 同一个体在干预前后的比较,本库的配对结构即此 |
| 疗效筛选 | 只纳入对治疗有反应者,会引入选择偏倚 |
| 左室射血分数 | 心脏每次收缩射出的血比例,CAST 的心功能门槛 |
| 去标识 | 移除或扰动可识别个体的信息,本库扰动的是日期 |
| ODC-BY | 开放数据共享署名许可,允许商用需署名 |
| PhysioNet | 由 MIT 等机构维护的生物医学信号数据平台 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 受试者数 | 809 | 官方页面 Background 段 | 官方页面 |
| 记录数 | 1543 | 官方页面;RECORDS 行数 |
官方页面 + 官方文件 |
| 配对人数 | 734 | 官方页面 Background 段 | 官方页面 |
| 单记录人数 | 75 | 官方页面 Background 段 | 官方页面 |
| 论文分析样本 | 769 | Europe PMC 摘要 | 论文摘要 |
| 配对组内死亡数 | 69 | 官方页面 Background 段 | 官方页面 |
| 主试验入组数 | 3,549 | 官方页面 Abstract 段 | 官方页面 |
| 每记录时长 | 约 24 小时 | 官方页面首段 | 官方页面 |
| 累计 RR 间期 | 约 1.5 亿 | 官方页面首段与 Usage Notes | 官方页面 |
| 时间基准 | 128 Hz | f004a.hea 等 |
官方文件 |
| 重标定基准 | 125.44 Hz | m010b.hea |
官方文件 |
| 药物组数 | 3 | 官方页面 Data Description | 官方页面 |
| 无定时信号比例 | 约六成 | 官方页面 Usage Notes | 官方页面 |
| 未压缩体积 | 615.4 MB | 官方页面 Files 区 | 官方页面 |
| 压缩包体积 | 616.6 MB | 官方页面 Files 区 | 官方页面 |
| 许可 | ODC-BY 1.0 | 官方页面 License 区 | 官方页面 |
| 首版日期 | 2004-07-02 | 官方页面 | 官方页面 |
| DOI | 10.13026/C25P42 | 官方页面 Discovery 区 | 官方页面 |
附录 B:数字的来源分层
第一层:官方页面与官方文件。 受试者数、记录数、配对数、单记录数、死亡数、主试验规模、时长、累计间期、药物组、无定时信号比例、体积、许可、日期、DOI,以及时间基准与重标定值,均来自项目主页与 RECORDS、若干头文件的直接访问。
第二层:论文摘要。 769 这个分析样本量、以及"只报时域指标因为许多磁带缺校准定时信号"这一方法学说明,来自 Europe PMC 返回的摘要。摘要只能支撑"论文这样写",不能支撑"全库如此"。
第三层:未核实。 三个药物组各自有多少条记录、按设备字段分层后的比例、各标签的出现频次、异常长间期的数量分布。这些需要下载全库逐条统计,超出本篇范围,正文中凡涉及处只做定性表述。
附录 C:完整参考文献
| 编号 | 文献 | 链接 | 用途 |
|---|---|---|---|
| 1 | CAST RR Interval Sub-Study Database v1.0.0 | https://physionet.org/content/crisdb/1.0.0/ | 全部规模、结构、边界数据的来源 |
| 2 | 该库的 PhysioNet 文件目录 | https://physionet.org/files/crisdb/1.0.0/ | RECORDS、头文件、ANNOTATORS |
| 3 | Stein PK, et al. Clin Cardiol 2000;23(3):187-94 | https://pubmed.ncbi.nlm.nih.gov/10761807/ | 子研究设计与分析样本 |
| 4 | Echt DS, et al. N Engl J Med 1991;324:781-8 | https://doi.org/10.1056/NEJM199103213241201 | CAST 主试验结论 |
| 5 | CAST-II Investigators. N Engl J Med 1992;327:227-33 | https://doi.org/10.1056/NEJM199207233270403 | 莫雷西嗪臂结论 |
| 6 | Epstein AE, et al. J Am Coll Cardiol 1991;18:14-19 | https://doi.org/10.1016/s0735-1097(10)80210-4 | CAST 全队列事件 |
| 7 | PhysioNet 平台综述(2026,Nature Health) | https://doi.org/10.1038/s44360-026-00096-z | 托管模式与引用规范 |
| 8 | PhysioBank 注释定义 | https://physionet.org/physiobank/annotations.shtml | 心搏类型码含义 |
| 9 | RR 间期与 HRV 操作指南 | https://physionet.org/content/annotations/ | ann2rr 与序列导出 |
附录 D:任务代码
任务一:按受试者分组的配对表构建
from collections import defaultdict
import json
pairs = defaultdict(dict)
for line in open('RECORDS'):
path = line.strip()
if not path:
continue
sub, name = path.split('/')
pairs[name[:4]][name[-1]] = f'{sub}/{name}'
rows = []
for sid, d in sorted(pairs.items()):
rows.append({'subject': sid, 'drug': sid[0],
'baseline': d.get('a', ''), 'therapy': d.get('b', '')})
print(len(rows))
print(sum(1 for r in rows if r['baseline'] and r['therapy']))
json.dump(rows, open('subjects.json', 'w'), ensure_ascii=False, indent=1)
任务二:头文件字段的结构化解析
import re
import wfdb
def parse_hea(rec, subdir):
h = wfdb.rdheader(rec, pn_dir=f'crisdb/{subdir}')
txt = ' '.join(h.comments)
def grab(key, stop=r'[,;]'):
m = re.search(key + r'\s*[:=]\s*([^,;]+)', txt)
return m.group(1).strip() if m else ''
note = grab('Note', stop=r'$')
return {
'fs': h.fs,
'age_range': grab(r'<age-range>'),
'sex': grab(r'<sex>'),
'medication': grab(r'<medication>'),
'rr_lo': float(grab(r'<RR-low-limit\(sec\)>')),
'rr_hi': float(grab(r'<RR-high-limit\(sec\)>')),
'timing_signal': ('timing signal' in note) and ('no timing' not in note),
'flutter_comp': ('flutter-compensated' in note) and ('not flutter-compensated' not in note),
'reel_to_reel': 'reel-to-reel' in note,
}
print(parse_hea('f004a', 'f'))
print(parse_hea('f004b', 'f'))
第二个函数的关键在最后三行:否定式表述必须显式排除,否则 not flutter-compensated 会被判成已补偿。这个坑在 f004a 与 f004b 这一对上正好能验证——前者应为已补偿,后者为未补偿。
任务三:设备条件分层后的描述统计
import numpy as np
def summarize(rec, subdir):
h = wfdb.rdheader(rec, pn_dir=f'crisdb/{subdir}')
ann = wfdb.rdann(rec, 'atr', pn_dir=f'crisdb/{subdir}')
t = np.asarray(ann.sample, dtype=float) / h.fs
rr = np.diff(t)
return {'n': rr.size, 'median_s': float(np.median(rr)),
'fs': h.fs, 'span_h': float(t[-1] - t[0]) / 3600.0}
for r, s in (('f004a', 'f'), ('f004b', 'f'), ('m010b', 'm')):
print(r, summarize(r, s))
这段代码返回的是记录级摘要,不是人群统计。它的用途是快速确认时间基准、时长量级与是否需要对某条记录单独处理,不用于推断分布。
附录 E:如果只记五件事
| 序号 | 记住什么 | 为什么 |
|---|---|---|
| 1 | 809 人、1543 条、每条约 24 小时、只有注释没有波形 | 这四个事实定义了一切用法与限制 |
| 2 | 734 人有用药前后配对,这是它最稀缺的部分 | 随机对照无法重做,配对结构不可再生 |
| 3 | 约六成记录无校准定时信号 | 频域分析前必须按头文件字段筛选 |
| 4 | 时间是 128 的分数秒,个别记录是 125.44 | 写死 128 会让时间轴偏约百分之二 |
| 5 | 人群是"心梗后 + 药物治疗有效"者 | 结论不能外推到普通人群,也不能当归因于药物 |
编辑说明
本文的核验时间为 2026 年 10 月 28 日。核对方式为直接访问 PhysioNet 项目页与文件目录,逐一确认 RECORDS、f004a.hea、f004b.hea、e001a.hea、m010b.hea 的可访问性与内容;论文侧只检索了 Europe PMC 的摘要,未读全文。
有一处口径冲突需要在此留痕:PhysioNet 页面按记录结构给出"734 人配对 + 75 人单条 = 809 人",而 2000 年论文摘要写的是子研究 769 人。两者相差 35 人,官方未说明差额构成。本文的处理方式是并列陈述、不作判断,并在 §3.3、§7.4 与 FAQ 第 6 问三处提示使用者注意,避免复现时误用。
本篇对 crisdb 这个名称做了一次专门辨析(§3.5、FAQ 第 1 问)。目录名与 CRISPR 的拼写相近,是这个词条最容易被误认的地方,检索与引用时需加以区分。未覆盖的项包括三个药物组各自的确切记录数、按设备字段分层的比例、各标签的出现频次与异常长间期的分布,这些需要下载全库统计。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- wctecgdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- ahadb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- chfdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- cudb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- ltdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- ltstdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- iafdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- nsr2db — 共享标签:生理信号 / 心电信号 / 心血管疾病
- nsrdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- stdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

