data.table滚动连接中‘nearest’定义及连接结果异常问询
问题根源:连接方向搞反导致重复赋值覆盖
你写的d[lookup, on = c("id", "date"), roll = "nearest", value := i.value]是用lookup的6行去更新d的2行——lookup里有3行id=id2的记录,每一行都会匹配到d里唯一的id2行,然后把lookup的value赋值过去。最后一次赋值的是lookup中id2的最后一行(值为6),所以最终结果是6,这根本不是roll="nearest"的问题,是重复赋值覆盖的锅。
一、roll="nearest"的准确定义
data.table里roll="nearest"的核心规则(以x[i, on=c(分组键, 滚动键), roll="nearest"]为例):
- 先按分组键(比如
id)把x和i分成对应组。 - 对
i里的每一行,找同组x中滚动键(比如date)和当前行滚动键差值最小的那一行匹配。 - 如果刚好卡在两个值中间(差值相同),就选
x里位置靠后的那行。 rollends=c(TRUE,TRUE)只是控制:如果i的滚动键超出了同组x的范围,允许用首尾行来匹配,默认就是开启状态。
二、连接方向差异的本质
data.table里x[i]和i[x]的核心区别是谁作为驱动表去查找谁:
x[i]:用i的每一行去查x,最终结果的行数和i一致。i[x]:用x的每一行去查i,最终结果的行数和x一致。
你要的是用d的两行去匹配lookup里的对应项,所以得让d当驱动表,也就是用lookup[d, ...]的形式,而不是反过来让lookup当驱动表去更新d。
三、单次连接得到预期结果的正确写法
直接让d作为驱动表,从lookup中匹配赋值,避免重复覆盖:
写法1:直接给d的value列赋值
library(data.table) # 构造示例数据 lookup <- data.table( id = c("id1", "id1", "id1", "id2", "id2", "id2"), date = as.Date(c("2023-01-01", "2023-01-02", "2023-01-03", "2023-01-01", "2023-01-02", "2023-01-03")), value = c(1,2,3,4,5,6) ) d <- data.table( id = c("id1", "id2"), date = as.Date(c("2023-01-04", "2022-12-31")), value = NA_real_ ) # 正确赋值逻辑 d[, value := lookup[.SD, on = c("id", "date"), roll = "nearest", x.value]]
写法2:直接生成结果表
d <- lookup[d, on = c("id", "date"), roll = "nearest", .(id, date, value = x.value)]
两种写法执行后,结果都符合预期:
| id | date | value |
|---|---|---|
| id1 | 2023-01-04 | 3 |
| id2 | 2022-12-31 | 4 |
内容的提问来源于stack exchange,提问作者SamR
相关产品推荐
相关产品推荐

