R语言匹配两个数据框 按站点日期筛选±1小时内数据
R语言实现双表按站点日期匹配、时间差±1小时过滤记录
需求说明
需要对data2做行过滤,仅保留同时满足以下条件的记录:
- 与
data1的Site(站点)、Date(日期)字段取值完全匹配 - 同站点同日期分组下,记录时间与
data1中任意一条对应记录的时间差绝对值在1小时范围内
已知data1行数多于data2,最终输出结构和示例给出的data_final一致。
注:示例给出的期望结果
data_final中,EFG站点最后一条记录的Date值2022-01-05为笔误,实际匹配到的是2012-01-05的22:00记录,该记录与data1同组23:00的时间差刚好为1小时,符合保留规则。
实现方案
方案1:data.table 实现(推荐,大数据量性能最优)
适合数据量较大的场景,非等值连接效率远高于常规join后过滤的写法:
# 加载依赖包 library(data.table) # 转换为data.table对象,拼接生成标准日期时间字段 setDT(data1) setDT(data2) data1[, datetime := as.POSIXct(paste(Date, Time), format = "%Y-%m-%d %H:%M")] data2[, datetime := as.POSIXct(paste(Date, Time), format = "%Y-%m-%d %H:%M")] # 非等值连接匹配时间窗口,去重得到最终结果 data_final <- data2[ data1, on = .(Site, Date, datetime >= datetime - 3600, datetime <= datetime + 3600), .(Site, Date, Time = x.Time), nomatch = NULL ][!duplicated(.SD, by = c("Site", "Date", "Time"))] # 可选:按站点、日期、时间排序 setorder(data_final, Site, Date, Time)
方案2:dplyr + lubridate 实现(适配tidyverse语法习惯)
如果平时更习惯用tidyverse系列的语法,可以用以下写法:
# 加载依赖包 library(dplyr) library(lubridate) # 拼接生成标准日期时间字段 data1 <- data1 %>% mutate(datetime = ymd_hm(paste(Date, Time))) data2 <- data2 %>% mutate(datetime = ymd_hm(paste(Date, Time))) # 连接后按时间差过滤,去重得到最终结果 data_final <- data2 %>% inner_join(data1, by = c("Site", "Date"), suffix = c("", "_ref")) %>% mutate(time_diff = abs(difftime(datetime, datetime_ref, units = "hours"))) %>% filter(time_diff <= 1) %>% select(Site, Date, Time) %>% distinct() %>% arrange(Site, Date, Time)
结果逻辑验证
运行代码后过滤逻辑和预期完全一致:
- ABC站点2022-02-02的14:30记录,与同组data1最近的13:00记录时间差为1.5小时,被过滤
- EFG站点2011-01-01的23:00记录,与同组data1最近的20:30记录时间差为2.5小时,被过滤
- 其余记录均满足时间差要求,全部保留
内容的提问来源于stack exchange,提问作者Sarah
相关产品推荐
相关产品推荐

