信息速览
三十秒的门诊心电图里,十二个导联同时在看同一颗心脏;二十四小时的 Holter 里,只有两三个导联在整夜盯着它。两件事在临床上各有各的位置,却几乎从不合流——十二导联的诊断价值来自导联间的关系(心梗的定位、束支阻滞的分型都靠它),长时程的价值来自时间上的覆盖(阵发性事件只在某个夜里出现)。而公开数据集的取舍也一直是二选一:十二导联的库通常每段只给十秒,长时程的库通常只给一到两个导联。
INCART 是这条分界线上的一个例外。圣彼得堡心脏病技术研究所把为冠心病检查所做的 Holter 记录重新切成半小时一段,保留了全部十二个标准导联,配上逐搏注释,在 2008 年交给了 PhysioNet。它因此能回答一个别处很难回答的问题:同一次心律失常发作,在十二个导联上的表现差异有多大——有些房颤在 V1 清晰得像教科书,在肢体导联上却几乎看不出来;用一个导联训练出来的模型,会在这类记录上系统性地漏诊。
它的代价同样明确:只有 75 段、32 名患者、单一中心、俄罗斯人群,标注以心搏为主而非节律为主。它不是规模上的大库,是一件稀缺的"对照工具"。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 全名 | St Petersburg INCART 12-lead Arrhythmia Database |
| 发布方 | PhysioNet(原始数据由俄罗斯圣彼得堡 Institute of Cardiological Technics 贡献) |
| 首次发布 | 2008 年 5 月 1 日,版本 1.0.0 |
| 最近改动 | 2015 年 9 月 18 日,重算头文件校验和,信号与标注未改 |
| 记录数 | 75 段 |
| 患者数 | 32 名(17 男、15 女,18–80 岁,平均 58 岁) |
| 每段时长 | 30 分钟 |
| 导联数 | 12(I、II、III、aVR、aVL、aVF、V1–V6) |
| 采样率与分辨率 | 257 Hz,16 位带符号整数存储,增益 250–1100 ADC 单位/毫伏 |
| 每段采样点 | 462600 |
| 原始来源 | 32 份冠心病检查 Holter |
| 标注规模 | 合计超过 175,000 条心搏标注 |
| 标注生成方式 | 自动初标 + 人工修正,遵循 PhysioBank 标准心搏注释定义 |
| 文件格式 | WFDB:.hea 头文件 / .dat 信号 / .atr 注释 |
| 许可 | ODC-BY 1.0,无需注册 |
| 典型用途 | 心搏分类的跨库测试、房颤检测、单导联与多导联对比、噪声鲁棒性评估 |
§1 它要解决的具体麻烦
1.1 每一段心电图都是"半个证据"
心电图在诊断链条上有两种价值,对应两种完全不同的采集姿态。第一种是"形态价值":十二个导联从不同角度切开心电向量,ST 段抬高在哪几个导联上出现、QRS 波群的宽度落在哪个区间,都能指向具体的心肌壁与传导通路。这种价值对导联数极度敏感,少一个 V1,右束支阻滞的分型就无从谈起。第二种是"节律价值":心房是规整地放电还是一团颤动、室性早搏是一天几个还是几分钟一个、心动过缓发生在凌晨几点。这种价值对覆盖时长极度敏感,对导联数要求不高——一个足够干净的 II 导联就能判断大部分节律问题。
临床为了拿到这两种价值,付出了两笔不同的代价。门诊十二导联只需躺十秒钟,便宜、快速、不打扰患者,但只能看到十秒钟的节律;Holter 要背一整天,能抓住阵发性事件,但要背十二个电极会让患者无法正常工作与睡觉,于是退到两到三个导联。这就是为什么临床上不存在"十二导联二十四小时"的常规检查——不是没人想过,是患者背不动。
公开数据集继承了同样的分界。十二导联的库,比如各家医院贡献的诊断级数据库,普遍给的是十秒一类的短片段;长时程的库,比如 MIT-BIH 房颤库、长期房颤库,普遍是一到两导联配二十小时以上的覆盖。两者各自成为成熟的任务基准,但它们共同缺了一个维度:跨导联的一致性。
1.2 三条常见的错误期待
第一条,期待它是"高质量的十二导联诊断数据"。它的原始记录来自 Holter,电极是贴在体表、在患者走动时录的,噪声水平明显高于静息十二导联机打的十秒图。把它当诊断级的形态学标准来用,会立刻遇到基线漂移与肌电干扰(§7.3)。
第二条,期待它有"房颤逐段标签"。它的注释文件是心搏级的,AFIB 这类节律标注是否存在、覆盖多少,取决于标注者对每一段的处理,官方页面并没有承诺逐段节律标签。想用做房颤二分类,标签得自己从心搏序列或诊断描述里推(§2.2)。
第三条,期待它能代表"健康人的十二导联"。全部患者都是为冠心病检查而来,官方明确说筛选时优先选了心电图与缺血、冠心病、传导异常、心律失常相符的人。它是一个"异常偏多"的人群,正常心搏的多样性反而不足。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 心搏级别的形态分类(N/S/V/F/Q) | 十七万余条心搏标注,十二导联同步 | 够,且可以同时评估单导联与多导联的差距 |
| 房颤检测的训练与测试 | 心搏序列 + 部分记录诊断中含房颤或阵发性房颤 | 可做,但标签需二次加工 |
| 长时程节律负荷统计 | 每段三十分钟,可以算单位时间负荷 | 够做片段级,不足以做日级负荷 |
| 心梗的导联定位 | 十二导联齐全,部分记录描述含 ST 改变 | 不够,无导联级 ST 定量标注 |
| 束支阻滞分型 | 十二导联齐全,部分记录诊断含束支阻滞 | 可做探索,样本太少不足以训练 |
| 健康人群基线 | — | 不够,全部为冠心病人群 |
| 多中心泛化验证 | 单一中心、单一国家 | 不够,只能做"跨库"而不是"跨中心" |
| 可穿戴单导联算法评测 | 可从十二导联中抽出任一导联 | 够,这是它最有价值的用法之一 |
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 你已用 MIT-BIH 心律失常库训好一个心搏分类器,想证明它不只是记住了那 47 个人 | 提供同一套注释码、另一套设备与人群的外部测试集,标注可直接映射 | 先跑零样本外测拿到掉分幅度,再决定是否做微调;按患者编号划测试集 |
| 你在做可穿戴单导联房颤检测,担心模型只在"好导联"上有效 | 同一段时间里有十二个导联,可逐导联训练、逐导联评测,量化导联位置造成的性能差 | 固定患者划分,训练集与测试集使用同一导联,再单独跑"训练用 II、测试用 V1"的错配实验 |
| 你要做噪声鲁棒性研究,缺一个干净的噪声源 | 长度三十分钟、十二导联同步,便于叠加同源噪声并保持导联间关系 | 用标准噪声库按目标信噪比叠加,记录每个导联的原始信噪比作为协变量 |
| 你在教心电图判读,需要一个"同一发作、多种表现"的例子 | 可截取同一时间窗内十二导联波形做对照教学 | 用 §2.3 的读取流程导出图像,注意标注位置可能有偏移 |
| 你想做一个十二导联节律分类模型,但手里只有短片段库 | 提供长时程上下文,可以把十秒片段放进三十分钟背景里比较 | 先确认你要的是片段级还是记录级标签,后者需自建 |
| 你在核对某个公开结果的复现性 | 规模小、下载快,适合做快速复现基线 | 全量只有几十兆,可一次下完(§5.2) |
1.5 一句话判断
它不适合当"更大的训练集",而适合当"更锋利的尺子":在同一段时间轴上量出十二个导联之间的差异,而这个差异正是单导联模型最容易忽略的东西。
1.6 不适合谁:四条边界
不适合拿来做规模训练。 75 段、32 名患者,深度学习模型一两轮就能记住全部。想用数据量换性能的项目,用它会立刻过拟合。
不适合拿来做正常人群建模。 全部患者为冠心病检查人群,平均年龄 58 岁,异常心搏比例偏高。用它训练出的"正常心搏"表征,会偏向这一人群的形态。
不适合拿来做药物或干预研究。 记录里没有用药信息、没有随访、没有结局变量。唯一的临床上下文是 .hea 里一行诊断与一行心电图特征摘要。
不适合做严格的节律界标研究。 心拍注释的位置由算法在十二导联上综合确定,官方明确说明位置未经人工逐条校正。用它算 RR 间期、做心率变异性,误差会直接进入结果。
§2 数据构成与规格
2.1 一段记录由三个文件组成
数据库采用 WFDB(Waveform Database)格式,这是 PhysioNet 自 1980 年代沿用至今的物理信号存储规范。每一段记录对应同名的三个文件:.hea 是纯文本头文件,声明采样率、信号条数、每条信号的增益与基线并附患者信息;.dat 是二进制信号本体,按采样点交错存放十二个导联的整数值;.atr 是二进制注释文件,存放事件位置与类型。
三者缺一不可。只拿 .dat 无法还原毫伏值,因为没有增益;只拿 .atr 无法知道这些时刻对应什么波形。这也是为什么把数据转成通用格式(比如 CSV 或 NumPy)是有损操作——头文件里的增益、基线、导联名会被压进列头,注释里的类型码会被压成字符串,后续再想回到原始语义就得靠映射表(§5.4)。
数据库根目录下还有几个附属文件。RECORDS 列出全部记录名;ANNOTATORS 说明注释文件的角色(只有一行:atr reference beat annotations);record-descriptions.txt 与 files-patients-diagnoses.txt 把头文件里散落的诊断信息汇总成两个便于阅读的清单,前者按记录列出心电图特征,后者按患者列出所属记录与诊断。
2.2 字段/记录的完整字典
下表把头文件、注释文件、附属清单里的信息项逐条列出。需要强调:本库的"字段"不是表格列,而是 WFDB 头文件的关键字行与注释类型码。
| 信息项 | 所在位置 | 取值形态 | 含义 | 使用注意 |
|---|---|---|---|---|
| 记录名 | .hea 第 1 行首字段 |
I01–I75 |
记录标识 | 字面量就是文件名前缀 |
| 信号条数 | .hea 第 1 行第 2 字段 |
12 |
导联数 | 全部记录均为 12 |
| 采样率 | .hea 第 1 行第 3 字段 |
257 |
每秒采样点数 | 非 250 也非 360,插值前要重采样 |
| 采样点数 | .hea 第 1 行第 4 字段 |
462600 |
总长度 | 除以采样率正好 1800 秒 |
| 文件名 | .hea 信号行第 1 字段 |
I01.dat |
信号存放在哪个文件 | 多导联共用同一个 .dat |
| 存储格式 | .hea 信号行第 2 字段 |
16 |
16 位带符号整数 | 不是浮点 |
| 增益 | .hea 信号行第 3 字段 |
如 306 |
ADC 单位/毫伏 | 逐记录不同,250–1100 |
| 位分辨率 | .hea 信号行第 4 字段 |
16 |
ADC 位数 | 实际有效位受增益影响 |
| ADC 零值 | .hea 信号行第 5 字段 |
0 |
零电平对应的整数值 | 换算时先减零值 |
| 初始值 | .hea 信号行第 6 字段 |
如 1161 |
首采样点整数值 | 2015 年修订补齐 |
| 校验和 | .hea 信号行第 7 字段 |
如 -11409 |
采样点累加和 | 用于校验 .dat 完整性 |
| 块大小 | .hea 信号行第 8 字段 |
0 |
每帧字节数 | 本库用自动计算 |
| 导联名 | .hea 信号行第 9 字段 |
I…V6 |
解剖位置 | 顺序固定,12 行一一对应 |
| 年龄 | .hea 注释行 |
65 |
患者年龄 | 以 #<age>: 开头 |
| 性别 | .hea 注释行 |
F / M |
患者性别 | 以 #<sex>: 开头 |
| 诊断 | .hea 注释行 |
自由文本 | 临床诊断 | 以 #<diagnoses> 开头 |
| 患者编号 | .hea 注释行 |
1–32 |
来源 Holter 序号 | 以 # patient 开头,划分数据集的关键 |
| 心电图特征 | .hea 注释行 |
自由文本 | 如 PVCs, noise |
也是 record-descriptions.txt 的内容 |
| 心搏位置 | .atr |
采样点序号 | 事件发生时刻 | 已由算法在十二导联综合定位 |
| 心搏类型 | .atr |
类型码 | 如 N、V、L |
见下表 |
| 节律变换 | .atr |
+ |
节律切换处 | 覆盖率因记录而异 |
心搏类型码沿用 PhysioBank 的标准定义,本库声明遵循该标准。最常出现的几类如下:
| 类型码 | 含义 | 映射到 AAMI 五分类 |
|---|---|---|
N |
正常心搏 | N |
L |
左束支阻滞心搏 | N |
R |
右束支阻滞心搏 | N |
B |
未分型束支阻滞心搏 | N |
A |
房性早搏 | S |
a |
伴差异性传导的房性早搏 | S |
J |
交界性早搏 | S |
S |
室上性早搏或异位搏动 | S |
V |
室性早搏 | V |
r |
R-on-T 室性早搏 | V |
F |
室性融合波 | F |
e |
房性逸搏 | Q |
j |
交界性逸搏 | Q |
n |
室上性逸搏 | Q |
E |
室性逸搏 | Q |
f |
起搏与正常心搏融合 | F |
Q |
无法分类的心搏 | Q |
? |
学习阶段未分类 | Q |
官方说明全部患者都没有起搏器、多数有室性早搏,所以实际出现的类型集中在上面几类;/(起搏心搏)理论上不应出现,但代码里做了保留是为了兼容其他库。
2.3 一条记录的完整解剖
以 I01 为例。头文件第一行 I01 12 257 462600 说明:记录名 I01,12 个导联,257 Hz,共 462600 个采样点。462600 ÷ 257 = 1800,即 1800 秒整,也就是三十分钟——每一段都被精确切到整分钟,这一点让按分钟切窗变得非常省事。
接下来是 12 行信号声明。以 I01 的 II 导联为例:
I01.dat 16 306 16 0 457 21378 0 II
从右往左读:导联名 II;格式 16(16 位整数);.dat 内的间距是 0(表示由 wfdb 自动按 12 条 16 位信号计算帧长);校验和 21378;初始值 457;ADC 零值 0;位分辨率 16;增益 306(即 306 个整数值对应 1 毫伏,约 3.27 微伏/单位);文件名 I01.dat。
增益这一项在本库里跨度很大。I01 的十二个导联增益都在 306 附近,而 I75 的部分导联增益是 612。同一个数据库内不同记录增益不同,意味着"整数值直接喂进模型"的写法会把绝对幅度信息搅乱——必须按 .hea 换算成毫伏,或至少先按增益归一。这是本库一个容易踩的坑,因为它不像单一增益的库那样在文档里反复提醒。
文件末尾三行注释给出了患者上下文:
#<age>: 65 <sex>: F <diagnoses> Coronary artery disease, arterial hypertension
\# patient 1
\# PVCs, noise
把后面几行连起来读:I01 来自 1 号患者,65 岁女性,诊断为冠心病合并动脉高血压,这段三十分钟里能看到室性早搏,并且有噪声段。record-descriptions.txt 里对应的一行就是 PVCs, noise。
读取信号与注释的标准写法:
import wfdb
import numpy as np
#-- 远程直读,无需先下载;pn_dir 指向 PhysioNet 上的库名
rec = wfdb.rdrecord('I01', pn_dir='incartdb')
ann = wfdb.rdann('I01', 'atr', pn_dir='incartdb')
print(rec.fs, rec.sig_len, rec.sig_name[:3]) #-- 257 462600 ['I', 'II', 'III']
print(rec.p_signal.shape) #-- (462600, 12) 已换算成毫伏
print(ann.sample[:5], ann.symbol[:5])
#-- 统计心搏类型
from collections import Counter
print(Counter(ann.symbol).most_common(10))
p_signal 是已按增益与零值换算过的浮点毫伏值;如果需要原始整数,用 d_signal。ann.sample 是采样点序号,除以 257 即得秒数。
2.4 记录与患者的映射关系
患者的分布并不均匀:有的患者贡献了一段,有的贡献了五六段。官方说明同一患者编号下的记录都来自同一次 Holter,因此患者内部的相关性极强。
| 患者编号 | 记录数(官方清单所见) | 说明 |
|---|---|---|
| 单人一段 | 多数患者 | 单次 Holter 只切出一段 |
| 单人两段及以上 | 少数患者 | 例如 2 号患者对应 I03、I04、I05 三段 |
| 合计 | 75 段 / 32 名患者 | 平均每人 2.3 段左右 |
上表前两行只做定性描述,具体每人的段数应以 files-patients-diagnoses.txt 为准。这个平均值的含义很直接:如果按记录做随机划分,测试集里大约每三个人就有两人在训练集里有"同一次 Holter 的兄弟段"。这是本库最容易被低估的泄漏源(§7.3)。
泄漏的机制值得拆开讲。同一次 Holter 的多段记录,共享的不只是同一个人,而是同一批电极、同一个放大器、同一段体位变化、同一套背景噪声。十二导联的增益与基线在整次记录里恒定,所以某段里出现的工频干扰形态、某个导联接触不良造成的固定偏移,会在兄弟段里原样重现。模型只要学会"这个偏移模式下该输出什么",就能在测试集里白拿分,而这个能力到真实的另一家医院就完全失效。
更隐蔽的是节律层面的相关。同一次记录里,如果患者在上午九点处于房颤、十点转复,那么被切成两段之后,一段是房颤、一段是窦律,但两段的心房形态特征(f 波振幅、P 波电轴)来自同一颗心脏。按记录随机切分时,测试段里"这个人特有的"房颤波形正在训练段里被见过。这解释了为什么一些文献里按记录切分得到的成绩那么好,换了按患者切分就掉一截——差异不来自模型强弱,来自切分口径。
正确做法很朴素:从头文件读出 # patient,把患者编号作为分组键,用 GroupKFold 或直接按编号区间切。判断标准只有一条——同一个人绝不出现在两侧。
2.5 与同类资源的字段差异
| 对比项 | INCART | MIT-BIH 心律失常库 | MIT-BIH 房颤库 | 长期房颤库 |
|---|---|---|---|---|
| 导联数 | 12 | 2 | 2 | 2 |
| 单段时长 | 30 分钟 | 30 分钟 | 10 小时 | 24–25 小时 |
| 采样率 | 257 Hz | 360 Hz | 250 Hz | 128 Hz |
| 记录数 | 75 | 48 段 | 25 段 | 84 段 |
| 患者数 | 32 | 47 名 | 25 名 | 84 名 |
| 心搏级标注 | 有 | 有 | 有 | 有 |
| 节律级标注 | 部分(视记录) | 部分 | 有 | 有 |
| 人群 | 冠心病检查人群 | 心律失常门诊与住院人群 | 阵发性或持续性房颤 | 长期房颤 |
| 主要用途 | 跨库测试、导联对比 | 心搏分类基准 | 房颤检测与终止预测 | 长程房颤负荷 |
这张表要说清的只有一件事:INCART 在"导联数"这一列上唯一性地突出,在"时长"与"规模"两列上都不占优。它的定位不是替代任何一个库,而是补上别人补不了的那一列。
2.6 十二个导联各自的物理含义
用法上的差异,根子在这十二个导联各自测的是心电向量在不同方向的投影。把它们按方向排好,很多「为什么某个导联更清楚」的问题就有了答案:
| 导联 | 安放位置 | 观察的主要方向 | 常见失真来源 |
|---|---|---|---|
| I | 右臂—左臂 | 左右方向 | 双臂活动导致的基线漂移 |
| II | 右臂—左腿 | 上下偏左 | 呼气末段体位变化 |
| III | 左臂—左腿 | 上下偏左(与 II 互补) | 与 II 高度相关,异常时两者一起偏 |
| aVR | 右上 | 右上方 | 幅度小,量化噪声占比高 |
| aVL | 左肩 | 左上方 | 易受投影抵消,房性活动弱 |
| aVF | 左下 | 正下方 | 下壁缺血观察点 |
| V1 | 胸骨右缘第 4 肋间 | 前后偏右 | 呼吸造成的基线起伏最明显 |
| V2 | 胸骨左缘第 4 肋间 | 前后偏右 | 同上 |
| V3 | V2 与 V4 中点 | 前后 | 电极贴合度对幅度影响大 |
| V4 | 左锁骨中线第 5 肋间 | 前后偏左 | 心尖搏动造成的运动伪迹 |
| V5 | 左腋前线第 5 肋间 | 左外侧 | 运动伪迹 |
| V6 | 左腋中线第 5 肋间 | 左外侧 | 幅度衰减 |
Holter 的十二导联并不是门诊机的标准几何——门诊机是十个电极、靠电阻网络合成出十二个导联,Holter 则要兼顾患者活动,电极位置与连线方式会做取舍。这意味着本库的十二导联在绝对幅度上与门诊机不可直接比。用它做「十二导联诊断学」的研究时,这一点要写进方法节;用它做「同一记录的导联间相对差异」的研究时,这个差异不影响结论——还是 §4.3 的案例给出的那个道理:横向比较比绝对值可靠。
§3 它是谁的数据:一个研究所的 Holter 遗产
3.1 贡献者与机构
数据库由俄罗斯圣彼得堡的心脏病技术研究所(Institute of Cardiological Technics,简称 Incart)贡献。官方页面把初始开发归于 Viktor Tihonenko 与 Alexander Khaustov,附加核验由 Sergey Ivanov 与 Alexei Rivin 完成,问题与更正的联系人是 Evgeniy Yakushenko。机构名里的 “Technics” 值得留意——它是一个面向心脏诊断技术的研究所,而不是单纯的临床科室,这解释了为什么这批数据从诞生起就带着"可被算法使用"的自觉:切段对齐到整分钟、注释遵循国际通用码表、头文件里把患者上下文写得齐整。
3.2 时间线
| 时间 | 事件 | 意义 |
|---|---|---|
| 2008-05-01 | 数据库在 PhysioNet 上线,版本 1.0.0 | 首次公开 |
| 2015-09-18 | 头文件修订,补齐校验和与初始值 | 信号与标注未动,只改元数据 |
| 2017 | 作为来源之一被大型房颤分类挑战赛使用 | 用户面从心搏分类扩展到节律分类 |
| 近年 | 被大量用作跨库外部测试集 | 定位从"可训练库"转向"可验证库" |
第三、四行属于使用侧的观察,不是官方版本的变更记录,这里列出是为了说明它身份的变化(§8)。
3.3 采集场景:为冠心病检查而做的 Holter
官方原话是:原始记录取自接受冠心病检查的患者。筛选入册时,优先选心电图与缺血、冠心病、传导异常及心律失常相符的对象。这句话包含了两层筛选:第一层是临床指征——这些人本来就被怀疑有冠心病;第二层是数据挑选——从这批里再挑出心电图有"料"的。
由此可以推出它的人群画像:年龄 18–80 岁,平均 58 岁,男女比例接近均衡(17 男、15 女),无起搏器植入,多数有室性早搏。官方诊断分布表如下:
| 诊断 | 患者数 | 备注 |
|---|---|---|
| 急性心肌梗死 | 2 | |
| 短暂性缺血发作(心绞痛) | 5 | |
| 陈旧性心肌梗死 | 4 | |
| 冠心病合并高血压 | 7 | 其中 4 例心电图符合左心室肥厚 |
| 窦房结功能不全 | 1 | |
| 室上性异位搏动 | 18 | 最常见 |
| 心房颤动或室上性心动过速 | 3 | 其中 2 例为阵发性房颤 |
| WPW 综合征 | 2 | |
| 房室传导阻滞 | 1 | |
| 束支传导阻滞 | 3 |
这些诊断在必要时经酶学检测、冠状动脉造影、电生理检查与压力监测确认。把这张表加总会超过 32,因为一名患者可以有多个诊断——这正是它的价值所在:它不是"每人一个标签"的干净分类集,而是真实的多病共存。
3.4 数据来源的三个层次
理解这份数据要先分清三层:Holter 记录(原始,未公开)、三十分钟段(公开的基本单位)、心搏标注(公开的监督信号)。第一层不可得,说明为什么同一患者的段间相关性无法从公开数据里彻底消除;第二层决定了每段的边界都是人为切的,切点可能落在一次心律失常的中途;第三层决定了监督信号的时间粒度是心搏而不是秒。
§4 它最独特的东西:同一段时间里的十二个视角
4.1 十二导联与长时程的交集为什么稀缺
临床上做十二导联需要十根电极,做二十四小时需要患者带着记录仪生活。两者叠加,患者体验与信号质量的代价都很大,所以常规检查里不存在这种组合。公开数据集的稀缺也来自同一个现实约束:愿意公开十二导联长时程数据的机构,必须本来就有一批做了十二导联 Holter 的患者。
这正是 INCART 的来历。它不是为了做数据集而专门采集的,而是既有临床流程的副产品——研究所本来就在为冠心病患者做 Holter,把记录切段、标注、捐赠,成本远低于从零采集。
所以它的稀缺性不是"采集得精细",而是"恰好存在"。这也解释了它为什么一直只有 75 段:不是没人想要更多,而是愿意再捐一个 12 导联 Holter 队列的机构太少。
4.2 十二个导联看同一件事,结果差多少
十二导联的解剖含义可以用一句话概括:肢体导联(I、II、III、aVR、aVL、aVF)看额面,胸前导联(V1–V6)看横面。心房电活动的主向量大致朝左下后方,所以在 V1 上投影最强,信号最清楚;在 aVL 上往往接近垂直,幅度最小。
这个几何关系直接决定了它在算法评测里的用途:
| 导联 | 主要朝向 | 对心房活动的敏感度 | 对室性早搏形态的区分度 |
|---|---|---|---|
| II | 下壁 | 高(P 波明显) | 中 |
| V1 | 右前胸 | 最高(房颤 f 波最清楚) | 高(可辨左右束支图形) |
| aVR | 右上 | 极性相反 | 中 |
| aVL | 左肩 | 低(易被投影抵消) | 低 |
| V5 / V6 | 左腋 | 中 | 中 |
上表的"敏感度"是根据导联电轴得出的定性判断,本库本身并不提供这种逐导联的统计。它的价值在于给你一个可以做实验的场地:把同一批记录在不同的导联上各跑一遍,差异会自己显现出来。
4.3 案例:同一段房颤在 II 导联与 V1 导联上的差别
取 I50。record-descriptions.txt 里它的描述是 PVCs, tachycardia, atrial fibrillation, ST depression——室性早搏、心动过速、心房颤动、ST 段压低,四件事挤在三十分钟里。这是一段理想的观察样本:底部节律是房颤,中间还混着室早与 ST 改变。
用 §2.3 的代码读出这段信号后,取同一时间窗(比如第 600 秒到第 620 秒)画 II 与 V1:
import wfdb
import numpy as np
rec = wfdb.rdrecord('I50', pn_dir='incartdb')
fs = rec.fs
a, b = int(600 * fs), int(620 * fs)
lead2 = rec.p_signal[a:b, rec.sig_name.index('II')]
v1 = rec.p_signal[a:b, rec.sig_name.index('V1')]
#-- 用简单的差分能量比较两个导联的"可见度"
for name, x in (('II', lead2), ('V1', v1)):
print(name, '峰峰值 mV =', round(float(np.ptp(x)), 3),
' 一阶差分均方 =', round(float(np.mean(np.diff(x) ** 2)), 6))
把这段实验的三种典型结果记下来,就成了后续讨论的支点:
| 观察 | II 导联 | V1 导联 | 对模型的含义 |
|---|---|---|---|
| f 波可见度 | 常被 T 波与基线漂移淹没 | 细碎波动更清楚 | 单导联 II 的房颤检测容易漏掉低幅房颤 |
| QRS 形态 | 下壁轴,室早常呈主波向下 | 右胸轴,室早常呈主波向上 | 同一室早两个导联的形态几乎相反 |
| 噪声敏感性 | 易受肌电干扰 | 更易受呼吸基线漂移 | 噪声鲁棒性评测需按导联分别报告 |
这不是一个"发现",而是一个可以用它自己验证的观察。§4.3 的案例在全文出现三次,分别在 §3 解释数据组织方式、§5 讲读取流程、§7 讲误判来源——之所以反复回来,是因为它把"十二导联"这个卖点从抽象的好处变成了一个可以复现的小实验。
4.4 标注的粒度:心搏级清楚,节律级模糊
这是它的第二层特色,也是它最容易被误判的地方。心搏标注非常规整:每段三十分钟,段落内每一次 QRS 都被标出类型,合计超过十七万条。这个量级意味着全库平均每分钟约 80 个心搏,符合静息到轻度活动的范围。
但节律标注不一样。PhysioBank 的标准注释体系里有 + 表示节律变换,其后可以带节律类型;本库官方页面并没有说明节律标注的覆盖策略。因此,"这一段是不是房颤"这个判断,从 .atr 里读不出来,只能从"心搏序列是否绝对不规则"或"诊断描述里有没有写房颤"间接推。
这两种推法各有代价:前者需要算法,且会在频发早搏时误判;后者只有粗粒度,因为一条记录里可能只有局部是房颤(I71 的描述就是 paroxysmal atrial fibrillation,阵发性意味着大部分时间可能不是)。
4.5 边界条件:什么情况下它不再适用
把它的优点说透之后,必须把「什么时候不该抬出它」也列清楚。下面这张表不是免责声明,而是使用判断:
| 条件 | 是否适用 | 判断依据 |
|---|---|---|
| 你要证明模型能处理门诊级静息十二导联 | 不适用 | 它是 Holter 记录,行动状态与门诊静息不同 |
| 你要评估模型对运动伪迹的鲁棒性 | 适用,而且是少有的适用场景 | 十二导联同时受同一段运动影响,可分别看 |
| 你要做导联缺失下的补全实验 | 适用 | 十二导联齐全,可任意遮蔽再重建 |
| 你要做 12 导联的房颤逐段分类 | 谨慎 | 节律标签不全,需自建口径并公开验证 |
| 你要做长时程(小时级)节律负荷 | 不适用 | 单段只有三十分钟,无法跨小时累计 |
| 你要做多中心外部验证 | 只算半边 | 它是外中心,但只有一处,不能代表多中心 |
| 你要做儿童或青少年心电模型 | 不适用 | 年龄下限 18 岁 |
| 你要做起搏心律识别 | 不适用 | 官方说明全部患者无起搏器 |
这张表最有用的两行是第三行与第六行。第三行说的补全实验,是它被低估的用途:十二导联齐全意味着你可以人为遮蔽某几个导联,训练一个「从可见导联重建被遮蔽导联」的模型,而重建得好不好可以逐导联量化。这类实验在单导联库里根本做不了。第六行则提醒:用它做外测得到的是「从一个中心跨出去」的结果,不是「跨多个中心」的结果;论文里写成后者,就是夸大。
§5 怎么拿到:从目录树到可训练张量
5.1 目录结构与下载面
PhysioNet 的文件目录是扁平的:根目录下直接放 75 组三个文件,加上几个附属清单,没有按患者或日期分的子目录。
| 路径 | 内容 | 大小量级 |
|---|---|---|
/files/incartdb/1.0.0/RECORDS |
75 行记录名 | 数百字节 |
/files/incartdb/1.0.0/ANNOTATORS |
注释角色说明 | 一行 |
/files/incartdb/1.0.0/record-descriptions.txt |
每段的特征摘要 | 数千字节 |
/files/incartdb/1.0.0/files-patients-diagnoses.txt |
患者与诊断清单 | 数千字节 |
/files/incartdb/1.0.0/Ixx.hea |
头文件 | 约 1 KB |
/files/incartdb/1.0.0/Ixx.dat |
十二导联信号 | 约 11 MB/段 |
/files/incartdb/1.0.0/Ixx.atr |
注释 | 数千字节到数十 KB |
官方没有提供打包的整库压缩包,只有逐文件目录。全量按每段约十一兆估算,体量在几百兆级,可以一次下完——这是它相对大多长时程库的一个实用优点。
5.2 批量下载
#-- 只下一次,存到本地目录;--recursive 会把目录树按原样拉开
wget --no-parent --recursive --level=1 --accept=hea,dat,atr,txt \
--directory-prefix=incartdb \
https://physionet.org/files/incartdb/1.0.0/
#-- 核对记录数:RECORDS 末行没有换行,wc -l 会少算一条
python3.11 - <<'PY'
import urllib.request
names = urllib.request.urlopen(
'https://physionet.org/files/incartdb/1.0.0/RECORDS').read().decode().split()
print(len(names), names[0], names[-1])
PY
第二段特意写出来,是因为 wc -l 在这里会给出 74 而不是 75。文件最后一行 I75 之后没有换行符,行计数习惯的统计会漏掉它。同样的情况在按行读取 RECORDS 的脚本里也会出现——如果不做 split 直接 line.strip,最后一行仍然被读到,但如果用 count('\n') 就错了。
5.3 用 wfdb 直接流式读取
import wfdb
import numpy as np
names = wfdb.get_record_list('incartdb')
print(len(names)) #-- 75
#-- 逐段流式读取,不落盘;只统计心搏类型分布
from collections import Counter
tot = Counter()
for name in names:
ann = wfdb.rdann(name, 'atr', pn_dir='incartdb')
tot.update(ann.symbol)
print(tot.most_common(12))
get_record_list 从 RECORDS 解析,能正确处理末行无换行的情况。这个接口的好处是不需要本地磁盘,代价是每段要重新走网络,全库过一遍要一段时间。
5.4 转成通用的表结构
如果下游是 PyTorch 或 TensorFlow 的常规管线,通常需要切成定长片段。切窗策略直接决定任务难度:
import wfdb
import numpy as np
import pandas as pd
FS = 257
WIN = 10 * FS #-- 十秒一窗,与常规十二导联诊断的时长相仿
rows = []
for name in ['I01', 'I02', 'I03']:
rec = wfdb.rdrecord(name, pn_dir='incartdb')
ann = wfdb.rdann(name, 'atr', pn_dir='incartdb')
#-- 每个心拍落在哪个窗里
win_of_beat = ann.sample // WIN
for w in np.unique(win_of_beat):
sel = win_of_beat == w
#-- 取该窗内的多数心搏类型作为窗标签(示例口径,换口径请显式改)
label = pd.Series(ann.symbol[sel]).value_counts().index[0]
seg = rec.p_signal[w * WIN:(w + 1) * WIN]
if seg.shape[0] < WIN:
continue
rows.append({'record': name, 'win': int(w), 'label': label,
'lead_II': seg[:, 1].astype('float32')})
df = pd.DataFrame(rows)
print(df.shape, df['label'].value_counts().head())
这段代码只用三条记录演示口径。上正式实验时有三处必须改:一是患者编号要从 .hea 的 # patient 行读进来跟着一行走,否则后面按患者划分无从下手;二是窗标签的口径要写进方法节,否则复现不了;三是只留了 II 导联一列,做多导联模型时要把十二列都留住——这正是本库和其他单导联库最根本的区别。
5.5 心搏级注释的读取与 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',
'e': 'Q', 'j': 'Q', 'n': 'Q', 'E': 'Q', 'Q': 'Q'}
ann = wfdb.rdann('I50', 'atr', pn_dir='incartdb')
mapped = [AAMI.get(s, 'skip') for s in ann.symbol]
print(len(mapped), mapped[:8])
映射表不是这个库独有的,它来自心电算法评价的通行分组:把各种束支阻滞与正常心搏并作 N,把室上性早搏与房性早搏并作 S,把室性与 R-on-T 并作 V,把融合波作 F,其余作 Q。做跨库对比时必须用同一张表,否则数字不可比。
5.6 五个最容易出错的地方
| 位置 | 错误写法 | 后果 | 正确做法 |
|---|---|---|---|
| 统计记录数 | wc -l RECORDS 得 74 |
少一条记录 | 按空白切分计数 |
| 幅度换算 | 直接用 d_signal 训练 |
不同记录增益不同,幅度不可比 | 用 p_signal 或先除增益 |
| 数据集划分 | 按记录随机切分 | 同一次 Holter 泄漏 | 按 # patient 分组 |
| 重采样 | 当成 250 Hz 处理 | 时间轴偏 3% | 显式按 257 Hz 重采样 |
| 注释位置 | 当作精确 R 峰 | RR 间期有系统误差 | 需要精确定位时自行检测 |
§6 与库内条目的关系
6.1 关系图谱
INCART 在心电类条目里的位置,可以用"导联数 × 时长"两个轴摆出来:
| 条目 | 导联 | 时长 | 与 INCART 的关系 |
|---|---|---|---|
| PhysioNet/CinC 2017 | 1 | 数十秒 | 同为房颤检测来源,规模大得多但只有单导联 |
| MIT-BIH 房颤库 | 2 | 10 小时 | 互补:它长、INCART 宽 |
| 长期房颤库 | 2 | 24–25 小时 | 互补:它是日级负荷的标准,INCART 是片段级 |
| 十二导联心律失常库(PTB-XL 类) | 12 | 10 秒 | 直接对照:同为十二导联,一个长一个短 |
| Georgia 十二导联挑战库 | 12 | 10 秒 | 直接对照:人群不同(美国东南部),时长相同 |
| 本库 | 12 | 30 分钟 | 两个维度同时不短的少数几个之一 |
这条关系线的意义在于:如果你要论证"多导联比单导联好",只用短片段库说服力有限,因为短片段库的标签是诊断级的、人群是筛查人群;INCART 提供的是同一段连续记录内的对照,噪声、患者、时段都相同,只有导联在变。这是最干净的对照组。
6.2 检索路径
| 你要找的东西 | 检索词 | 会落到哪里 |
|---|---|---|
| 同一套注释码的其他库 | PhysioBank annotation、MIT-BIH |
§2.2 的类型码表在多个库通用 |
| 房颤长时程对照 | AFDB、Long-Term AF、LTAFDB |
§6.1 表 |
| 十二导联短片段对照 | PTB-XL、Georgia、12-lead |
§6.1 表与 §2.5 |
| 可穿戴单导联评测 | CinC 2017、single-lead AF |
§1.4 的处境表 |
| 噪声鲁棒性 | NSTDB、noise stress |
§5.6 的噪声叠加做法 |
| 挑战赛来源 | CinC 2017、challenge |
§8.2 |
6.3 与其他库的分工判据
选数据集时最实际的问题不是「哪个最好」,而是「哪个负责哪一段」。下面把常见的心电任务逐项拆开,看 INCART 该站在哪一格:
| 任务 | 主粮仓该用什么 | INCART 的位置 | 原因 |
|---|---|---|---|
| 心搏形态分类的预训练 | 大体量十二导联短片段库 | 只在外部测试出现 | 样本太少,预训练会记死 |
| 房颤检测的预训练 | 单导联大规模库 | 可在外部测试或严控下做微调 | 标签需二次加工 |
| 跨导联一致性研究 | 无可替代 | 主力 | 十二导联同步且长 |
| 导联遮蔽与补全 | 无可替代 | 主力 | 同上 |
| 噪声鲁棒性评测 | 噪声库加任一长时程库 | 主力之一 | 十二导联可分别报告 |
| 心率变异性研究 | 位置标注更严谨的库 | 辅助 | 位置未逐条校正 |
| 儿科心电模型 | 儿科专库 | 不适用 | 年龄下限 18 岁 |
| 闭环诊断报告生成 | 配报告的影像与信号库 | 不适用 | 只有诊断摘要,没有长文本 |
这张表的前两行是大多数人的真实处境:他们已经有主粮仓,缺的是一个不撒谎的裁判。被高估的用法是第三到第五行之外的所有行——把 INCART 当主粮仓的人不少,但真正需要它的场景集中在导联维度上。
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
先纠正一个常见的误判:把小样本库的问题当成"质量差"。INCART 的 75 段不是采集能力不足,而是可捐赠的十二导联 Holter 队列本来就少(§4.1)。评价它的时候不能套用"越大越好"的尺子,而应该问:在它能回答的那个问题上,它的样本够不够?
这个校正会改变五维评分的读法。规模一项它拿不到高分,但在"任务唯一性"上它几乎无可替代。把这两件事混在一起看,就会得出"不值得用"的错误结论。
7.1 五维评分
按 DAIMS 的常用维度打分,每项 1–5 分,分数针对"作为心电算法研究数据"这个用途:
| 维度 | 分数 | 理由 |
|---|---|---|
| 数据规模 | 2 | 75 段、32 名患者,训练不足,测试够用 |
| 标注质量 | 4 | 自动初标加人工修正,但位置未逐条校正 |
| 任务适配 | 5 | 十二导联加长时程,跨导联研究几乎没有替代品 |
| 文档完整 | 4 | 官方页面把人群、诊断、格式、注意事项写得清楚 |
| 可获取性 | 5 | 免注册、ODC-BY、体量小,一次下完 |
五项合计 20 分(满分 25)。这个分数结构说明它不是"全能型"选手:规模拖后腿,其余四项稳健,其中适配性拉满。
7.2 标注质量的两层
第一层是类型对不对。官方说明标注由自动算法生成后再人工修正,遵循标准定义。人工修正保证了类型的高准确度,这是它能在多个跨库研究中当"可信外部测试集"的基础。
第二层是位置准不准。官方同时明确:心拍位置由算法在十二导联上综合确定,位置本身没有人工校正,可能有偶发错位。这句话常被略过,但它对下游影响很实:任何依赖 R 峰精确时刻的指标(RR 间期、心率变异性的高频成分、QT 间期)都会带上这份误差。
| 用途 | 位置误差的影响 | 建议 |
|---|---|---|
| 心搏分类 | 小,因为分类靠形态而非时刻 | 可直接用 |
| 心率变异性 | 中到大,直接进入 RR 序列 | 先做自检测 R 峰再对齐 |
| QT / 复极分析 | 大,需逐搏定位 | 不适合直接用 |
| 房颤检测 | 中,节律不规则性可由误差部分吞掉 | 配合自检测交叉验证 |
7.3 已知的、可枚举的偏差
| 偏差 | 表现 | 影响 |
|---|---|---|
| 单人中心 | 全部患者来自圣彼得堡一家机构 | 设备、贴电极规范、判读习惯都单一 |
| 人群偏斜 | 冠心病检查人群,平均 58 岁 | 健康青年的正常形态样本少 |
| 筛选偏斜 | 优先选心电图"有料"的人 | 正常段落比例低于自然人群 |
| 段间相关性 | 同一 Holter 切出多段 | 随机切分会导致乐观偏差 |
| 标注位置 | 算法定中,未逐条校正 | 时间敏感指标有误差 |
| 节律标签不全 | 以心搏类型为主 | 节律任务需二次加工 |
| 2015 年修订 | 只改头文件 | 用旧版头文件的人校验和对不上 |
7.4 外部验证矩阵
INCART 在这几年最常被引用的方式,是当"别人家的测试集"。这类用法可以从公开论文摘要里看出轮廓。
| 验证角色 | 做法 | 讲得通的地方 | 风险 |
|---|---|---|---|
| 跨库心搏分类 | 在 MIT-BIH 上训练,本库零样本测试 | 注释码同源,可直接映射 | 人群与设备差异会同时被算作"泛化" |
| 跨库房颤检测 | 在短片段库上训练,本库外测 | 长时程片段更接近真实使用 | 标签口径需自己统一 |
| 轻量模型部署评估 | 在本库上跑量化与嵌入式推理 | 无注册本库,评测链完整 | 只看心搏级,看不到节律级 |
| 噪声注入 | 叠加噪声库做压力测试 | 十二导联可分别报告 | 本库本身噪声已偏高,叠加要谨慎 |
外部研究里已经能看到这种用法的原话:一篇 2026 年关于轻量心电分类的对照研究,明确把本库作为外部测试集,与 MIT-BIH 的分组切分一起评估量化与嵌入式部署;同期多篇心搏分类论文也在跨库设置里把它列为外测目标。这些引用说明它作为"外部集"的身份已经稳定,但它作为"训练集"的地位从未确立。
值得注意的是,那类轻量研究给出的结论往往并不乐观:在 MIT-BIH 自身的分组测试里表现还可以的模型,换到本库外测时,稀有类的召回会明显下滑。这个下滑不是评测过失,而是跨库差异的真实读数——设备带宽不同、人群不同、噪声谱不同,三者叠加。对本库的使用者来说,这意味着一个具体的用法建议:把它当"说不"的工具比当"说好"的工具更有价值。如果你的模型在本库外测上掉得厉害,那说明它在单库内的成绩里有相当一部分来自记住而不是学会;如果掉得不多,才值得进一步讨论。
反过来也要防止把外测成绩当作绝对标准。本库只有 75 段、32 名患者,一次外测的成绩波动很大,不同随机种子的差异可能与模型版本的差异同量级。合理的做法是固定患者划分与随机种子,在同一份划分上比较不同模型,而不是跨论文比较绝对数值。固定种子这件事在单库实验里常被省略,在做外测时却几乎是必需的,因为样本太小,一次划分的偶然性足以颠倒排名。
7.5 它为何能持续:稀缺的不是数据量,是那个组合
它没有更新、没有扩版,却一直被引用,原因是它占着一个别人不愿再占的坑:十二导联加三十分钟。新增这样的库需要一家机构本来就有一批十二导联 Holter 并且愿意公开,这个前提比"再采一批十秒图"难得多。只要这个组合仍然稀缺(§4.1),它作为对照组的价值就不会被新库替代。
§8 生态位与历史
8.1 历史沿革
INCART 诞生在 PhysioNet 数据捐赠的高峰期。2000 年代中后期,PhysioNet 已经积累了 MIT-BIH 系列的多套库,形成了"注释码统一、格式统一"的联邦式生态。INCART 的加入方式很典型:一家临床机构把已有的记录按规范整理后捐献,平台负责长期托管。这种模式让它在没有基金续命的情况下存活了将近二十年。
8.2 与挑战赛的关系
它对更广的用户群体而言,第一次大规模曝光来自 2017 年的房颤分类挑战赛。那届挑战赛把训练集的来源分散到多个数据库,本库是其中之一,比赛给出的训练规模是八千余条单导联记录。这里有个常被混淆的点:挑战赛用的是从本库抽取单导联片段后的形态,而不是原始的十二导联三万分钟整体;参与者的模型看到的是片段,不是完整的半小时。
这个细节值得强调,因为它解释了为什么很多人"觉得"用过 INCART,其实只见过它被切片之后的样子。原始库的十二导联同步关系,在挑战赛的数据发布里被拆掉了。
8.3 生态位:对照尺而不是主力粮仓
| 角色 | 主力粮仓 | 对照尺 |
|---|---|---|
| 典型用法 | 大规模训练、预训练 | 外部测试、跨域评测、消融对照 |
| 需要的前提 | 数据量大、标签细 | 人群不同、设备不同、导联配置不同 |
| 代表库 | MIT-BIH、短片段十二导联大库 | 本库、其他小体量跨中心库 |
| 失败模式 | 过拟合、标签噪声累积 | 样本太少导致结论不稳 |
INCART 坐在右边这一列。把对照尺当粮仓用,会立刻遇到规模瓶颈;把粮仓当对照尺用,会立刻遇到"自己测自己"的问题。两者不能互换。
8.4 谁在用它,用来做什么
从公开文献的摘要看,使用者集中在三类:做跨库泛化的信号处理组(把它当外部集)、做轻量部署的工程组(把它当真实难度基准)、做多导联方法的研究组(把它当唯一有十二导联长时程的舞台)。第三类最少,但正是它最不可替代的位置。
§9 使用指引
9.1 三种角色的路径
| 角色 | 第一天 | 第一周 | 注意事项 |
|---|---|---|---|
| 算法研究者 | 读官方页面与头文件,跑通 §2.3 的读取 | 建立按患者划分的基线,做单导联与多导联对照 | 先定标签口径再动手(§5.4) |
| 设备工程师 | 抽 II 导联与 V1 导联各跑一遍 | 量化导联位置造成的性能差,做噪声注入 | 报告要分导联,不要只报平均 |
| 教学与临床工程 | 截取 §4.3 的案例时段 | 做十二导联对照的教学图 | 标注位置未校正,图上要说明 |
9.2 一条最短的可用流程
#-- 1. 取记录清单
curl -sL https://physionet.org/files/incartdb/1.0.0/RECORDS -o RECORDS
#-- 2. 读头文件里的患者编号,建立分组表
for r in $(cat RECORDS); do
echo -n "$r "
curl -sL "https://physionet.org/files/incartdb/1.0.0/${r}.hea" \
| grep '^# patient' | awk '{print $3}'
done > record2patient.txt
#-- 3. 按患者编号分组划分(示例:患者 1-24 训练,25-32 测试)
awk '$2<=24{print $1}' record2patient.txt > train.txt
awk '$2>24{print $1}' record2patient.txt > test.txt
wc -l train.txt test.txt
import wfdb
import numpy as np
def load_lead(name, lead):
rec = wfdb.rdrecord(name, pn_dir='incartdb')
return rec.p_signal[:, rec.sig_name.index(lead)], rec.fs
x, fs = load_lead('I50', 'V1')
print(x.shape, fs) #-- 462600 个采样点,257 Hz
上面 bash 段里的第二步会发起 75 次请求。想要更省事,可以直接用官方的 files-patients-diagnoses.txt,它已经把患者与记录对好了。
9.3 引用方式
PhysioNet 的惯例是引用数据集本身加平台:
| 引用对象 | 内容 |
|---|---|
| 数据集 | St Petersburg INCART 12-lead Arrhythmia Database, version 1.0.0. PhysioNet. 2008. |
| 平台 | PhysioNet 平台综述论文(2026 年发表于 Nature Health),按官方页面的 Cite 按钮生成 |
| 联系人 | 官方页面给出的机构联系人,用于报告错误 |
写论文时建议同时注明:使用的版本号(1.0.0)、是否使用 2015 年修订后的头文件、以及划分方式是否按患者。
§10 AI 使用声明
| 项目 | 声明 |
|---|---|
| 文本生成 | 本文由 AI 辅助撰写,编辑把关结构与事实 |
| 数字来源 | 规模、结构、边界三类数字来自 PhysioNet 官方页面与文件目录 |
| 文件核验 | RECORDS、I01.hea、I75.hea、两个附属清单经直接访问确认 |
| 记录数不一致 | RECORDS 末行无换行导致行计数少一,已在 §5.2 说明 |
| 论文信息 | 仅参考 Europe PMC 摘要,未读全文 |
| 未核验内容 | 各心搏类型的具体条数、节律标注的覆盖率 |
| 图像 | 无配图;封面为生成式提示词,不含真实心电图 |
| 免责 | 本文不构成临床建议;数据使用须遵守 ODC-BY 1.0 署名要求 |
常见误读(避坑清单)
| 说法 | 实际 | 证据 |
|---|---|---|
| 「它有七十四条记录」 | 七十五段,wc -l 少算是因为末行无换行 |
RECORDS 末行是 I75 且无换行符 |
| 「它是十二导联二十四小时」 | 每段三十分钟,切自更长的 Holter | 头文件 462600 采样点 ÷ 257 Hz = 1800 秒 |
| 「它有房颤的逐段标签」 | 心搏级注释为主,节律标签不完整 | ANNOTATORS 只写 reference beat annotations |
| 「它可以直接训练心搏分类器」 | 能训,但 32 名患者一两轮就记全 | 官方记录名清单仅 75 条 |
| 「十二导联齐全就能做心梗定位」 | 无逐导联 ST 定量标注 | 诊断是整段摘要,不是导联级标签 |
| 「它的增益都一样,可以直喂整数」 | 逐记录不同,官方说 250–1100 | I01 与 I75 头文件增益不同 |
| 「按记录随机切分就可以」 | 同一患者的多段来自同一次 Holter | 头文件 # patient 说明 |
| 「它是 250 Hz」 | 257 Hz | 头文件第 1 行第 3 字段 |
| 「它是健康人基线」 | 全部为冠心病检查人群 | 官方人群描述 |
| 「它和 MIT-BIH 是同一批人」 | 不同国家、不同机构、不同人群 | 官方贡献机构为圣彼得堡研究所 |
FAQ
Q1:INCART 到底有多少条记录?为什么有人说是七十四?
七十五段,编号 I01 到 I75。说七十四的人大多是用 wc -l RECORDS 数的,而该文件最后一行没有换行符,行计数会漏掉最后一条。用空白切分或逐行读到文件尾就不会出错。
Q2:它能直接拿来做房颤检测吗?
可以,但要先确认标签口径。.atr 给的是心搏类型,房颤得靠心搏序列的不规则性或诊断描述间接判断。有研究组用官方记录的诊断文本拼出节律标签,那是二次加工,论文里要写清。
Q3:为什么它常被当作 MIT-BIH 心律失常库的跨库测试集?
两者用同一套注释码与同一套读写工具,映射到 AAMI 五分类很直接。同时它来自另一个国家、另一套设备、另一批患者,正好检验模型跨域后的表现。
Q4:十二导联是不是意味着可以做心梗定位?
导联配置具备条件,标注不具备。数据库没有逐导联的 ST 段定量标注,部分记录描述里写了 ST 改变,但那是整段定性摘要。
Q5:训练集和测试集该怎么分?
按患者编号分,不按记录编号分。头文件里的 # patient 说明多段来自同一次 Holter,随机按记录切分会把同一患者带进两侧,结果虚高。
Q6:为什么采样率是 257 Hz 这种奇怪的值?
这是原始 Holter 设备的采样率,没有重采样到 250 Hz。做跨库拼接时要么全部重采样到统一值,要么在时间轴上显式按 257 Hz 换算,否则会有百分之三左右的时间偏差。
Q7:标注准确吗?
类型准确度较高,因为是自动初标加人工修正;位置准确度一般,官方明确说位置由算法在十二导联上综合确定且未逐条校正。所以形态类任务可以直接用,时刻类任务要小心。
Q8:它和 CinC 2017 挑战赛的数据是什么关系?
本库是那届挑战赛的训练来源之一,但挑战赛用的是从中抽取的单导联片段,不是原始十二导联整体。想研究跨导联差异,必须用原始库。
Q9:体量有多大?能一次下完吗?
全量在几百兆级,可以一次下完。官方没有整库压缩包,是逐文件目录,用 wget 递归或 wfdb 流式读取都可以。
Q10:能不能用它做健康人正常心搏的参考?
不太合适。全部患者为冠心病检查人群,平均 58 岁,且筛选时偏向心电图有异常的人,正常心搏的形态多样性不足。
Q11:它的许可允许商业使用吗?
ODC-BY 1.0 允许,包括商业用途,条件是署名。引用时要写清数据集名称、版本与来源,具体条款以官方许可全文为准。
Q12:为什么只有 75 段?官方没有扩版计划吗?
官方没有给出扩版说明。从数据来源看,十二导联 Holter 在临床上本就不常见,能贡献这类记录的机构有限,这更像是现实约束而不是计划中断。
术语表
| 术语 | 解释 |
|---|---|
| Holter | 便携式长时程心电监护,患者随身携带记录仪生活 |
| 十二导联 | I、II、III、aVR、aVL、aVF 加 V1–V6,临床标准配置 |
| 逐搏标注 | 对每一次心搏标出位置与类型 |
| WFDB | PhysioNet 使用的波形数据库格式,含头文件、信号、注释 |
.hea |
纯文本头文件,声明采样率、增益、患者信息 |
.dat |
二进制信号文件 |
.atr |
二进制注释文件 |
| 增益 | 每毫伏对应的 ADC 整数值,换算物理量时使用 |
| ADC 零值 | 零电平对应的整数值,换算时先减 |
| 校验和 | 采样点累加和,用于检测文件是否完整 |
| AAMI 五分类 | 心电算法评价的通行分组:N、S、V、F、Q |
| 心房颤动 | 心房电活动紊乱,心室率绝对不规则 |
| 阵发性 | 事件间歇出现而非持续存在 |
| 室性早搏 | 心室提前除极的心搏,形态宽大 |
| 束支阻滞 | 束支传导受阻,QRS 增宽并可分型 |
| ST 段改变 | 复极异常,可提示缺血 |
| 患者级划分 | 同一患者的所有记录只进训练或只进测试 |
| 跨库测试 | 在一个库训练、另一个库测试,衡量泛化 |
| 节律注释 | 标注一段时间内的节律类型,与心搏级不同 |
| 单导联偏倚 | 模型只在特定导联有效,换导联即失效 |
| ODC-BY | 开放数据共享署名许可 |
| PhysioNet | 由 MIT 等机构维护的生物医学信号数据平台 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 记录数 | 75 | 官方页面;RECORDS 逐行 | 官方页面 |
| 患者数 | 32 | 官方页面 | 官方页面 |
| 性别构成 | 17 男、15 女 | 官方页面 | 官方页面 |
| 年龄范围 | 18–80 岁,平均 58 | 官方页面 | 官方页面 |
| 每段时长 | 30 分钟 | 官方页面;头文件 462600/257 | 官方页面 |
| 导联数 | 12 | 官方页面;头文件 | 官方页面 |
| 采样率 | 257 Hz | 官方页面;头文件 | 官方页面 |
| 每段采样点 | 462600 | I01.hea、I75.hea | 官方文件 |
| 增益范围 | 250–1100 | 官方页面 | 官方页面 |
| 注释总量 | 超过 175,000 条 | 官方页面 | 官方页面 |
| 记录名格式 | I01–I75 | RECORDS | 官方文件 |
| 注释角色 | reference beat annotations | ANNOTATORS | 官方文件 |
| 许可 | ODC-BY 1.0 | 官方页面 | 官方页面 |
| 首版日期 | 2008-05-01 | 官方页面 | 官方页面 |
| 修订日期 | 2015-09-18 | 官方页面版本历史 | 官方页面 |
| 单段信号体积 | 约 11 MB | I01.dat 响应头 | 官方文件 |
附录 B:数字的来源分层
第一层:官方页面与官方文件。 记录数、患者数、时长、导联、采样率、增益范围、注释总量、许可、日期。这些数字来自项目主页的摘要与数据描述段,以及 RECORDS、头文件、两个附属清单。
第二层:论文摘要。 关于它作为外部测试集的用法、以及与轻量化部署评测的关系,来自 Europe PMC 返回的摘要。摘要只能支撑"有人这样用",不能支撑"这样用效果如何"。
第三层:未核实。 各心搏类型的具体条数、节律标注在多少条记录里出现、噪声段的分布。这些需要逐条下载统计,超出了本篇的范围,正文中凡是涉及的地方都只做定性表述。
附录 C:完整参考文献
| 编号 | 文献 | 链接 | 用途 |
|---|---|---|---|
| 1 | St Petersburg INCART 12-lead Arrhythmia Database v1.0.0 | https://physionet.org/content/incartdb/1.0.0/ | 全部规模、结构、边界数据的来源 |
| 2 | 该库的 PhysioNet 文件目录 | https://physionet.org/files/incartdb/1.0.0/ | RECORDS、头文件、附属清单 |
| 3 | PhysioNet 平台综述(2026,Nature Health) | https://doi.org/10.1038/s44360-026-00096-z | 托管模式与引用规范 |
| 4 | PhysioBank 注释定义 | https://physionet.org/physiobank/annotations.shtml | 心搏类型码的标准含义(经归档页核对) |
| 5 | Europe PMC 检索:跨库心电分类与轻量部署 | https://www.ebi.ac.uk/[europepmc](https://www.qianfanghub.com/ai-ready-dataset/europepmc/1353)/ | 外部用法与验证角色 |
| 6 | MIT-BIH 心律失常库(对照) | https://physionet.org/content/mitdb/ | §2.5 与 §6.1 的对比 |
| 7 | MIT-BIH 房颤库(对照) | https://physionet.org/content/afdb/ | §2.5 与 §6.1 的对比 |
| 8 | PhysioNet/CinC 2017 挑战赛(来源之一) | https://physionet.org/content/challenge-2017/ | §8.2 与 FAQ Q8 |
附录 D:任务代码
任务一:按患者划分的跨库心搏分类骨架
import wfdb
import numpy as np
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',
'e': 'Q', 'j': 'Q', 'n': 'Q', 'E': 'Q', 'Q': 'Q'}
def patient_of(name):
#-- 读头文件第 4 行之后的注释,找 # patient
h = wfdb.rdheader(name, pn_dir='incartdb')
return h.comments[-2] if len(h.comments) >= 2 else ''
def beats(name, half=36):
rec = wfdb.rdrecord(name, pn_dir='incartdb', physical=True)
ann = wfdb.rdann(name, 'atr', pn_dir='incartdb')
xs, ys = [], []
for s, sym in zip(ann.sample, ann.symbol):
if sym not in AAMI:
continue
if s - half < 0 or s + half >= rec.sig_len:
continue
xs.append(rec.p_signal[s - half:s + half, :].T) #-- 12 x 72
ys.append(AAMI[sym])
return np.array(xs, dtype='float32'), np.array(ys)
for n in wfdb.get_record_list('incartdb')[:3]:
x, y = beats(n)
print(n, patient_of(n), x.shape, np.unique(y))
任务二:同一时段十二导联的可见度对比
import wfdb
import numpy as np
rec = wfdb.rdrecord('I50', pn_dir='incartdb')
fs = rec.fs
start, end = 600, 900 #-- 看五分钟
lo, hi = int(start * fs), int(end * fs)
rows = []
for i, lead in enumerate(rec.sig_name):
x = rec.p_signal[lo:hi, i]
rows.append((lead, float(np.ptp(x)), float(np.std(np.diff(x)))))
for lead, p2p, dv in sorted(rows, key=lambda r: -r[2]):
print(f'{lead:>3} 峰峰值 {p2p:6.2f} mV 差分标准差 {dv:.4f}')
第二段代码给的是"导联间差异"的一个最粗糙的度量。它的用途不是下结论,而是暴露出差异确实存在——在某些记录上,V1 的差分标准差可以是 aVL 的数倍。拿到这个表再去设计更有针对性的实验。
附录 E:如果只记五件事
| 序号 | 记住什么 | 为什么 |
|---|---|---|
| 1 | 75 段,32 名患者,每段 30 分钟,12 导联,257 Hz | 这四个数字定义了一切用法与限制 |
| 2 | 它是"对照尺"而不是"粮仓" | 拿它做主力训练会过拟合,拿它做外部测试最有价值 |
| 3 | 十六万余条心搏标注,节律标注不完整 | 心搏分类可直接用,房颤要二次加工 |
| 4 | 按患者划分,不按记录划分 | 同一 Holter 的泄漏会让结果虚高 |
| 5 | 它唯一不可替代的地方是十二个导联同步 | 跨导联差异研究几乎找不到第二个这样的库 |
编辑说明
本文的核验时间为 2026 年 10 月 27 日。核对方式为直接访问 PhysioNet 项目页与文件目录,逐一确认 RECORDS、I01.hea、I75.hea、ANNOTATORS、两个附属清单的可访问性与内容;论文侧只检索了 Europe PMC 的摘要,未读全文。记录数 75 与 wc -l 得到的 74 之间的一字之差,原因是 RECORDS 末行无换行符,这一点在 §5.2 与 FAQ 第 1 问里各说明一次。未覆盖的内容包括:各心搏类型的具体条数、节律标注的覆盖率、噪声段的分布、以及逐段诊断与记录描述的完整对应关系。这些需要下载全量后统计,本文按要求只写规模、结构、边界三类数字。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- afpdb — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- aftdb — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- twadb — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- cinc-2021 — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- ltafdb — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- cinc-2011 — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- cinc-2020 — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- butppg — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- ecg-image-database — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
- georgia-12-lead-ecg-challenge — 共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

