从MIMIC学习组织自己的数据
相对于SEER数据库(我们得到的是几乎可以直接进行分析的数据),MIMIC 数据库在数据采集后虽然经过了一定的处理,但是保留了数据库原始的样貌,所以我们除了对MIMIC数据进行分析外,还可以从MIMIC数据库中学习怎样设计数据库,怎样组织数据,用在我们构建自己的数据库的过程中。
存储数据的组织形式:星状设计、长表和宽表
- MIMIC数据库属于关系型数据库,是星状结构(star schema)设计,MIMIC数据库中admission 表格是核心,是中心表格,包含了可供分析的信息,其余表格为附属表格,包含的信息是对主表格信息的注释、分类和描述,可以用来分组、过滤主表格信息。主附表格通过共同的ID将相关得数据联系在一起。
-
- 这是我们可以借鉴的信息。我们可以将数据库设计为星状结构,来组织我们的数据。
- 查询:使用SQL的join命令将分散在多个表格中的相关的数据拼接在一起,其中的一种变化是with临时表形成过渡表格,对某一个表格中的数据进行初步的处理,然后在主查询中对数据进行二次处理(用join语句拼接)。以MIMIC数据库为例,假设我们想要查询每个住院患者的年龄、性别、入院类型、入院诊断和死亡时间(如果有的话)。我们需要从多个表格中获取这些数据,如patients, admissions, icustays等。我们可以用以下SQL语句来实现:
--创建一个临时表格,计算每个患者的年龄
with age as (
select
p.subject_id,
p.gender,
a.hadm_id,
a.admittime,
a.dischtime,
a.deathtime,
a.admission_type,
a.diagnosis,
-- 计算年龄
round((cast(a.admittime as date) - cast(p.dob as date))/365.242, 2) as age
from patients p
inner join admissions a
on p.subject_id = a.subject_id
)
-- 主查询,使用join语句拼接临时表格和其他表格
select
a.subject_id,
a.gender,
a.hadm_id,
a.admittime,
a.dischtime,
a.deathtime,
a.admission_type,
a.diagnosis,
-- 处理年龄异常值
case
when a.age > 89 then '>89'
else cast(a.age as varchar)
end as age,
i.first_careunit as icu
from age a
left join icustays i
on a.hadm_id = i.hadm_id
order by a.subject_id, a.hadm_id;
-
有的表属于纵向结构,代表记录条目的ID列是有重复的。每个表格内的变量的组织也是有主有次,往往有且只有一个变量是核心变量,其他是都是符号关键变量的注释或者解释,这种结构组织的数据,便于录入,但是不便于分析。有些临床数据可以使用这种形式来进行组织。比如MIMIC数据库中有多个长表格,例如:
- chartevents: 包含患者在ICU期间的各种生理测量和护理记录
- labevents: 包含患者在住院期间的各种实验室检查结果
- microbiologyevents: 包含患者在住院期间的各种微生物检查结果
- outputevents: 包含患者在ICU期间的各种出液记录
- inputevents_cv: 包含使用CareVue系统的患者在ICU期间的各种入液记录
- inputevents_mv: 包含使用MetaVision系统的患者在ICU期间的各种入液记录
- procedureevents_mv: 包含使用MetaVision系统的患者在ICU期间的各种操作记录
- 如何查询,需要将多条变量变成一条变量,通过取mean,max等。以MIMIC数据库为例,假设我们想要从chartevents表中提取以下信息:每个患者在ICU期间的平均心率(心率的item_id为211);每个患者在ICU期间的平均血压(血压的item_id为220045);每个患者在ICU期间的平均体温(体温的item_id为223761);每个患者的性别(性别在patients表中).我们可以用以下SQL语句来实现:
-- 创建一个临时表格,筛选出心率、血压和体温的数据
with vital_signs as (
select
subject_id,
itemid,
valuenum
from chartevents
where itemid in (211, 220045, 223761)
)
-- 主查询,使用join语句连接临时表格和patients表,使用aggregate函数计算平均值
select
v.subject_id,
p.gender,
-- 计算平均心率
avg(case when v.itemid = 211 then v.valuenum else null end) as avg_hr,
-- 计算平均血压
avg(case when v.itemid = 220045 then v.valuenum else null end) as avg_bp,
-- 计算平均体温
avg(case when v.itemid = 223761 then v.valuenum else null end) as avg_temp
from vital_signs v
inner join patients p
on v.subject_id = p.subject_id
group by v.subject_id, p.gender
order by v.subject_id;
- 有的表属于宽表,代表记录条目的ID列是唯一的,也是我们组织自己数据的一种形式。从宽表格中提取数据相对简单。MIMIC数据库中的宽表格有以下几个:admissions: 包含了每个患者的入院信息,如入院时间、出院时间、入院类型、死亡标志等;patients: 包含了每个患者的基本信息,如性别、出生日期、死亡日期等;transfers: 包含了每个患者在医院内部的转移信息,如转移时间、转移前后的位置、转移类型等;icustays: 包含了每个患者在重症监护病房的停留信息,如停留时间、停留时长、停留位置等;services: 包含了每个患者在重症监护病房的服务信息,如服务类型、服务开始时间、服务结束时间等;prescriptions: 包含了每个患者在重症监护病房的药物处方信息,如药物名称、药物剂量、药物开始时间、药物结束时间等。以MIMIC数据库为例,假设我们想要从admissions表中提取以下信息:每个患者的入院次数;每个患者的平均住院天数;每个患者的死亡率;我们可以用以下SQL语句来实现:
-- 主查询,使用aggregate函数计算入院次数、平均住院天数和死亡率
select
subject_id,
-- 计算入院次数
count(*) as admission_count,
-- 计算平均住院天数
avg(datediff(day, admittime, dischtime)) as avg_los,
-- 计算死亡率
sum(case when hospital_expire_flag = 1 then 1 else 0 end) * 1.0 / count(*) as mortality_rate
from admissions
group by subject_id
order by subject_id;