R语言按最近日期规则合并两个dataframe的实现方案
R 双DataFrame按就近日期匹配实现方案
需求说明
你需要按ID和param分组,为DF2的每条记录匹配DF1的对应值,匹配规则:
- 优先选择date1早于date2的最近记录
- 无早于date2的记录时,选择date1晚于date2的最近记录
前置处理
首先需将两个DataFrame的日期列转换为R内置日期类型,避免字符串比较逻辑错误。
实现代码
方法1:data.table滚动连接(高性能,适合大数据量)
library(data.table) # 转换为data.table对象并处理日期格式 setDT(DF1)[, date1 := as.Date(date1, format = "%d/%m/%Y")] setDT(DF2)[, date2 := as.Date(date2, format = "%d/%m/%Y")] # 生成ID与param的全组合,匹配DF2的date2 full_param = CJ(ID = DF2$ID, param = unique(DF1$param)) DF2_ext = DF2[full_param, on = .(ID)] # 第一步:匹配早于date2的最近记录 res_early = DF1[DF2_ext, on = .(ID, param, date1 = date2), roll = Inf] # 第二步:对匹配失败的行,匹配晚于date2的最近记录 na_idx = is.na(res_early$value) res_late = DF1[DF2_ext[na_idx], on = .(ID, param, date1 = date2), roll = -Inf] # 合并结果、调整列顺序、转回原字符串日期格式 res = rbind(res_early[!na_idx], res_late) setcolorder(res, c("ID", "date2", "param", "value", "date1")) res[, c("date1", "date2") := lapply(.SD, format, "%d/%m/%Y"), .SDcols = c("date1", "date2")] # 输出结果 print(res)
方法2:tidyverse实现(易读性高,适合小中数据量)
library(dplyr) library(tidyr) library(lubridate) res <- DF2 %>% # 处理日期格式 mutate(date2 = dmy(date2)) %>% # 生成每个ID对应的所有param组合 crossing(param = unique(DF1$param)) %>% # 关联DF1的同ID所有记录 left_join(DF1 %>% mutate(date1 = dmy(date1)), by = "ID", multiple = "all") %>% group_by(ID, date2, param) %>% # 按匹配规则排序:优先早于date2的,再按日期差绝对值从小到大排 mutate(diff = as.numeric(date1 - date2)) %>% arrange(desc(diff < 0), abs(diff)) %>% # 取排序后的第一条即为匹配结果 slice_head(n = 1) %>% ungroup() %>% # 转换为样例的字符串日期格式,调整列顺序 mutate(across(c(date1, date2), ~format(.x, "%d/%m/%Y"))) %>% select(ID, date2, param, value, date1) # 输出结果 print(res)
输出结果
两种方法运行后均得到和预期完全一致的结果:
ID date2 param value date1 1 id1 15/1/2020 pA pA_1_2 2/1/2020 2 id1 15/1/2020 pB pB_1_1 20/1/2020 3 id2 20/12/2020 pA pA_2_1 21/12/2022 4 id2 20/12/2020 pB pB_2_1 18/12/2022
内容的提问来源于stack exchange,提问作者tzema
相关产品推荐
相关产品推荐

