1) Base R - sapply 这使用 base R。对于 data.df 中 dt 的每个组件,它会在同一日期在 lookup.df 中找到大于它的所有日期时间,然后返回第一个的索引。最后,它将 data.df 和 lookup.df 的那些索引的行放在一起。
ix <- sapply(data.df$dt, function(dt) with(lookup.df,
which(ldt >= dt & as.Date(ldt, tz = "") == as.Date(dt, tz = ""))[1]
))
res <- cbind(data.df, lookup.df[ix, ])
rownames(res) <- NULL
给予:
> res
dt v1 ldt lv
1 2020-01-08 11:30:00 1 2020-01-08 11:30:00 2
2 2020-01-10 11:30:00 2 2020-01-10 11:31:00 5
3 2020-01-11 12:30:00 3 <NA> NA
2) Base R - 合并 这是一种替代的 base R 方法。将日期列附加到每个输入数据框,然后按该列合并两者。删除 lookup.df 日期/时间小于 data.df 日期/时间的任何行,然后取出从相同原始 data.df 行派生的每组行的第一行。这将获得匹配项,但它会错过根本没有匹配项的行,因此请执行第二次合并以将其取回。
data.df$date <- as.Date(data.df$dt, tz = "")
lookup.df$date <- as.Date(lookup.df$ldt, tz = "")
m <- merge(data.df, lookup.df, by = "date", all.x = TRUE, all.y = FALSE)
m <- subset(m, dt <= ldt)
m <- m[!duplicated(m[1:3]), ]
merge(data.df[-3], m[-1], by = c("dt", "v1"), all.x = TRUE, all.y = FALSE)
给予:
dt v1 ldt lv
1 2020-01-08 11:30:00 1 2020-01-08 11:30:00 2
2 2020-01-10 11:30:00 2 2020-01-10 11:31:00 5
3 2020-01-11 12:30:00 3 <NA> NA
3) SQL 尽管问题要求提供基本 R 解决方案,但此处还添加了一个 sql 解决方案,因为它提供了将问题特别直接地转换为代码的自联接复杂的情况。它对指定条件执行左连接,并采用从 data.df 中同一行派生的所有行中找到的最小值 ldt。
library(sqldf)
data.df$date <- as.Date(data.df$dt, tz = "")
lookup.df$date <- as.Date(lookup.df$ldt, tz = "")
sqldf("select D.dt, D.v1, min(L.ldt) as ldt, L.lv
from [data.df] D left join [lookup.df] L
on D.dt <= L.ldt and D.date == L.date
group by D.rowid")
给予:
dt v1 ldt lv
1 2020-01-08 11:30:00 1 2020-01-08 11:30:00 2
2 2020-01-10 11:30:00 2 2020-01-10 11:31:00 5
3 2020-01-11 12:30:00 3 <NA> NA
注意
问题中有一个问题,R 无法读取花哨的引号,因此我们将其用作输入:
data.df <- data.frame(dt = as.POSIXct(c('2020-01-08 11:30:00',
'2020-01-10 11:30:00', '2020-01-11 12:30:00')),
v1=c(1,2,3))
lookup.df <- data.frame(ldt = as.POSIXct(c('2020-01-08 11:29:00',
'2020-01-08 11:30:00', '2020-01-08 11:31:00', '2020-01-10 10:30:00',
'2020-01-10 11:31:00', '2020-01-11 11:30:00', '2020-01-12 11:30:00')),
lv = 1:7)