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

Cor*_*one 6 r data.table

这与这个问题有关(我可以在data.table join中查看`j`中重复的列名吗?),因为我认为与此相反的是真的.

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
Run Code Online (Sandbox Code Playgroud)

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

> 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 
Run Code Online (Sandbox Code Playgroud)

为什么是这样?

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 
Run Code Online (Sandbox Code Playgroud)

Aru*_*run 9

我认为,这是由于重复的子集DT1[DT2, value1-value],使每一个nameDT2.也就是说,你必须在这里执行j每个操作i,而不是仅仅执行一个j操作join.对于1e6个唯一条目,这变得非常昂贵.也就是说,[.data.table变得显着而且引人注目.

DT1[DT2][, value1-value] # similar to rowSums
DT1[DT2, value1-value]
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,DT1[DT2]你执行第一种情况,join真的很快.当然,如您所示,有了更多列,您会看到不同之处.但重点是执行一次连接.但在第二种情况下,你是按照DT2的名字对DT1进行分组,对于每一个你都在计算差异.也就是说,您DT1为每个子集的每个值进行DT2子集化- 每个子集的'j'操作!你可以通过运行这个来更好地看到这个:

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
Run Code Online (Sandbox Code Playgroud)

当你有太多的列并且join许多列超过了耗时的操作时,似乎可以克服重复子集化的这种开销.您可以通过分析其他代码来自行检查.