3. EHR数据基础与工程视角
电子健康记录(EHR)是基因组数据融合工程中最主要的临床表型来源。要把基因型与临床表型对齐,第一步不是写代码,而是理解EHR里到底有哪些实体、它们如何被标识、如何被编码,以及这些编码在工程上会带来哪些约束。本节从数据模型、术语体系和工程约束三个层面展开。
一、EHR的核心数据模型:以患者为中心的实体关系
无论底层是关系型数据库、FHIR资源还是OMOP CDM,EHR的语义骨架基本一致:患者(Patient)是中心实体,围绕它展开就诊(Encounter),就诊之下挂载诊断(Condition/Diagnosis)、用药(Medication)、检验(Lab/Observation)和生命体征(Vital Signs)。理解这个层级关系,是后续做数据抽取、时间对齐和表型定义的基础。
关键点在于:患者标识通常不是单一字段。一个患者可能同时拥有院内病案号(MRN)、身份证号、医保号、以及跨机构的主索引(EMPI)ID。工程上必须明确哪一个是“主键”,哪些是“外部映射”,否则在跨系统关联时会出现一人多号或一号多人的问题。
就诊是临床事件的时间容器。一次住院、一次门诊、一次急诊都对应一个Encounter,带有入院时间、出院时间、科室、医生等属性。诊断、用药、检验都发生在某次就诊内,因此就诊ID是连接临床事件的时间锚点。
诊断记录疾病状态,通常用ICD编码表示;用药记录药物暴露,用RxNorm或ATC编码;检验记录实验室结果,用LOINC编码标识检验项目;生命体征如血压、体温、心率,通常也归入Observation类,但往往有独立的采集频率和单位约定。
二、术语体系:ICD、LOINC、RxNorm的定位与差异
EHR中的临床概念几乎都以编码形式存储,而不是自由文本。三种最常用的术语体系各有明确分工:
- ICD(国际疾病分类):用于诊断和手术操作编码。ICD-10-CM有约7万条诊断码,ICD-9-CM约1.4万条。工程上最需要注意的是版本切换——同一疾病在ICD-9和ICD-10中编码完全不同,跨版本队列必须做映射表。
- LOINC(观测指标标识符逻辑命名与编码):用于检验项目和生命体征。LOINC码描述的是“测什么”,而不是“结果是什么”。例如“血肌酐”有独立的LOINC码,但结果值需要结合单位(mg/dL或μmol/L)才能解释。
- RxNorm:用于临床药物。它提供从成分(Ingredient)到临床药品(Clinical Drug)的多层级粒度。工程上常见的问题是:处方记录可能只写了商品名,需要先归一化到RxNorm的Ingredient层,才能做跨机构的药物暴露分析。
三者的共同工程约束是:编码不是一对一的。一个本地检验项目可能映射到多个LOINC码,一个ICD-10码可能对应多个SNOMED CT概念。因此,术语映射必须保留映射来源、映射方向和置信度,不能简单做字符串替换。
三、工程视角下的关键约束
从工程实现角度看,EHR数据有四个必须提前处理的约束:
- 时间戳的粒度与一致性:就诊有入院/出院时间,检验有采样时间和报告时间,用药有开始/结束时间。基因组数据融合时,必须明确用哪个时间做对齐——是诊断时间、用药开始时间,还是检验采样时间。不同选择会直接改变表型定义的结果。
- 缺失值的语义:EHR中的空值可能表示“未测量”“未记录”“不适用”或“患者拒绝”。工程上不能统一当作NULL处理,否则会引入系统性偏差。
- 单位与参考范围:检验结果必须带单位。同一项目在不同实验室可能使用不同单位,LOINC码相同但单位不同时,需要做单位换算后再比较。
- 编码版本与本地扩展:医院常使用本地扩展码补充标准术语的不足。这些扩展码在跨机构交换时无法直接解释,必须附带映射说明。
四、一个可参考的抽取示例
假设我们要从EHR中抽取“2型糖尿病患者”的队列,并关联其用药和检验数据。一个合理的工程流程是:
-- 示例:基于ICD-10的诊断筛选(示意SQL,非实测)
SELECT p.patient_id, e.encounter_id, d.icd_code, d.diagnosis_time
FROM patient p
JOIN encounter e ON p.patient_id = e.patient_id
JOIN diagnosis d ON e.encounter_id = d.encounter_id
WHERE d.icd_code LIKE 'E11%' -- ICD-10-CM 2型糖尿病
AND d.diagnosis_time BETWEEN '2020-01-01' AND '2023-12-31';
-- 关联用药:RxNorm Ingredient层
SELECT m.patient_id, m.rxnorm_ingredient, m.start_date, m.end_date
FROM medication m
WHERE m.rxnorm_ingredient IN ('860975', '860974') -- 二甲双胍相关
AND m.start_date >= '2020-01-01';
-- 关联检验:LOINC码 + 单位
SELECT l.patient_id, l.loinc_code, l.result_value, l.unit, l.specimen_time
FROM lab l
WHERE l.loinc_code = '4548-4' -- 糖化血红蛋白HbA1c
AND l.unit = '%'
AND l.specimen_time >= '2020-01-01';
这个示例的关键点不在于SQL本身,而在于每一步都显式处理了术语编码、时间范围和单位。实际工程中,还需要处理同一患者多次就诊的去重、同一检验多次结果的取值策略(首次、末次、均值或极值),以及用药记录的剂量归一化。
理解EHR的数据模型和术语体系,本质上是在为后续的基因组-临床关联建立“语义对齐”的基础。只有把患者标识、就诊时间、诊断编码、药物编码和检验编码都处理清楚,才能保证基因型与表型的关联分析不会因为数据层面的歧义而失效。