MIMIC-IV 使用笔记:ID 逻辑、模块边界与 V2.0 避坑指南
发布时间:2026/10/10 12:46:18 锦皓数字建站

简介面向临床医疗数据研究者与机器学习建模人员这份MIMIC-IV文档介绍与使用笔记以结构化方式解析了重症监护数据库的核心逻辑。内容涵盖患者标识体系subject_id、hadm_id、transfer_id、stay_id、日期时间字段规范、编码表规则以及Core/Hosp/ICU/ED/CXR/Note六大模块的定位。针对admission、patient、transfers、diagnoses_icd、labevents、drgcodes等常用表逐一说明字段含义与典型坑点如部分院内死亡患者缺失deathtime、同一hadm_id存在ICD-9与ICD-10两套诊断、低优先级排序有时不准确等实际问题并给出医院内转移、急诊时间等细节解读。资源为单个docx文档约97KB便于离线查阅虽然体量不大但信息密度较高。已有7734人学习使用适合刚开始接触MIMIC-IV、需要快速摸清表结构及数据分析注意事项的研究者。1. MIMIC-IV 使用笔记先把 ID 逻辑、模块边界和 V2.0 的坑讲清楚第一次拿到 MIMIC-IV 的访问权限时大多数人都不是被分析难住的是被几十张表之间的关系绕晕的subject_id、hadm_id、transfer_id、stay_id 四个 ID 谁嵌套谁date 和 time 字段分辨率有什么差别ICD-9 和 ICD-10 为什么会在同一张诊断表里同时出现。这份文档就是解决这些问题的——它把 Core/Hosp/ICU/ED/CXR/Note 六个模块的核心表、字段含义和实际使用中容易翻车的点都记了下来同时标注了 V2.0 相对旧版本的关键变化。适合正在跑 ICU 数据分析、构建预后模型、或者拿公开库做课程设计与论文复现的开发者。2. 四个 ID 与时间字段先把数据的粒度对齐再谈分析2.1 subject_id / hadm_id / transfer_id / stay_id 的层级关系MIMIC-IV 的跟踪逻辑可以概括成一句话subject_id 认人hadm_id 认住院transfer_id 认病房转移stay_id 认同类型病房内的连续停留。这个层级关系是后面所有关联查询的地基很多入门者在这里翻车是因为只记住了患者有唯一 ID却没意识到每次入院、每次转床都会产生新 ID。以 ICU 场景为例一个患者在某次住院期间从 ICU 的 A 病房转到 B 病房transfer_id 会更新但 stay_id 保持不变如果再转到普通病房ICU 模块的 stay_id 就结束了。换句话说stay_id 是 ICU 模块内部的概念而 transfer_id 覆盖整个住院期间的床位移动。所有 ID 的分配都是随机的与时间先后无关所以别指望通过 subject_id 的大小判断入组先后。ID粒度典型用途subject_id患者跨表关联患者人口学、随访数据hadm_id单次住院关联入院诊断、化验、DRG、出院结局transfer_id病房转移事件追踪患者在院内的床位流转stay_id同类型病房连续停留关联 ICU 模块中的 chartevents、inputevents做分析时有一个习惯我建议尽早养成凡是涉及 ICU 内生命体征、静脉给药、呼吸机参数一律以 stay_id 为纽带凡是涉及诊断、入院来源、出院去向、院内死亡一律以 hadm_id 为纽带凡是涉及死亡随访、年龄、性别、首次入院年份一律回到 subject_id。混用这三个粒度是数据量对不上时最常见的元凶。2.2 date 与 time 字段时间分辨率是入模前必须确认的事文档里反复强调一个规则后缀为 date 的字段分辨率最低为天后缀为 time 的字段分辨率最低为分钟。这个规则看似简单但实际跑 SQL 时很容易忽略。比如 admissions 表里的 admittime 和 dischtime 都是分钟级而 procedures_icd 里的 chartdate 只有天级——如果你想算入院后多少小时做了手术用 chartdate 是算不出精确时间的只能退回到天级窗口。更隐蔽的是 charttime 与 storetime 的区别。charttime 是测量的记录时间storetime 是数据录入/存储时间两者可能相差数小时。文档给出的准则是临床分析以 charttime 为准。我见过有人用 storetime 去对齐 ICU 入科时间结果把一批夜班补录的数据整体平移了几个小时导致 24 小时生命体征窗口里混进了前一天的测量值。另外要注意 intime / outtime 这类字段。icustays 表的 intime 是进入 ICU 的时间outtime 是离开时间los 是 ICU 停留天数。计算入 ICU 后 6 小时/24 小时的时间窗时基线应该用 intime 而不是 charttime 的最小值——后者会被转运途中的零散记录污染。2.3 anchor_age 与 anchor_year脱敏之后的年龄怎么算patients 表里没有出生日期取而代之的是 anchor_age 和 anchor_year。anchor_age 表示第一次入院年龄规则是小于 18 岁记为 0大于 89 岁记为 91。这种截断方式意味着你拿到的年龄是一个粗略值不能精确到岁数 月数。anchor_year 是第一次入院年份anchor_year_group 则给出一个大约真实的入院时间区间。做纵向研究时需要用 anchor_year_group 来近似时间跨度比如患者在 2014-2016 年之间首次入院。很多新手想靠 anchor_age 反推出生年份去计算某个随访节点的准确年龄这条路走不通——数据库设计时就没打算让你还原真实日历时间。实际处理时我的做法是如果只需要成年 / 老年这种粗粒度分层直接用 anchor_age如果需要入院时的年龄是否大于某阈值也直接用 anchor_age如果要做时间相关的生存分析把 anchor_year_group 的起始年当作时间原点并在方法学里注明近似。3. 六大模块拆解从人口学到影像每条分析链路对应哪几张表3.1 模块总览先定位再取数MIMIC-IV 的表格分为六个模块Core、Hosp、ICU、ED、CXR、Note。其中 Core 模块在 V2.0 里被移除admissions、patients、transfers 这三张表挪到了 Hosp 模块。如果你手上还是 V1.x 的导入版本schema 前缀会是 mimic_coreV2.0 之后统一是 mimiciv_hosp、mimiciv_icu、mimiciv_ed。写 SQL 之前先确认一下自己库里的 schema否则表名都找不到。模块内容核心表常见分析场景CoreV2.0 并入 Hosp人口学、入院信息、病房转移admissions、patients、transfers人群筛选、基线特征表、结局定义Hosp诊断、化验、药物、微生物、收费diagnoses_icd、labevents、prescriptions、microbiologyevents合并症评分、实验室指标、用药分析ICU生命体征、出入量、呼吸机、镇静icustays、chartevents、inputevents、procedureevents重症监测、时序模型、早期预警ED急诊分诊、生命体征、药物协调edstays、triage、vitalsign、medrecon急诊拥挤度、分诊模型CXR胸片文件路径与影像学报告cxr-record-list、cxr-study-list影像模型、图像-标签训练Note出院总结、超声、影像等文本报告不公开获取文本挖掘、NLP3.2 Hosp住院、诊断、化验与处方Hosp 模块是六边形战士几乎所有非 ICU 时序数据都在这。admissions 表以每次入院为单位每条记录有一个唯一的 hadm_id其中 hospital_expire_flag 表示本次住院是否院内死亡。这里有个值得注意的细节部分院内死亡患者没有 deathtime可能是数据库本身的问题所以做结局变量时我会以 hospital_expire_flag 为准而不是靠 deathtime 是否为空来判断。诊断相关的表有三层d_icd_diagnoses 是 ICD 编码的定义表包含 icd_code、icd_version、long_titlediagnoses_icd 是患者实际诊断记录seq_num 表示优先级序号越靠前越重要drgcodes 则使用 DRG 编码与 diagnose 表中的主要诊断相对应通常用于医保分组相关的分析。有一个坑必须记住同一 hadm_id 可能对应两套诊断一套 ICD-9一套 ICD-10本质上表达相同的临床信息取一套使用即可。化验相关的核心是 d_labitems 和 labevents。d_labitems 通过 itemid 连接 labevents字段里有 fluid血液、尿液等、category血气、化学以及 V2.0 之前存在的 loinc_code。labevents 的每个检验样本有 specimen_id同一个样本可以做多个检验value 是文本结果valuenum 是数值结果valueuom 是单位ref_range_lower/ref_range_upper 是正常参考范围flag 标记是否异常。做定量分析时优先用 valuenum后面避坑章节会细说。药物相关的是 prescriptions 和 pharmacy。prescriptions 记录每张处方的 starttime、stoptime、drug 名称、剂量、给药途径pharmacy 表通过 pharmacy_id 与其关联补充药物容器、NDC 编码、GSN 编码等信息。如果要算24 小时液体入量注意 prescriptions 里的剂量单位比较杂需要先统一单位。3.3 ICUchartevents 是重症分析的主战场ICU 模块的数据来自临床信息系统记录内容包括静脉给药、呼吸机设置、生命体征等。icustays 表给出每次 ICU 入住的 intime、outtime、los 以及 first_careunit、last_careunit。一个患者一次住院可能有多次 ICU 入住每次对应一个新的 stay_id分析时如果要首次入 ICU得按 intime 排序自己取第一条。chartevents 是 ICU 模块里最大也最常用的表包含病人所有图表数据。它通过 itemid 关联 d_items 表d_items 里有一个 linksto 字段标明该项目实际连接到哪张表——比如 chartevents、inputevents 还是 outputevents。这点非常实用想找药物相关记录先查 d_items 里 linksto inputevents 的条目而不是直接翻 chartevents。下面的 itemid 是日常分析里比较常用的几个但注意不同版本可能有增减跑数据前先用 d_items 核对 label。itemidlabel说明220045Heart Rate心率220179Non Invasive Blood Pressure Systolic无创收缩压220181Non Invasive Blood Pressure Mean无创平均压220050Respiratory Rate呼吸频率220210O2 saturation pulseoxymetry指脉氧饱和度chartevents 的字段里charttime 是测量时间storetime 是录入时间前文已经强调以 charttime 为准。warning 字段表示是否为手工记录常见于手动输入的生命体征。有一点要注意chartevents 内含部分 lab 数据与 labevents 表重复做实验室指标建模时优先从 labevents 取数chartevents 只作为补漏。V2.0 里还新增了 itemid220001用来记录来自 MetaVision 的 1000 多个问题多数与护理计划有关分析生命体征时记得把它过滤掉。3.4 ED急诊分诊与住院衔接ED 模块记录急诊相关信息通过 subject_id 和 hadm_id 与其他模块相连。edstays 是急诊来访的主要跟踪表提供进入和离开急诊的时间diagnosis 表提供从急诊科出院后确定的诊断triage 表存第一次分诊时的生命体征vitalsign 表记录急诊收治后 1-4 小时的常规生命体征vitalsign_hl7 表则是通过遥测技术每分钟记录的数据数据量更大但覆盖时段可能不完整。ED 和住院之间的关系很容易踩坑急诊患者不一定住院住院患者也不一定从急诊入院。因此 edstays 里部分记录没有 hadm_id这是正常的不要当成数据缺失去补。统计急诊转住院率时要以 edstays 为分母用 hadm_id 是否非空来判断是否住院。medrecon 表是入院时的药物协调记录pyxis 表则记录通过 pyxis 系统配制的药物这两个表在做用药安全性分析时比较有价值。3.5 CXR影像文件与自动标注标签CXR 模块提供胸部 X 光片的源数据原始文件是 DICOM 格式同时提供 JPG 格式下载。cxr-study-list 记录影像学报告路径指向 txt 文件cxr-record-list 记录图像文件dicom_id 是图像编码path 指向 dcm 文件。文档里特意提到一个现象有影像的患者可能没有住院记录且有部分图像按照路径找不到对应文件——即有文本却找不到对应图像。做多模态研究时必须先做路径完整性检查。CXR 模块里最有价值的是 CheXpert 自动标注结果这是基于影像学报告的非人工标注为 14 个标签打标。每个标签有四种取值1 表示被正面提及0 表示被负面提及如无肺不张-1 表示被提到但无法判断或说法模棱两可空值表示该特征没有被提到。四个取值对应四种建模策略做分类任务时通常把 1 当阳性、其余当阴性但 -1 也可以单独作为一个不确定性类别。mimic-cxr-2.0.0-split 还提供了训练集、验证集、测试集的官方划分做影像模型直接按这个划分走。3.6 Note不公开的文本报告模块Note 模块包括出院总结、超声、心电图、影像学等文本报告但当前版本标注为 NOT PUBLICLY AVAILABLE不随主数据库公开分发。如果你需要做临床文本 NLP需要走额外的数据申请流程如果只是做常规表格数据分析这个模块可以先跳过。4. V2.0 变化与版本迁移新增 omr、随访数据与新表 ingredientevents4.1 版本迁移第一件事Core 模块不存在了MIMIC-IV_V2.0 发布于 2022 年 6 月第一个结构性变化是移除 Core 模块admissions、patients、transfers 三张表全部并入 Hosp 模块。这意味着 V1.x 时期习惯写的 mimic_core.admissions 路径全部失效需要改成 mimiciv_hosp.admissions。第二个变化是移除新生儿数据后续会与新生儿重症监护室数据一起在其他项目中单独发布。如果你之前在跑儿科相关分析V2.0 里对应人群直接缺失需要换数据源。还有一个容易被忽略的变化由于患者纳入机制改变大约 700 个 stay_id约 1%发生了改变。不同版本的数据摘要、计数都不再可比版本迁移后第一件事是重新跑一遍基线统计而不是沿用旧数字。4.2 ICU 模块的变化ingredientevents 与 itemid 220001V2.0 的 ICU 模块新增了 ingredientevents 表与 inputevents 关联。之前 inputevents 里跟踪的每次静脉给药都与一组成分相关这些成分包括含水量、热量信息等现在这些成分被分离到 ingredientevents 表中。这个变化对营养学相关研究是利好可以通过对所有水成分求和来评估 fluid input而不需要自己从药物成分表里拼。同时chartevents 新增 itemid220001记录来自 MetaVision 的 1000 多个问题大多数与护理计划有关在护士轮班期间早上 7 点或晚上 7 点记录。这个 itemid 会让 chartevents 的表征发生变化——如果你按 itemid 粗筛生命体征可能会把这批非监测类记录带进来建议在 d_items 里查一下 220001 的 category分析时直接排除。inputevents 和 procedureevents 各删除了几个全空值列inputevents 删除了 cancelreasonprocedureevents 删除了 totalamount、totalamountuom、cancelreason 以及一批 comments 相关字段。如果你的旧脚本里引用了这些列迁到 V2.0 会直接报 column does not exist。4.3 Hosp 模块的变化随访数据、omr 新表与 labevents 的 itemid 调整Hosp 模块是 V2.0 改动最密集的地方。admissions 表修复了患者通过急诊入院时缺少 edregtime 和 edouttime 的问题transfers 表修复了 hadm_id 为 NULL 的急诊患者 outtime 错误——V1.x 里这批记录的在院停留时间算错了。patients 表的 dod 字段是本次更新最大的惊喜新增了来自州死亡记录的院外死亡数据。对入住 ICU 的患者死亡日期记录从 8,223 条增加到 23,844 条也就是说 V2.0 版本的随访数据可用了。之前很多研究只能用 hospital_expire_flag 做院内死亡结局现在可以做院外生存分析。但注意 dod 包含院内死亡与院外死亡两部分做结局定义时要区分场景如果研究终点是院内死亡仍然用 hospital_expire_flag如果是全因死亡率则用 dod。新增的 omr 表来自在线医疗记录包含血压、身高、体重、BMI 和估计肾小球滤过率eGFR。这些值可从住院和门诊访问中获得许多情况下还能拿到患者住院前的基线值。以前想在 MIMIC 里找基线 BMI要么从 chartevents 里拼要么忍受大量缺失现在直接查 omr 就行做急性肾损伤相关研究时 eGFR 基线尤其有用。labevents 的变化比较折腾d_labitems 表中 43 项 itemid 发生变更loinc_code 列被删除之后与外部标准的映射会在官方 git 仓库中协作维护。另外许多以前只出现在 comments 字段的实验室指标现在 value 字段里也有值了。迁移时最稳妥的办法是导出旧版 43 个 itemid 列表对照新版 label 建立映射而不是凭记忆写硬编码。4.4 迁移到 V2.0 后先检查这几项版本迁移后别急着跑分析先做三个检查第一核心表行数对比确认 icustays、admissions、labevents 的行数变化在预期范围内第二itemid 映射检查把常用旧版 itemid 与新版 d_items 做一次 label 匹配第三时间字段完整性检查重点看 transfers 表里 hadm_id 为 NULL 的急诊患者 outtime 是否已修复。一个常用的检查 SQL 思路是这样的以旧版 itemid 为基准按 label 文本模糊匹配新版 itemid把差异项列出来。SELECT old.itemid AS old_itemid, old.label AS old_label, new.itemid AS new_itemid, new.label AS new_label FROM ( SELECT itemid, label FROM mimiciv_hosp.d_labitems WHERE itemid IN (50806, 50807, 50808, 50809) ) old LEFT JOIN mimiciv_hosp.d_labitems new ON lower(trim(old.label)) lower(trim(new.label)) WHERE old.itemid ! new.itemid OR new.itemid IS NULL;这里先从旧版常用 itemid 列表建一个临时子集按 label 文本与新版表做等值匹配然后找出 itemid 改变或匹配不上的记录。需要注意匹配条件只用了 label 文本如果同一 label 对应多个 itemid会返回多行这是正常的关键是确认旧 id 是否还在新表中存在。如果 new.itemid 为空说明这个项目可能已被合并或删除需要去官方变更说明里确认。跑完这条 SQL再用新版映射表更新你的分析脚本。5. 使用笔记里的避坑清单四个最容易误读数据的地方5.1 同一个 hadm_id 出现两套 ICD 诊断现象查 diagnoses_icd 按 hadm_id 筛选时发现同一个住院记录返回了几十条诊断仔细一看ICD-9 和 ICD-10 各有一套内容基本对应但编码完全不同。原因医院系统在 ICD 版本过渡期同一住院记录同时用两套编码系统各编码了一遍。文档里明确说本质上相同取一套使用即可。解决在 join 诊断定义表d_icd_diagnoses时把 icd_version 写进关联条件做统计时统一加一个 WHERE icd_version 10 的过滤或用 ICD-9取决于你的研究用什么版本同时 seq_num 越靠前越重要低优先级的排序有时不准确用来做合并症识别时只取前几个诊断即可。5.2 deathtime 与 hospital_expire_flag 不一致现象hospital_expire_flag 1 的患者里有一部分在 admissions 表的 deathtime 字段是 NULL也有部分患者 deathtime 非空但 flag 0。原因文档里的原话是可能是数据库本身的问题。deathtime 的采集链路在不同年份、不同院区并不完全一致而 hospital_expire_flag 是结构化的出院状态字段可靠性更高。解决判定院内死亡一律用 hospital_expire_flag不要用 deathtime 是否为空来做生存分析的事件标注。如果研究终点是短期死亡可以结合 deathtime 计算死亡距入院时间但遇到 deathtime 缺失时按 flag 补一个最大随访时间做右删失不要直接删掉这条记录。V2.0 补充了院外死亡数据后dod 字段包含了更多死亡信息但要区分院内死亡与院外死亡两者混在一起算会高估短期死亡率。5.3 labevents 的 value 与 valuenum文本值 vs 数值值现象从 labevents 取某个检验指标做统计时直接 SELECT value 发现有的行是 4.2有的是 0.5还有的是 NEGATIVE对 value 做 CAST 转数字直接报错。原因value 是检验结果的原始文本允许带比较运算符、文字描述valuenum 是系统尽量转成数字的结果但只有能明确转成数值时才非空。两个字段是互补关系不是冗余关系。解决定量指标一律用 valuenum并在过滤条件里加 valuenum IS NOT NULL定性结果如阴性、阳性、未检出从 value 取配合 flag 字段判断是否异常。另外部分低定量检测比如 0.5在 valuenum 里可能是 0.5要留意检测下限对分布的影响。V2.0 里很多以前只在 comments 里出现的值现在进了 value 字段但 comments 仍然值得检查尤其做罕见指标时。5.4 ED 与住院表关联别把急诊就诊都当作住院现象用 edstays join admissions 做分析发现大量急诊记录匹配不上 hadm_id或者反过来一部分住院患者的入院来源并不是急诊。原因急诊患者不一定住院住院患者也不一定从急诊入院。edstays 中存在很多只来急诊、处理完就回家的患者这些记录天然没有 hadm_id。解决分析急诊相关问题时先明确分母。研究急诊转住院率时以 edstays 为分母统计 hadm_id 非空的比例研究急诊来源患者特征时以 edstays join admissions 的结果为样本并注明排除标准。另一个相关的坑是 transfers 表V1.x 中 hadm_id 为 NULL 的急诊患者 outtime 存在错误导致停留时间计算偏差V2.0 已修复但如果你在跨版本比较历史结果要格外小心这个口径差异。6. 把模块串起来一条首次 ICU 入院的分析流水线前面把表拆开讲最后落到实际场景。最常见的分析起点是首次入院 ICU 的成年患者然后拉人口学、诊断、生命体征、结局。我的习惯是先圈人群再取数据避免一上来就 join 大表。WITH first_icu AS ( SELECT subject_id, hadm_id, stay_id, intime, ROW_NUMBER() OVER (PARTITION BY subject_id ORDER BY intime) AS icu_seq FROM mimiciv_icu.icustays ) SELECT icu.subject_id, icu.hadm_id, icu.stay_id, icu.intime, pat.anchor_age, pat.gender, adm.hospital_expire_flag FROM first_icu icu JOIN mimiciv_hosp.patients pat USING (subject_id) JOIN mimiciv_hosp.admissions adm USING (subject_id, hadm_id) WHERE icu.icu_seq 1 AND pat.anchor_age 18;这个查询先用窗口函数给每个患者的所有 ICU 入住按时间排序取第一次入 ICU 的记录再关联 patients 和 admissions 拿人口学与院内死亡标志。WHERE 条件里的 anchor_age 18 是成年人筛选的常用口径anchor_age 本身就是首次入院年龄直接用即可。注意 icu_seq 是本次新计算的排序和原表里的任何 ID 都无关。人群圈定之后拉入 ICU 后 24 小时的心率和血压按 itemid 白名单过滤。SELECT ce.charttime, di.label, ce.value, ce.valuenum, ce.valueuom FROM mimiciv_icu.chartevents ce JOIN mimiciv_icu.d_items di ON ce.itemid di.itemid WHERE ce.stay_id 30123456 AND ce.itemid IN (220045, 220179, 220181, 220210, 220050) AND ce.charttime BETWEEN ce.intime AND ce.intime INTERVAL 24 hours ORDER BY ce.charttime;这段代码把 chartevents 与 d_items 关联将 itemid 翻译成可读 label时间窗口用 intime 加 24 小时间隔约束确保取到的是入 ICU 后第一天的数据。itemid 白名单里是心率、收缩压、平均压、血氧、呼吸频率这几个常用监测项窗口过滤可以显著减小结果集避免扫描整张 chartevents。使用时要确认你库里的 itemid 与 label 对应关系版本更新后建议先单独查一遍 d_items。数据出完后我会强制对三件事做检查一是 hospital_expire_flag 与 deathtime 的对应关系确认没有 flag1 但 deathtime 为空的样本二是确认 schema 前缀与版本匹配V2.0 用 mimiciv_hosp、mimiciv_icu别混用旧前缀三是时间字段对齐方式窗口一律基于 intime 与 charttime不碰 storetime。这三项检查做完结果基本可以放心往下走。从那以后每次拿到新版 MIMIC 数据我都强制走一遍这套流程先写清四个 ID 的层级和结局变量定义再跑人群筛选最后按 itemid 白名单拉数据。这个习惯帮我少踩了无数次版本迁移和字段误读的坑。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。