nic*_*las 1 performance r data.table
我有一个小的data.table和使用transform它需要永远.这是一个可重复的例子:
library(data.table)
#data.table 1.8.8
set.seed(1)
dataraw <- data.table(sig1 = runif(80000, 0, 9999),
sig2 = runif(80000, 0, 9999),
sig3 = runif(80000, 0, 9999))
system.time(transform(dataraw, d = 1))
# user system elapsed
#16.345 0.016 16.359
dataraw2 <- as.data.frame(dataraw)
system.time(transform(dataraw2, d = 1))
# user system elapsed
#0.002 0.002 0.005
Run Code Online (Sandbox Code Playgroud)
transform与data.frame一起使用时,为什么data.table的速度如此之慢?
Aru*_*run 14
o
transform()开启的缓慢data.table已经确定#2599.但是,请使用:=.
虽然从文档和?transform.data.table(从SenorO的帖子中)可以清楚地看出,惯用的方法是使用:=(通过引用分配),这是非常快的,但我认为知道为什么 transform慢一点仍然很有趣data.table.从我已经设法到目前为止领悟,transform.data.table是不是总是慢.
我会尝试在这里回答这个问题.它本身似乎不是一个问题transform.data.table,而是它对data.table()函数的调用.通过观察data.table:::transform.data.table,滞后来自这条线:
ans <- do.call("data.table", c(list(`_data`), e[!matched]))
Run Code Online (Sandbox Code Playgroud)
那么,让我们data.table按照以下顺序对这一行进行基准测试:
DT <- data.table(x=1:1e5, y=1:1e5, z=1:1e5)
system.time(do.call("data.table", c(list(DT), list(d=1))))
user system elapsed
0.003 0.003 0.026
Run Code Online (Sandbox Code Playgroud)
哦,这非常快!让我们的基准测试相同,但值不是按顺序:
DT <- data.table(x=sample(1e5), y=sample(1e5), z=sample(1e5))
system.time(do.call("data.table", c(list(DT), list(d=1))))
user system elapsed
7.986 0.016 8.099
# tested on 1.8.8 and 1.8.9
Run Code Online (Sandbox Code Playgroud)
它变慢了.造成这种差异的原因是什么?要做到这一点,我们必须调试data.table()功能.通过做
DT <- data.table(x=as.numeric(1:1e5), y=as.numeric(1:1e5), z=as.numeric(1:1e5))
debugonce(data.table)
transform(DT, d=1)
Run Code Online (Sandbox Code Playgroud)
并且通过连续点击"输入",你将能够找到这种缓慢的原因:
exptxt = as.character(tt) # roughly about 7.2 seconds
Run Code Online (Sandbox Code Playgroud)
很明显,as.character成为问题.为什么?为此,请比较:
as.character(data.frame(x=1:10, y=1:10))
# [1] "1:10" "1:10"
as.character(data.frame(x=sample(10), y=sample(10)))
# [1] "c(9, 10, 4, 7, 6, 5, 1, 3, 8, 2)" "c(8, 5, 3, 7, 6, 10, 9, 1, 4, 2)"
Run Code Online (Sandbox Code Playgroud)
重复此上更大的数据看出,as.character在取样data.frame得到更慢.
那么,问题就变成了,为什么不呢
data.table(x = sample(1e5), y=sample(1e5))
Run Code Online (Sandbox Code Playgroud)
耗时的?这是因为,赋予data.table()函数的输入被替换(with subsitute()).在这种情况下,tt变为:
$x
sample(1e+05)
$y
sample(1e+05)
Run Code Online (Sandbox Code Playgroud)
并且as.character(tt)然后就变成了:
# [1] "sample(1e+05)" "sample(1e+05)"
Run Code Online (Sandbox Code Playgroud)
这意味着,如果你这样做:
DT <- data.table(x = c(1,3,4,1,4,1,3,1,2...), y = c(1,1,4,1,3,4,1,1,3...))
Run Code Online (Sandbox Code Playgroud)
我认为这需要很多时间(通常不会这样做,因此没有问题).
Señ*_*r O 11
来自?transform.data.table:
transform by group is particularly slow. Please use := by group instead.
within, transform and other similar functions in data.table are not just provided
for users who expect them to work, but for non-data.table-aware packages to
retain keys, for example. Hopefully the (much) faster and more convenient
data.table syntax will be used in time.
Run Code Online (Sandbox Code Playgroud)
正如@Roland建议的那样,您应该始终细分代码的组件,以找出实际占用时间/资源的内容.在这种情况下,它不是log,但是transform.使用:=了data.tables,transform为data.frames,列表等.
罪魁祸首不是log:
> dt <- data.table(A=1:1000000)
> system.time(transform(as.data.frame(dt), B=A * 1))
user system elapsed
0.00 0.02 0.01
> system.time(transform(dt, B=A * 1))
user system elapsed
14.61 0.00 14.61
Run Code Online (Sandbox Code Playgroud)