Base R或dplyr如何实现ID匹配+日期区间匹配的merge合并?
R实现按id匹配+日期间隔条件的连接方法
前提说明
你有如下两个因子类型日期的数据表:
table_1 = data.frame(id = c("123", "123", "125", "125"), date_1 = c("2010-01-31","2010-01-31", "2015-01-31", "2018-01-31" )) table_1$id = as.factor(table_1$id) table_1$date_1 = as.factor(table_1$date_1) table_2 = data.frame(id = c("123", "121", "125", "126"), date_2 = c("2009-01-31","2010-01-31", "2010-01-31", "2010-01-31" ), date_3 = c("2011-01-31","2010-01-31", "2020-01-31", "2020-01-31" )) table_2$id = as.factor(table_2$id) table_2$date_2 = as.factor(table_2$date_2) table_2$date_3 = as.factor(table_2$date_3)
需要满足的匹配条件:
- table_1$id = table_2$id
- table_1$date_1介于table_2$date_2和table_2$date_3之间
1. Base R实现
完全可以用Base R实现,逻辑是先按id做匹配生成同id的所有行组合,再筛选符合日期间隔的行即可。由于你的日期是YYYY-MM-DD格式的因子,字符串排序逻辑和日期排序逻辑一致,直接比较大小即可。
# 左连接:保留table_1的所有行,匹配table_2符合条件的行,要内连接去掉all.x参数即可 merge_temp <- merge(table_1, table_2, by = "id", all.x = TRUE) # 筛选符合日期间隔条件的记录 final_base <- merge_temp[merge_temp$date_1 >= merge_temp$date_2 & merge_temp$date_1 <= merge_temp$date_3, ] # 可选去重:按id+date_1去重,避免相同id不同日期的记录被误删 final_base_no_dup <- final_base[!duplicated(final_base[, c("id", "date_1")]), ]
说明:你之前用sqldf出现重复行是因为table_1中id=123本身就有2条完全相同的记录,每条记录都会匹配到table_2的对应行,属于正常现象,不是方法缺陷。
2. dplyr实现
如果习惯用tidyverse语法,可以用dplyr 1.1.0及以上版本支持的非等值连接语法,代码更简洁:
library(dplyr) final_dplyr <- left_join( table_1, table_2, # 直接指定连接条件 join_by(id == id, date_1 >= date_2, date_1 <= date_3) ) # 可选去重 final_dplyr_no_dup <- final_dplyr %>% distinct(id, date_1, .keep_all = TRUE)
如果需要其他连接类型,把left_join替换为inner_join(内连接)、right_join(右连接)即可。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

