R语言按个体ID对应事件日期区间筛选随访记录的实现问题
问题解答
现有逻辑说明
你观察到的「ID为5的个体1988年12月15日的随访被匹配到2019年9月3日的事件,之后被过滤」是同ID多对多关联的正常表现:同一个体的每一条随访会和该个体的所有事件逐一匹配生成多行,过滤步骤仅会删除不满足对应事件时间区间的行。只要该随访落在任意一个事件的2年观测窗口内,就会有对应的匹配行被保留,不会出现有效记录被误删的问题。
如果你的需求是每个随访仅保留一条记录,可以在过滤后按visit_id去重即可,避免同一条随访落在多个事件窗口时出现重复行。
更高效的实现方案
你原有的先全量关联再过滤的方案,在随访数据量极大时会生成非常多的无效中间匹配行,占用过多内存、运行效率低。可以直接使用非等值连接在关联阶段就完成时间区间的筛选,大幅提升性能:
方案1:dplyr 1.1.0+ 原生非等值连接
library(dplyr) library(lubridate) # 先给事件表生成观测窗口终点 event_data_total <- event_data_total %>% mutate(event_end_date = event_date %m+% years(2)) # 关联时直接匹配ID和时间区间,无需后续过滤 data_joined_final <- inner_join( visit_data, event_data_total, join_by( visit_person_id == event_person_id, visit_date >= event_date, visit_date <= event_end_date ) ) # 若需要每个随访仅保留一条,加去重步骤即可 # data_joined_final <- distinct(data_joined_final, visit_id, .keep_all = TRUE)
方案2:超大数据量用data.table实现
如果随访记录量级达到十万以上,data.table的性能远高于dplyr:
library(data.table) library(lubridate) # 转换为data.table格式 setDT(event_data_total) setDT(visit_data) # 生成观测窗口终点 event_data_total[, event_end_date := event_date %m+% years(2)] # 非等值连接,nomatch=NULL等价于inner join data_joined_final <- event_data_total[visit_data, on = .(event_person_id = visit_person_id, event_date <= visit_date, event_end_date >= visit_date), nomatch = NULL ] # 去重(可选) # data_joined_final <- unique(data_joined_final, by = "visit_id")
内容的提问来源于stack exchange,提问作者MDStat
相关产品推荐
相关产品推荐

