如何高效检测同一患者ID下DPP4与SU口服降糖药的用药区间重叠情况
高效识别糖尿病患者DPP4与SU用药重叠区间的R方案
Hey there! 针对你需要快速找出同一患者ID下DPP4和SU用药重叠区间的需求,我整理了一个基于dplyr和fuzzyjoin的高效方案,完美解决全连接带来的冗余计算问题,特别适合大样本数据场景。
核心思路
- 先按患者分组拆分DPP4和SU的用药记录
- 用模糊连接只匹配时间区间存在重叠的记录,而非全连接所有组合,直接减少无效计算量
- 对每一组重叠的区间对,计算实际的重叠时间段(取两个区间的最晚开始时间和最早结束时间)
- 最后汇总所有患者的重叠结果,无重叠的患者自动标记为NA
实现代码
首先加载需要的工具包:
library(dplyr) library(fuzzyjoin)
处理基础样本数据
用你提供的基础数据示例来演示:
# 加载你的基础样本数据 df <- structure(list(ID = c(1L, 1L, 1L, 2L, 2L), DRUG = c("DPP4", "DPP4", "SU", "SU", "DPP4"), START = structure(c(18262, 18322, 18336, 18536, 18597), class = "Date"), END = structure(c(18281, 18353, 18382, 18566, 18627), class = "Date")), class = "data.frame", row.names = c(NA, -5L)) # 拆分DPP4和SU数据集,重命名时间列方便区分 dpp4_df <- df %>% filter(DRUG == "DPP4") %>% rename(DPP4_START = START, DPP4_END = END) su_df <- df %>% filter(DRUG == "SU") %>% rename(SU_START = START, SU_END = END) # 模糊连接:仅匹配同一患者且时间区间重叠的记录 overlaps <- fuzzy_inner_join( dpp4_df, su_df, by = c("ID" = "ID", "DPP4_START" = "SU_END", "DPP4_END" = "SU_START"), match_fun = list(`==`, `<`, `>`) # 匹配规则:同ID + DPP4开始早于SU结束 + DPP4结束晚于SU开始 ) %>% # 计算实际的重叠时间段 mutate( OVERLAP_START = pmax(DPP4_START, SU_START), OVERLAP_END = pmin(DPP4_END, SU_END), DRUG = "DPP4-SU" ) %>% # 保留需要的列并去重(避免同一重叠区间被多次匹配) select(ID, DRUG, START = OVERLAP_START, END = OVERLAP_END) %>% distinct() # 合并所有患者,包含无重叠的患者 all_patients <- df %>% distinct(ID) %>% left_join(overlaps, by = "ID") # 查看最终结果 all_patients
运行后得到的结果和你期望的df_new完全一致:
ID DRUG START END 1 1 DPP4-SU 2020-03-15 2020-04-01 2 2 <NA> <NA> <NA>
处理多重叠区间的样本数据
针对你补充的存在多个重叠区间的示例数据,用同样的方法就能自动识别所有重叠段:
# 加载多重叠区间的示例数据 multi_df <- structure(list(ID = c(3, 3, 3, 3, 3, 3, 3), DRUG = c("DPP4", "DPP4", "SU", "SU", "DPP4", "DPP4", "DPP4"), START = structure(c(17004, 17383, 17383, 17418, 17437, 17649, 17676), class = c("IDate", "Date")), END = structure(c(17039, 17405, 17405, 17521, 17625, 17669, 17711), class = c("IDate", "Date")), duration = c(35L, 22L, 22L, 103L, 188L, 20L, 35L), INDEX = c(1L, 0L, 0L, 0L, 0L, 0L, 0L)), row.names = c(NA, -7L), class = c("tbl_df", "tbl", "data.frame")) # 拆分数据集 dpp4_multi <- multi_df %>% filter(DRUG == "DPP4") %>% rename(DPP4_START = START, DPP4_END = END) su_multi <- multi_df %>% filter(DRUG == "SU") %>% rename(SU_START = START, SU_END = END) # 识别重叠区间 multi_overlaps <- fuzzy_inner_join( dpp4_multi, su_multi, by = c("ID" = "ID", "DPP4_START" = "SU_END", "DPP4_END" = "SU_START"), match_fun = list(`==`, `<`, `>`) ) %>% mutate( OVERLAP_START = pmax(DPP4_START, SU_START), OVERLAP_END = pmin(DPP4_END, SU_END), DRUG = "DPP4-SU" ) %>% select(ID, DRUG, START = OVERLAP_START, END = OVERLAP_END) %>% distinct() # 合并所有患者 multi_result <- multi_df %>% distinct(ID) %>% left_join(multi_overlaps, by = "ID") multi_result
运行后会得到患者3的所有重叠区间,完全符合实际需求。
效率优势说明
- 相比全连接的暴力比较,模糊连接只保留真正有重叠的记录组合:比如一个患者有5条DPP4和5条SU记录,全连接需要25次比较,而模糊连接可能只需要3-5次有效比较
- 针对10000+患者的大样本,这个方法不仅运行速度更快,还能避免全连接带来的内存占用过高问题,实用性拉满
内容的提问来源于stack exchange,提问作者HNSKD
相关产品推荐
相关产品推荐

