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

R 为什么在列数较少的data.table上,DT1[DT2][,value1 value]比DT1[DT2,value1 value]快?,r,data.table,R,Data.table,这与这个问题()有关,这个问题的提出是因为我假设与此相反的是真的 data.table仅包含两列: 假设您希望联接两个数据表,然后对两个联接的列执行一个简单的操作,这可以通过一次或两次调用[: 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, v

这与这个问题()有关,这个问题的提出是因为我假设与此相反的是真的

data.table仅包含两列: 假设您希望联接两个
数据表
,然后对两个联接的列执行一个简单的操作,这可以通过一次或两次调用
[

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 

我认为这是由于重复的子集设置
DT1[DT2,value1-value]
使
DT2
中的每个
名称都成为可能。也就是说,您必须在这里为每个
i
执行
j
操作,而不是在
连接之后只执行一个
j
操作。这对于1e6个唯一条目来说成本非常高。也就是说,
[.data.table
变得重要和引人注目

DT1[DT2][, value1-value] # similar to rowSums
DT1[DT2, value1-value]
在第一种情况下,
DT1[DT2]
,首先执行
连接,速度非常快。当然,如图所示,有了更多的列,您会看到差异。但关键是执行一次连接。但在第二种情况下,您将按DT2的名称对DT1进行分组,并为每一个DT2计算差异。也就是说,您正在为
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
Rprof()

t1我把标题改成了更直接的。希望没问题。我只是想确认你意识到了(从OP看不明显)在第一种情况下,有一个隐藏的
by
,这两个表达式通常给出两种*类型的expressions@eddi我想我并没有意识到-是否愿意在此基础上进一步扩展?请看和后续。我希望这种行为在未来会变得明确,使差异变得明显。精彩的问题n+答案