6

这与这个问题(我可以在 data.table 连接中访问 `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

事实证明,进行两次调用(先进行联接,然后进行减法)比一次调用要快得多

> 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 
4

1 回答 1

9

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

DT1[DT2][, value1-value] # similar to rowSums
DT1[DT2, value1-value]

在第一种情况下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

当您有太多列并且join在许多列上超过作为耗时的操作时,重复子集的这种开销似乎被克服了。您可以通过分析其他代码自己检查这一点。

于 2013-07-18T09:28:07.463 回答