我正在尝试通过data.table调用替换SQL生产的笛卡尔积。我在资产和价值方面拥有悠久的历史,并且需要所有组合的子集。假设我有一个表T,其中T = [日期,合同,价值]。在SQL中看起来像
SELECT a.date, a.contract, a.value, b.contract. b.value
FROM T a, T b
WHERE a.date = b.date AND a.contract <> b.contract AND a.value + b.value < 4
在RI现在有以下内容
library(data.table)
n <- 1500
dt <- data.table(date = rep(seq(Sys.Date() - n+1, Sys.Date(), by = "1 day"), 3),
contract = c(rep("a", n), rep("b", n), rep("c", n)),
value = c(rep(1, n), rep(2, n), rep(3, n)))
setkey(dt, date)
dt[dt, allow.cartesian = TRUE][(contract != i.contract) & (value + i.value < 4)]
我相信我的解决方案会首先创建所有组合(在本例中为13,500行),然后进行过滤(至3000)。但是,SQL(并且我可能错了)联接子集,更重要的是不要将所有组合都加载到RAM中。任何想法如何更有效地使用data.table?
使用= .EACHI功能。在data.table
联接中,子集紧密相连;即,联接只是使用-的另一个子集,data.table
而不是通常的整数/逻辑/行名。考虑到这些情况,以这种方式设计它们。
基于子集的联接允许在联接时将-j
表达式和分组操作合并在一起。
require(data.table)
dt[dt, .SD[contract != i.contract & value + i.value < 4L], by = .EACHI, allow = TRUE]
这是惯用的方式(如果您i.*
只想使用cols作为条件,但又不返回它们),但是.SD
尚未进行优化,因此为每个组评估j
-expression的.SD
成本很高。
system.time(dt[dt, .SD[contract != i.contract & value + i.value < 4L], by = .EACHI, allow = TRUE])
# user system elapsed
# 2.874 0.020 2.983
使用的某些案例.SD
已经过优化。在解决这些情况之前,您可以通过以下方式解决它:
dt[dt, {
idx = contract != i.contract & value + i.value < 4L
list(contract = contract[idx],
value = value[idx],
i.contract = i.contract[any(idx)],
i.value = i.value[any(idx)]
)
}, by = .EACHI, allow = TRUE]
这需要0.045秒,而不是方法中的0.005秒。但是每次都by = .EACHI
评估j
-expression(因此评估内存效率)。那是您必须接受的权衡。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句