使用dplyr实现跨两个数据框的主体级日期范围过滤(避免连接)
基于日期范围过滤大体积Target数据框
需求
根据Reference数据框中每个ParticipantId对应的DateA值,过滤Target数据框中满足DateA落在Date1与Date2区间内的行。由于Target数据量极大无法全量加载到内存,要求使用dplyr管道实现,优先避免表连接操作。
示例数据
原始Target数据
| ParticipantId | Date1 | Date2 |
|---|---|---|
| 10001 | 1/02/2010 | 1/02/2015 |
| 10001 | 3/02/2016 | 1/02/2018 |
| 10001 | 1/02/2019 | 1/02/2020 |
| 10001 | 1/02/2021 | 1/02/2023 |
| 10002 | 1/02/2016 | 1/02/2018 |
| 10002 | 1/02/2019 | 1/02/2020 |
| 10002 | 1/02/2021 | 1/02/2023 |
| 10003 | 1/02/2013 | 1/02/2020 |
| 10003 | 1/02/2021 | 1/02/2023 |
Reference数据
| ParticipantId | DateA |
|---|---|
| 10001 | 3/12/2013 |
| 10002 | 5/15/2022 |
| 10003 | 9/20/2022 |
期望过滤结果
| ParticipantId | Date1 | Date2 |
|---|---|---|
| 10001 | 1/02/2010 | 1/02/2015 |
| 10002 | 1/02/2021 | 1/02/2023 |
| 10003 | 1/02/2021 | 1/02/2023 |
数据初始化代码(需加载lubridate库)
library(lubridate) library(dplyr) Reference <- structure( list( ParticipantId = 10001:10003, DateA = c("3/12/2013", "5/15/2022", "9/20/2022") ), class = "data.frame", row.names = c(NA, -3L) ) Target <- structure( list( ParticipantId = c( 10001L, 10001L, 10001L, 10001L, 10002L, 10002L, 10002L, 10003L, 10003L ), Date1 = c( "1/2/2010", "1/2/2016", "1/2/2019", "1/2/2021", "1/2/2016", "1/2/2019", "1/2/2021", "1/2/2019", "1/2/2021" ), Date2 = c( "1/2/2015", "1/2/2018", "1/2/2020", "1/2/2023", "1/2/2018", "1/2/2020", "1/2/2023", "1/2/2020", "1/2/2023" ) ), class = "data.frame" )
解决方案代码
核心思路:将Reference转换为以ParticipantId为名称的日期向量,对Target按ParticipantId分组后,在每组内匹配对应的DateA并做区间判断。该方式无需表连接,适配大体积数据(若Target为数据库连接或分块数据,dplyr可自动兼容)。
# 预处理Reference:转换日期格式并转为命名向量 ref_date_vec <- Reference %>% mutate(DateA = mdy(DateA)) %>% tibble::deframe() # 过滤Target数据 filtered_target <- Target %>% # 转换日期列格式 mutate( Date1 = mdy(Date1), Date2 = mdy(Date2) ) %>% # 按ParticipantId分组 group_by(ParticipantId) %>% # 过滤:当前组的DateA落在Date1和Date2之间的行 filter(between(ref_date_vec[[as.character(cur_group()$ParticipantId)]], Date1, Date2)) %>% ungroup() %>% # 转换回原始日期字符串格式(可选,按需保留) mutate( Date1 = format(Date1, "%m/%d/%Y"), Date2 = format(Date2, "%m/%d/%Y") ) # 查看结果 print(filtered_target)
运行结果
# A tibble: 3 × 3 ParticipantId Date1 Date2 <int> <chr> <chr> 1 10001 01/02/2010 01/02/2015 2 10002 01/02/2021 01/02/2023 3 10003 01/02/2021 01/02/2023
内容的提问来源于stack exchange,提问作者TDeramus
相关产品推荐
相关产品推荐

