如何使用 data.table 在日期范围内执行连接?
Posted
技术标签:
【中文标题】如何使用 data.table 在日期范围内执行连接?【英文标题】:How to perform join over date ranges using data.table? 【发布时间】:2015-02-13 18:42:28 【问题描述】:如何使用 data.table 执行以下操作(直接使用 sqldf)并获得完全相同的结果:
library(data.table)
whatWasMeasured <- data.table(start=as.POSIXct(seq(1, 1000, 100),
origin="1970-01-01 00:00:00"),
end=as.POSIXct(seq(10, 1000, 100), origin="1970-01-01 00:00:00"),
x=1:10,
y=letters[1:10])
measurments <- data.table(time=as.POSIXct(seq(1, 2000, 1),
origin="1970-01-01 00:00:00"),
temp=runif(2000, 10, 100))
## Alternative short names for data.tables
dt1 <- whatWasMeasured
dt2 <- measurments
## Straightforward with sqldf
library(sqldf)
sqldf("select * from measurments m, whatWasMeasured wwm
where m.time between wwm.start and wwm.end")
【问题讨论】:
这能解决您的问题吗? ***.com/questions/5123197/… @DavidRobinson 谢谢。这个问题我其实已经看过了,可惜我的数据量很大,真的更喜欢快速的data.table解决方案…… 我知道这有点不真实,但我是唯一一个得到 1969 年 12 月 31 日约会的人吗?不应该是 1970 年 1 月 1 日吗? @SerbanTanasa 时区问题我猜... 【参考方案1】:您可以使用foverlaps()
函数,它可以有效地实现间隔连接。在您的情况下,我们只需要一个用于 measurments
的虚拟列。
注意 1: 您应该安装 data.table -
v1.9.5
的开发版本,因为foverlaps()
的错误已在此处修复。你可以找到安装说明here。注意 2: 为了方便起见,我会在此处致电
whatWasMeasured
=dt1
和measurments
=dt2
。
require(data.table) ## 1.9.5+
dt2[, dummy := time]
setkey(dt1, start, end)
ans = foverlaps(dt2, dt1, by.x=c("time", "dummy"), nomatch=0L)[, dummy := NULL]
更多信息请参见?foverlaps
,性能比较请参见this post。
【讨论】:
有什么办法可以让我们摆脱某种 %between% 语句?很难让 dt2[time %between% dt1[, list(start,end)]] 像我希望的那样工作。 @SerbanTanasa,看看the post 我已经在我的答案中链接了。它还比较了使用between
的解决方案的性能。
感谢您的回答。伟大的。有用。非常快。唯一的小问题是它不喜欢 start 或 end 或 time 的缺失值。也许 na.rm 处理会很好。此外,在对真实数据进行此练习时,我最终得到两个额外的不需要的列,名为“start”和“end”,我在输入数据中既没有,也没有键名或任何东西......
@Samo,使用 na.omit()
和 cols
参数(如果您使用的是 1.9.5)。会考虑na.rm
的论点,谢谢。我不明白 - 您的 data.table whatWasMeasured
有两列 start
和 end
,并且 sqldf 输出在您的帖子中的示例中也有相同的列。
@Arun 谢谢。是的,请忽略我关于幻象启动和意外出现的评论。实际上它们并没有出现。感谢您的理解。我在“真实”数据而不是上面的玩具示例上对此进行测试,显然我没有刷新所有对象......以上是关于如何使用 data.table 在日期范围内执行连接?的主要内容,如果未能解决你的问题,请参考以下文章