为什么DT1 [DT2] [,value1-value]比data.table上的DT1 [DT2,value1-value]更快,列数更少?

时间:2013-07-18 09:23:49

标签: r data.table

这与这个问题(Can I access repeated column names in `j` in a data.table join?)有关,因为我认为与此相反的是真实的。

data.table只有2列:

假设您希望加入两个data.tables,然后对两个已加入的列执行简单操作,可以通过一次或两次调用.[来完成此操作:

N = 1000000
DT1 = data.table(name = 1:N, value = rnorm(N))
DT2 = data.table(name = 1:N, value1 = rnorm(N))
setkey(DT1, name)

system.time({x = DT1[DT2, value1 - value]})     # One Step

system.time({x = DT1[DT2][, value1 - value]})   # Two Step

事实证明,进行两次调用 - 首先进行连接,然后进行减法 - 明显快于一次性

> system.time({x = DT1[DT2, value1 - value]})
   user  system elapsed 
   0.67    0.00    0.67 
> system.time({x = DT1[DT2][, value1 - value]})
   user  system elapsed 
   0.14    0.01    0.16 

为什么会这样?

带有许多列的

data.table:

如果您将大量列放入data.table,那么您最终会发现一步法更快 - 大概是因为data.table仅使用您在j中引用的列

N = 1000000
DT1 = data.table(name = 1:N, value = rnorm(N))[, (letters) := pi][, (LETTERS) := pi][, (month.abb) := pi]
DT2 = data.table(name = 1:N, value1 = rnorm(N))[, (letters) := pi][, (LETTERS) := pi][, (month.abb) := pi]
setkey(DT1, name)
system.time({x = DT1[DT2, value1 - value]})
system.time({x = DT1[DT2][, value1 - value]})

> system.time({x = DT1[DT2, value1 - value]})
   user  system elapsed 
   0.89    0.02    0.90 
> system.time({x = DT1[DT2][, value1 - value]})
   user  system elapsed 
   1.64    0.16    1.81 

1 个答案:

答案 0 :(得分:9)

我认为这是由于DT1[DT2, value1-value]name的每个DT2重复进行了子集j。也就是说,您必须在此处为每个i执行j操作,而不是在join之后只执行一次[.data.table操作。对于1e6个唯一条目,这变得非常昂贵。也就是说,DT1[DT2][, value1-value] # similar to rowSums DT1[DT2, value1-value] 变得重要而且引人注目。

DT1[DT2]

在第一种情况下,join,您首先执行DT1,而确实快。当然,如您所示,有了更多列,您会看到不同之处。但重点是执行连接一次。但在第二种情况下,你是按照DT2的名字对DT1进行分组,对于每一个你都在计算差异。也就是说,您为DT2的每个值子集Rprof() t1 <- DT1[DT2, value1-value] Rprof(NULL) summaryRprof() # $by.self # self.time self.pct total.time total.pct # "[.data.table" 0.96 97.96 0.98 100.00 # "-" 0.02 2.04 0.02 2.04 Rprof() t2 <- DT1[DT2][, value1-value] Rprof(NULL) summaryRprof() # $by.self # self.time self.pct total.time total.pct # "[.data.table" 0.22 84.62 0.26 100.00 # "-" 0.02 7.69 0.02 7.69 # "is.unsorted" 0.02 7.69 0.02 7.69 - 每个子集一个'j'操作!你可以通过运行这个来更好地看到这个:

join

当你的列数太多而许多列上的{{1}}超过了耗时的操作时,似乎可以克服重复子集化的开销。您可以通过分析其他代码来自行检查。