ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MIMIC-IV 3.1核心解析:Hosp与ICU模块表结构、关键字段与关联方法

MIMIC-IV 3.1核心解析:Hosp与ICU模块表结构、关键字段与关联方法 花了不少时间把MIMIC-IV 3.1完整过了一遍发现很多刚拿到数据权限的朋友第一反应都差不多解压出来几百个CSV看官方文档看得脑壳疼问群里老司机也是各说各话。其实MIMIC-IV 3.1这个版本的表虽然多但核心就集中在几个模块里其中Hosp和ICU又是绝大多数重症研究绕不开的两大块。这篇文章我准备用最直接的讲法把Hosp和ICU模块里的表格、关键字段、表间关联一次说清楚。适合两类人看一类是刚通过数据库使用培训、正准备跑第一个查询的新手另一类是已经写了几个月SQL、但每次查字段还得翻文档的老手。MIMIC-IV 3.1的数据结构并不是平铺的一堆表格它是按业务域拆开的。刚开始接触时不要试图把所有表都背下来而是先抓住模块划分再理解每张表在分析流程里的定位这样遇到具体问题时才知道去哪儿找数据、怎么把表拼起来。1. 先看懂模块划分再谈单张表1.1 MIMIC-IV 3.1的四大模块到底怎么分工MIMIC-IV 3.1整体上按数据来源和业务层级分成几个模块CORE放的是跨模块共用的基础表HOSP放的是医院住院层面的数据ICU放的是重症监护病房内的分钟级监测数据ED放的是急诊相关数据。这里要特别提醒一句CORE并不是说它不重要恰恰相反像patients、admissions这类最常被当作“主表”的表在官方架构里其实挂在CORE下面。只是CORE文件本身不大很多教程为了方便习惯把它和HOSP一起讲我后面也沿用这种讲法。如果打一个比方CORE是人的底稿HOSP是住院期间的全部病历ICU是住进ICU那几天的床边监测记录。三者通过三个主键逐层关联subject_id患者ID、hadm_id住院ID、stay_idICU入住ID。理解了这个层级关系你就知道为什么查一个ICU患者的数据往往要join三张以上的表——因为每个模块只存了自己职责范围内的字段。1.2 为什么教程先讲Hosp和ICU而不是先讲EDED模块从MIMIC-IV 3.0开始单独成型到3.1已经有了比较完整的急诊分诊、生命体征等数据。但在实际研究中ED数据的利用率远没有Hosp和ICU高。原因很现实急诊患者中很大一部分只是做了筛查、留观或简单处置并没有住院也没有进ICU这类患者如果纳入分析后面很可能会因为没有结局数据而被大量剔除。而Hosp和ICU则是几乎所有重症研究的主战场大多数临床问题都可以抽象成“识别目标人群、提取住院和ICU期间的特征、看结局”三个步骤这三步几乎全落在Hosp和ICU的表格上。还有一点很重要Hosp和ICU的字段设计存在大量公共逻辑比如都用itemid关联字典表都用charttime区分事件时间都允许同一个患者有多条记录。把这两个模块放在一起讲很多共性问题可以一次说透后面再看ED和CORE就会轻松很多。2. Hosp模块医院层面数据的“仓库”Hosp模块承担的是患者从入院到出院这一整段医院流程的数据记录。它的特点是表多、字段杂但绝大多数表都围绕一个核心主键hadm_id展开。下面我按使用频率把Hosp模块里最常打交道的几组表拆开讲。2.1 patients和admissions一切查询的起点patients表按subject_id每条一个患者记录性别gender、基于出生年份推算的anchor_age、所在的年代区间anchor_year_group以及死亡日期dod。注意MIMIC为了匿名化把出生日期改成了年份区间所以不要想着精确计算年龄anchor_age已经是一个可以拿来直接用的字段。admissions表则是按hadm_id每条一次住院。它记录入院时间admittime、出院时间dischtime、入院类型admission_type急诊、择期手术、紧急等、入院来源admission_location、出院去向discharge_location以及insurance、language、marital_status、ethnicity这些人口学信息。这里要特别记住hospital_expire_flag字段1表示该患者在住院期间死亡0表示存活出院。很多研究里的“院内死亡率”结局变量就是直接取这个字段算出来的。这两张表的关系是一对多一个subject_id可能对应多个hadm_id。所以做多次住院相关研究时一定要先想清楚是以患者为单位还是以住院为单位否则很容易把重复住院的记录当成独立样本。2.2 diagnoses_icd和procedures_icd诊断与手术怎么查诊断和手术编码表是筛选人群最常用的入口。diagnoses_icd记录每次住院期间的主要诊断和次要诊断procedures_icd记录住院期间做的有创操作和手术。两张表都用ICD编码体系字段里同时包含icd_code和icd_version9和10两套编码分别对应不同的字典表做转换时要去d_icd_diagnoses和d_icd_procedures里查可读的英文描述。实际分析中有一个高频问题同一个hadm_id下面会有好几条诊断记录怎么选seq_num字段就是排序号seq_num1通常代表主要诊断。如果研究要做“按诊断筛选人群”我的建议是先只取seq_num1做主诊断筛选再根据研究设计决定要不要纳入次要诊断。如果不加区分把所有诊断记录都算上人群体量会明显膨胀而且可能混入大量不相关的合并症。ICD编码在9和10之间差别很大比如心梗在ICD-9是410.x在ICD-10里就变成了I21.x。如果你用的是3.1版本建议直接以ICD-10为主只在历史版本对比时才需要处理两套编码的映射问题。2.3 labevents和microbiologyevents检验与微生物的关键字段labevents是临床研究里出镜率最高的表之一保存了住院期间所有的检验结果包括血常规、生化、凝血、血气等。核心字段有specimen_id标本号、itemid检验项目编码、charttime采样时间、value原始值字符串、valuenum数值型值、valueuom单位、ref_range_lower和ref_range_upper参考范围上下限以及flag异常标志。看到value和valuenum同时存在很多人会问为什么不能只用valuenum。因为一部分检验项目的结果本身就不是数值比如尿常规里的颜色、显微镜下的形态描述、微生物培养结果这些只能存在value里。所以做数值型指标分析时一定要先用itemid过滤到明确的项目再去取valuenum同时还要警惕单位不统一。同一个检验项目在不同年份、不同设备下可能出现过不同的单位处理肌酐、胆红素这类指标时要养成查看valueuom分布的习惯。microbiologyevents表保存微生物培养和药敏结果包括标本类型spec_type_desc、培养出的微生物org_name、抗生素ab_name、药敏结果interpretationS/I/R等。做院感、耐药分析的研究主要就是在这张表上做文章。需要提醒的是微生物报告的特点是“检验周期长、结果分层多”同一个标本可能先出涂片结果再出培养结果处理时要注意去重或按报告时间排序。2.4 emar、pharmacy和poe用药数据怎么理用药数据是很多人的知识盲区因为涉及的表比较多而且版本之间还有变化。3.1版本里处方层面的信息主要在pharmacy和poe/poe_order实际给药记录在emar和emar_detail。简单理解pharmacy偏药品字典和处方信息poe偏医嘱开立记录emar偏护士实际执行记录。emar表记录的是用药事件而不是静态处方同一个医嘱可能对应多次给药记录字段里能看到给药途径IV、PO、胃管等和给药时间。如果研究只想判断“某药是否使用过”直接查emar就够了但如果要算“总剂量”就要格外小心单位换算同一个药在不同科室可能用了不同剂型和剂量单位比如肝素就有u和iu两种写法头孢类的规格更是五花八门。另外要留意emar_detail这张表它是3.1版本里把给药过程拆得更细的一张新表适合做给药时间点、用药遗漏率这类精细分析。初学者不一定要用但有这个意识能少走弯路。2.5 字典表d开头的那批表究竟怎么用Hosp模块里有一批d_开头的字典表比如d_labitems、d_icd_diagnoses、d_icd_procedures。它们的作用非常简单把itemid、icd_code这类编码翻译成人能看懂的字段名同时附带category、unitname等额外属性。举个例子labevents里的itemid50862在d_labitems里可能对应的是“SCr/Serum Creatinine”这类标签不查字典表你根本不知道这个数字代表什么。我自己的习惯是任何从主表里查出来的itemid都要强制join一次字典表再进入下游分析。不要凭印象把某个itemid记死因为MIMIC版本迭代时itemid可能重新编号不同模块里同样数字的itemid含义也可能完全不一样。字典表就是用来兜底的它保证你在换版本、换项目时不用把SQL重写一遍。Hosp模块涉核心表速查如下方便日常检索。表名主键核心内容常用字段patientssubject_id患者基本信息gender, anchor_age, dodadmissionshadm_id住院记录admittime, dischtime, hospital_expire_flagdiagnoses_icdhadm_id seq_num诊断编码icd_code, icd_versionprocedures_icdhadm_id seq_num手术操作编码icd_code, icd_versionlabeventslabevent_id检验结果itemid, charttime, value, valuenummicrobiologyeventsmicroevent_id微生物培养药敏spec_type_desc, org_name, interpretationemaremar_id用药执行记录itemid, charttime, routepharmacypharmacy_id处方药品信息drug, dose, routepoepoe_id医嘱开立记录ordertime, order_typed_labitemsitemid检验项目字典label, category, unitnamed_icd_diagnosesicd_code icd_version诊断字典long_title3. ICU模块分钟级监测数据的核心ICU模块的定位和Hosp不同。Hosp记录的是“整个过程发生了什么”ICU记录的是“每时每刻发生了什么”。它包含生命体征、呼吸机参数、液体出入量、镇静评分等一系列高频采集的数据表的数据量通常比Hosp大一个数量级。要在这些表里高效查询必须先理解“事件表 字典表”的结构。3.1 icustaysICU入住的“主索引”icustays表是ICU模块的入口表每条记录代表患者一次ICU入住主键是stay_id同时保留subject_id和hadm_id方便向医院层面关联。字段有first_careunit和last_careunit记录首次和末次ICU类型intime和outtime是入ICU和出ICU的时间。为什么强调它是入口表因为ICU里的所有事件表比如chartevents、inputevents几乎都带有stay_id。分析时先确定目标ICU入住记录再通过stay_id去关联事件表是最标准的做法。反过来如果你拿到一个患者想看他某次ICU期间的全部数据也需要先靠icustays把stay_id定下来。实际使用中还有一个细节同一个患者可能在同一住院期间多次进出ICU所以不要默认一个hadm_id只有一个stay_id。做“ICU相关分析”时先明确是“第一次ICU入住”还是“所有ICU入住”通常会在icustays上按intime排序取第一条。3.2 chartevents和datetimeevents观察类事件的两张核心表chartevents是ICU模块里数据量最大的表记录生命体征、呼吸机参数、意识评分等一切周期性采集的数值和文本内容。结构上和labevents类似itemid加charttime再加value、valuenum、valueuom同时还带一个storetime字段表示数据入库时间。区分value和valuenum在这个表里特别重要。很多人写SQL时直接对value做聚合结果因为字符串类型报错。正确做法是取valuenum并限定valueuom比如血压的mmHg、体温的°C。如果碰到某一行value非空但valuenum是空说明该项目的结果本身就是文本比如瞳孔大小描述、Richmond镇静评分这类记录。datetimeevents记录的是时间点类型的事件比如气管插管时间、深静脉置管时间。它没有数值value只有charttime或者storetime作用是告诉你“这件事在什么时候发生了”。判断一个itemid该去chartevents还是datetimeevents查官方设计里是通过d_items表的linksto字段来区分的。3.3 inputevents和outputevents液体出入量怎么算inputevents记录ICU期间的液体输入包括静脉输液、肠内营养、血液制品等。它除了starttime和endtime之外有amount和amountuom表示总量和单位还有rate和rateuom表示输入速率。outputevents记录液体输出主要就是尿量、引流、呕吐物等字段结构相对简单也带amount单位。这两张表是液体平衡研究的关键。做液体复苏、AKI相关研究时通常要把输入和输出按小时汇总再相减得到净液体平衡。计算时最常踩的坑是单位混着用inputevents里大部分补液数据单位是ml但血管活性药物比如去甲肾上腺素可能以mcg/kg/min记录甚至有些泵入液体以ml/h记录。筛选时必须根据itemid把药物类和补液类分开否则汇总出来的“总输入量”会失真。3.4 procedureeventsICU里做了什么操作procedureevents记录ICU内的操作类事件比如CRRT、气管插管、经皮气管切开等。它和inputevents结构有些类似有starttime、endtime、value、valueuom等字段。做操作相关研究时要记住这里的“操作”是ICU内实时记录的操作和Hosp模块里的procedures_icd不是一个概念后者是出院时按编码规则统一整理的。举一个常见混淆场景研究“机械通气患者”时有人去查词库里有没有“ventilation”结果发现查不到满意结果。因为机械通气时长通常结合chartevents里的呼吸机参数比如itemid对应“Vent Mode”或“Respiratory Rate或者从procedureevents里找插管操作来推断。理解两张表的分工后这类问题就能快速定位。3.5 d_items连接所有itemid的钥匙d_items表放在ICU模块的字典表里但它实际上覆盖了chartevents、datetimeevents、inputevents、outputevents、procedureevents里所有itemid的翻译。字段包括itemid、label、category、unitname、linksto等。linksto字段非常关键它告诉你这个itemid对应的事件会落到哪张表。比如我想找“心率”可以先在d_items里过滤label like %Heart Rate%然后看linksto指向chartevents再去chartevents里查具体数据。反过来当你不确定某个指标去哪张表时也可以先到d_items里反查。表名主键核心内容常用字段icustaysstay_idICU入住记录intime, outtime, first_careunitcharteventschartevent_id生命体征与参数itemid, charttime, value, valuenumdatetimeeventsdatetimeevent_id时间点事件itemid, charttimeinputeventsinputevent_id液体输入amount, amountuom, rateoutputeventsoutputevent_id液体输出amount, amountuomprocedureeventsprocedureevent_idICU内操作starttime, endtime, valued_itemsitemid所有事件项目字典label, category, unitname, linksto4. 两个模块配合使用的核心场景接触一段时间后你会发现MIMIC真正难的不是单张表而是把不同模块的表串起来。这里分享三个我实际跑过的场景每一步都能看出Hosp和ICU是怎么协作的。4.1 场景一筛选特定人群并提取入ICU早期特征最经典的研究路径是先限定人群再提取特征。比如要看“感染性休克患者入ICU后24小时内的乳酸变化”。实现时先用diagnoses_icd锁定感染性休克相关的ICD编码join到admissions拿住院信息再通过icustays转成ICU入住记录最后从labevents或者chartevents里查乳酸值。示意查询如下SELECT icu.stay_id, pat.subject_id, adm.admittime, icu.intime, CASE WHEN adm.hospital_expire_flag 1 THEN 1 ELSE 0 END AS hosp_mortality FROM icustays icu LEFT JOIN admissions adm ON icu.hadm_id adm.hadm_id LEFT JOIN patients pat ON icu.subject_id pat.subject_id LEFT JOIN diagnoses_icd diag ON icu.hadm_id diag.hadm_id WHERE diag.icd_version 10 AND diag.icd_code LIKE R65.21%这个查询的核心思路是用subject_id保持在患者维度用hadm_id关联到住院维度用stay_id切到ICU维度。很多人容易漏掉的是诊断表里同一个hadm_id有多条记录所以筛人群时建议先对diagnoses_icd做去重或者限定seq_num避免同一个患者因为多条诊断被重复计数。4.2 场景二按小时汇总液体平衡液体平衡分析的SQL思路并不复杂但坑在单位。基本流程是先限定stay_id然后分别把inputevents和outputevents按时间窗口汇总再相减。SELECT stay_id, date_trunc(hour, starttime) AS hour_ts, SUM(amount) AS total_in FROM inputevents WHERE amountuom ml AND itemid NOT IN (...) GROUP BY stay_id, date_trunc(hour, starttime)这里有两个容易踩的细节第一inputevents里并不是所有行都是ml单位血管活性药、胰岛素泵通常是按mcg/kg/min或units/hr记录的筛选时要先通过d_items确认类别第二如果研究只看“补液量”要排除掉口服药、冲洗液这类非治疗性液体否则净液体平衡会偏差很大。对于outputevents最简单的方法是直接按amountuomml汇总尿量但要注意引流液是否计入总出量取决于研究问题。4.3 场景三把ICU事件与院内结局拼接很多研究需要的结局变量并不在ICU模块里比如院内死亡、30天再入院这些数据在Hosp模块的admissions或者patients里。拼接时要用hadm_id把ICU记录和住院记录关联起来。还有一个容易忽略的点如果患者死亡发生在ICU内那么admissions.hospital_expire_flag为1但死亡时间有可能和icustays.outtime不一致。判断“ICU内死亡”时建议用patients.dod与icustays.outtime比较或者直接看是否存在outtime与dod非常接近的记录。研究定义要写清楚否则后续结果容易受到不同定义的影响。5. 新手最常踩的坑与排查技巧这一节是实操中大家问得最多的问题汇总我按踩坑频率排个序。5.1 itemid直接拿来用不查字典表这是最常见的错误。很多人第一次在chartevents里看到itemid220045听群里说这是心率就直接where itemid220045往下跑。如果数据库版本没换可能侥幸能用一旦换到3.0或3.1某些itemid可能已经调整结果就全错了。更稳妥的方法是每次写SQL前都先查d_items确认label、category和linksto。别看这一步浪费时间它能帮你省下后面无数返工的麻烦。5.2 时间字段的时区、精度和空值MIMIC的时间字段比如admittime、intime、charttime官方按医院本地时间存储没有时区偏移。所以在SQL里直接比较即可不需要额外做时区转换。精度上admissions的时间精确到分钟ICU事件表精确到秒甚至更细做时间窗口匹配时要注意格式化一致性。空值也要留意。labevents里有相当一部分行的charttime为空但storetime不为空如果研究要求采样时间需要先排查空值比例。procedures_icd里的icd_code在某些老数据下可能为空最好做版本升级或转码检查。5.3 value、valuenum、valueuom如何取舍这三兄弟每张事件表里都有选择原则其实统一数值型分析用valuenum并限定valueuom文本型指标只能看value。举例说明。场景推荐写法原因统计乳酸最高值WHERE valuenum IS NOT NULL AND itemid...只有数值才能max/min看尿色描述SELECT value FROM labevents WHERE ...文本型结果无valuenum判断是否使用某药WHERE itemid IN (SELECT itemid FROM d_items WHERE label LIKE ...)适合先确认itemid集合按单位过滤WHERE valueuom mmHg防止单位混用5.4 数据量级大查询效率要控制chartevents是上亿行级别的表labevents也是千万行级。无脑select *或者缺少过滤条件会导致云端数据库配额瞬间耗尽。建议先加WHERE限定stay_id、itemid、时间范围再考虑是否需要全部字段。如果只是探索性分析可以先跑LIMIT 100看看数据结构。用BigQuery的话还可以在预览面板里直接看前几行减少不必要的全表扫描。5.5 字段语义快速对照表最后给一张常用字段对照表方便写SQL时快速查阅。字段名含义出现模块subject_id患者唯一标识core/hosp/icuhadm_id住院唯一标识core/hosp/icustay_idICU入住唯一标识icuitemid事件或检验项目编码hosp/icucharttime事件发生时间hosp/icustoretime数据入库时间hosp/icuvalue原始结果值字符串hosp/icuvaluenum数值型结果hosp/icuvalueuom单位hosp/icuseq_num编码排序号hosphospital_expire_flag院内死亡标识core拿数据后建议第一时间把这张表存下来写SQL时对照字段含义能少犯很多低级错误。我个人经验是先把数据导入本地数据库比如PostgreSQL或者DuckDB然后用一段简单的元数据查询把每个表的字段都过一遍建立自己的速查笔记。前期花这一两个小时后面整个研究阶段都能受益。
返回列表