OP 已要求
找到不包含在任何fdate 中的最近范围
start/stop范围
如果fdate 是包含在一个范围内,有两种可能的解释:
以下方法可用于获得两种解释的答案。
找到下一个最近的不同范围
- 将行号添加到
d2,因为这是必填信息
- 做一个反向滚动连接,找到最近的范围
start,它晚于或等于每个fdate,计算时间差
- 做一个前向滚动连接找到最接近或等于每个
fdate的范围stop,计算时间差
-
rbind() 两个子集,因此每个 fdate 有两行
- 对于每个
fdate,选择时差最小或行数较小的范围,以防出现平局
- 按
fdate 排序结果
实现为
d2[, rn2 := .I]
result <- rbind(
d2[d1, on = .(start = fdate), roll = -Inf,
.(rn2 = x.rn2, fdate = i.fdate, delta = x.start - i.fdate)],
d2[d1, on = .(stop = fdate), roll = +Inf,
.(rn2 = x.rn2, fdate = i.fdate, delta = i.fdate - x.stop)]
)[order(rn2), .(rn2 = rn2[which.min(delta)]), keyby = fdate]
result
fdate rn2
1: 2007-06-22 23:00:00 1
2: 2007-06-23 06:00:00 2
3: 2007-06-23 08:00:00 1
4: 2007-06-23 15:30:00 1
5: 2007-06-23 23:00:00 2
6: 2007-06-24 06:00:00 1
7: 2007-06-24 08:00:00 2
请注意,该用例已扩展为使用fdate 在两个范围之外、内部和之间测试各种配置(请参阅数据部分)。
结果在可视化时更容易验证:
library(ggplot2)
ggplot(result) +
aes(x = fdate, y = factor(rn2), label = seq.int(nrow(d1)), colour = factor(rn2)) +
geom_point() +
geom_text(nudge_y = 0.1) +
geom_segment(aes(yend = rn2, x = start, xend = stop, label = NULL), data = d2, size = 2) +
theme_bw() +
theme(legend.position = "none") +
ylab("matching d2 row number")
- 点 1、3、5 和 7 不包含在任何范围内,并且已分配到各自最近的范围 1 或 2。
- 点 4 不包含在任何范围内,但正好位于范围 1 的
stop 和范围 2 的 start 之间的中间,导致距离平局。如果出现平局,order(rn2) 可确保以可预测的方式选择较低的范围。
- 点 2 包含在范围 1 中,并分配给下一个不同范围 2。
- 点 6 包含在范围 2 中,并分配给下一个不同范围 1。
或者,返回NA
对于第二种解释,NA 分配给包含在一个范围内的fdate。为了识别这些情况,使用data.table 的%inrange% 运算符,它比foverlaps() 更易于使用:
result[fdate %inrange% d2[, .(start, stop)], rn2 := NA_integer_][]
fdate rn2
1: 2007-06-22 23:00:00 1
2: 2007-06-23 06:00:00 NA
3: 2007-06-23 08:00:00 1
4: 2007-06-23 15:30:00 1
5: 2007-06-23 23:00:00 2
6: 2007-06-24 06:00:00 NA
7: 2007-06-24 08:00:00 2
剧情
表明点 2 和 6 不再分配给任何范围。
数据
library(data.table)
d1 <- data.table(fdate = as.POSIXct(c("2007-06-22 23:00:00",
"2007-06-23 06:00:00",
"2007-06-23 08:00:00",
"2007-06-23 15:30:00",
"2007-06-23 23:00:00",
"2007-06-24 06:00:00",
"2007-06-24 08:00:00")))
d2 <- data.table(start = as.POSIXct(c("2007-06-23 00:00:00", "2007-06-24 00:00:00")),
stop = as.POSIXct(c("2007-06-23 07:00:00", "2007-06-24 07:00:00")))