基于长格式诊疗episode数据构建带日期的二元变量及多病共存分析
问题描述
我正在处理一份包含数十万人、约15年住院episode的临床数据表,表中每行对应一个episode,包含以下字段:
- episode编号
- episode日期(日期与episode编号未按时间顺序排列)
- 56种目标诊断的二元指标(1表示该episode存在对应诊断,0表示不存在)
可复现的R语言示例数据如下:
df <- data.frame( id = c("1001", "1001", "1001", "1001", "1001", "1001", "1002", "1002", "1002", "1002", "1002", "1003", "1003", "1003", "1003", "1003", "1003", "1003", "1005", "1005", "1005", "1005", "1005", "1005", "1005", "1005", "1005"), episode = c(0, 1, 2, 3, 4, 5, 0, 1, 3, 4, 5, 0, 2, 3, 6, 7, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9), date = sample(seq(as.Date('2010/01/01'), as.Date('2016/01/01'), by="day"), 27), diag_a = c(1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0), diag_b = c(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), diag_c = c(1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0), diag_d = c(1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0) )
需要实现以下需求:
- 识别每个ID是否出现过56种诊断中的任意一种,并提取每种诊断的最早确诊日期;
- 创建
multimorbidity二元列(0/1),标记参与者是否存在2种及以上目标诊断,并生成首次达到多病共存的日期(即第二种目标诊断出现的日期,可能在同一episode内); - 为每个ID统计出现的目标诊断数量,生成
condition_count列。
核心需求是获取每个ID的多病共存状态及首次发生日期,用于后续回归分析。
解决方案
使用tidyverse工具链处理,代码逻辑清晰且适合大规模数据:
首先加载依赖包:
library(tidyverse)
步骤1:提取各诊断最早日期及是否有任一诊断
先把宽格式的诊断列转成长格式,筛选出有诊断的记录,按ID和诊断分组取最早日期,再转回宽格式,最后标记是否存在至少一种诊断:
diagnosis_dates <- df %>% pivot_longer(cols = starts_with("diag_"), names_to = "diagnosis", values_to = "present") %>% filter(present == 1) %>% group_by(id, diagnosis) %>% summarise(first_diagnosis_date = min(date), .groups = "drop") %>% pivot_wider(id_cols = id, names_from = diagnosis, values_from = first_diagnosis_date) %>% mutate(any_diagnosis = if_else(rowSums(!is.na(select(., starts_with("diag_")))) > 0, 1, 0))
步骤2&3:计算诊断数量、多病共存状态及首次日期
先按ID和日期排序(确保时间顺序正确),然后逐行累计每个ID已出现的诊断种类,找到首次达到2种的日期;再统计每个ID的总诊断数,最后合并并补全缺失值:
multimorbidity_data <- df %>% arrange(id, date) %>% group_by(id) %>% # 计算截至当前行的累计诊断种类数 mutate( cumulative_conditions = pmap_int(seq(n()), function(i) { slice(cur_data(), 1:i) %>% select(starts_with("diag_")) %>% summarise(across(everything(), max)) %>% # 取每个诊断是否在之前出现过 pivot_longer(everything()) %>% filter(value == 1) %>% nrow() }) ) %>% # 筛选首次达到2种及以上诊断的记录 filter(cumulative_conditions >= 2) %>% slice(1) %>% select(id, first_multimorbidity_date = date) %>% # 合并总诊断数量数据 left_join( df %>% pivot_longer(cols = starts_with("diag_"), names_to = "diagnosis", values_to = "present") %>% filter(present == 1) %>% distinct(id, diagnosis) %>% group_by(id) %>% summarise(condition_count = n(), .groups = "drop"), by = "id" ) %>% # 标记多病共存状态 mutate(multimorbidity = if_else(condition_count >= 2, 1, 0)) %>% # 补全没有诊断或只有1种诊断的ID的缺失值 right_join(distinct(df, id), by = "id") %>% mutate( condition_count = replace_na(condition_count, 0), multimorbidity = replace_na(multimorbidity, 0), first_multimorbidity_date = replace_na(first_multimorbidity_date, NA_Date_) )
合并所有结果
把步骤1和步骤2的结果合并,得到最终的ID级汇总表:
final_result <- diagnosis_dates %>% full_join(multimorbidity_data, by = "id") # 查看结果 print(final_result)
这个方案能高效处理大规模数据,所有操作都是向量化或分组操作,避免循环;同时准确处理了同一episode出现多种诊断的情况(累计数会直接统计为对应数量,首次日期取该episode的日期)。
内容的提问来源于stack exchange,提问作者L.Steell
相关产品推荐
相关产品推荐

