data.table非等值连接匹配结果反直觉的原因及调整方法
data.table非等值连接的匹配行为与解决方案
该行为是data.table的既定机制
当使用x[y, on=..., :=]语法对x进行更新时,对于x中的每一行,y里所有满足连接条件的行都会依次执行更新操作,最终x中该行保留的是最后一次匹配的结果。
在你的示例中,dt2按date升序排列后,满足dt1$date <= dt2$date的行是id=2、3、4对应的记录,这三行会依次对dt1的唯一行进行更新,最后一次更新来自id=4的记录,所以结果显示的是2017-01-01和id=4。
除反转表序外的其他调整方法
1. 使用mult="first"参数
data.table提供了mult参数,专门用于控制多匹配场景下取哪一个结果,指定mult="first"即可直接取第一个满足条件的匹配项:
library(data.table) dt1 <- data.table(date = as.Date("2015-01-01")) dt2 <- data.table(id = 1:4, date = as.Date(c("2014-01-01", "2015-02-01", "2016-01-01", "2017-01-01"))) setorder(dt2, date) # 添加mult="first"参数 dt1[dt2, on = .(date <= date), `:=`(date2 = i.date, id = i.id), mult="first"]
运行后dt1的结果会是:
date date2 id 1: 2015-01-01 2015-02-01 2
2. 先筛选匹配项再连接
如果需要更灵活的控制,可以先从dt2中筛选出每个dt1记录对应的目标匹配行,再执行连接更新:
# 先获取dt1每个date对应的dt2中最小的符合条件的记录 match_records <- dt2[dt1, on = .(date >= date), .(date = x.date, date2 = i.date, id = i.id), mult="first"] # 用筛选后的记录更新dt1 dt1[match_records, on = .(date), `:=`(date2 = i.date2, id = i.id)]
这种方法适合需要对匹配逻辑做额外处理的场景,比如同时筛选多个条件。
内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

