You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 08:56:05