在R中从不同数据框提取符合日期范围条件的匹配ID列表
R语言基于日期范围的病例匹配解决方案
先修正示例代码的变量错误
原示例中FirstDtA和LastDtA引用了未定义的AdmissionDt,需改为AdmissionDtA:
IDA <- c(1:40) AdmissionDtA <- seq(as.Date("2014-01-01"), as.Date("2014-02-09"), by="days") FirstDtA <- AdmissionDtA - 2 LastDtA <- AdmissionDtA + 7 df.A <- data.frame(IDA, AdmissionDtA, FirstDtA, LastDtA) IDB <- c(41:80) AdmissionDtB <- seq(as.Date("2014-01-16"), as.Date("2014-02-24"), by="days") df.B <- data.frame(IDB, AdmissionDtB)
方案一:data.table高效非等连接(推荐大数据量场景)
data.table的非等连接能高效处理40万级别的数据,避免低效循环:
library(data.table) # 转换为data.table格式(提升处理速度) setDT(df.A) setDT(df.B) # 执行非等连接,筛选AdmissionDtB落在[FirstDtA, LastDtA]范围内的匹配对 matches <- df.A[df.B, on = .(FirstDtA <= AdmissionDtB, LastDtA >= AdmissionDtB), .(IDA, IDB), nomatch = 0] # 按IDA分组,将匹配的IDB合并为列表 match_groups <- matches[, .(MatchingIDB = list(IDB)), by = IDA] # 左连接回原数据框,为无匹配的行填充"no match" df.A <- df.A[match_groups, on = .(IDA)] df.A[is.na(MatchingIDB), MatchingIDB := list("no match")] # 查看结果示例 head(df.A)
方案二:dplyr + fuzzyjoin(易读性优先,适合tidyverse新手)
如果更熟悉tidyverse语法,可用fuzzyjoin实现直观的范围匹配:
library(dplyr) library(fuzzyjoin) # 模糊左连接,按日期范围匹配 df.A_matched <- df.A %>% fuzzy_left_join(df.B, by = c("FirstDtA" = "AdmissionDtB", "LastDtA" = "AdmissionDtB"), match_fun = list(`<=`, `>=`)) %>% group_by(IDA, AdmissionDtA, FirstDtA, LastDtA) %>% summarise( MatchingIDB = ifelse(all(is.na(IDB)), "no match", list(IDB[!is.na(IDB)])), .groups = "drop" ) # 查看结果示例 head(df.A_matched)
注意事项
- 确保所有日期列都是
Date类型,避免字符型导致匹配失效 - 若需要将匹配ID转为逗号分隔的字符串,可将
list(IDB)替换为paste(IDB, collapse = ", ") - 大数据量下优先选择data.table方案,效率显著高于dplyr+fuzzyjoin
内容的提问来源于stack exchange,提问作者Rnoob
相关产品推荐
相关产品推荐

