cbind vs rbind with data.table

and*_*rew 10 r data.table

我注意到,对于data.tables,cbind需要比rbind长得多的时间.这是什么原因?

> dt <- as.data.table(mtcars)                             
> new.dt <- copy(dt)                                      
> timeit({for (i in 1:100) dt.new <- rbind(dt.new, dt)})  
   user  system elapsed                                   
  0.237   0.012   0.253                                   
> new.dt <- copy(dt)                                      
> timeit({for (i in 1:100) dt.new <- cbind(dt.new, dt)})  
   user  system elapsed                                   
 14.795   0.090  14.912    
Run Code Online (Sandbox Code Playgroud)

哪里

timeit <- function(expr)
{
    ptm <- proc.time()
    expr
    proc.time() - ptm
}
Run Code Online (Sandbox Code Playgroud)

edd*_*ddi 8

最终,我认为这归结为alloc.col由于循环导致从列中删除各种属性而变慢.我不完全确定为什么这样做,也许Arun或Matt可以解释.

如下所示,基本操作cbindrbind以下快得多:

cbind.dt.simple = function(...) {
  x = c(...)
  setattr(x, "class", c("data.table", "data.frame"))
  ans = .Call(data.table:::Calloccolwrapper, x, max(100L, ncol(x) + 64L), FALSE)
  .Call(data.table:::Csetnamed, ans, 0L)
}

library(microbenchmark)

microbenchmark(rbind(dt, dt), cbind(dt, dt), cbind.dt.simple(dt, dt))
#Unit: microseconds
#                    expr      min        lq      mean    median        uq       max neval
#           rbind(dt, dt)  785.318  996.5045 1665.1762 1234.4045 1520.3830 21327.426   100
#           cbind(dt, dt) 2350.275 3022.5685 3885.0014 3533.7595 4093.1975 21606.895   100
# cbind.dt.simple(dt, dt)   74.125  116.5290  168.5101  141.9055  180.3035  1903.526   100
Run Code Online (Sandbox Code Playgroud)

  • 啊,我明白了。我的下一个想法 `setDT(setattr(do.call(c,list(...)),"class",c("data.frame")))` 慢得多。哦,简单的`setDT(do.call(c,list(...)))` 有效,但速度相同(慢)。 (2认同)
  • 是的,我使用了 `as.data.table` 和 `setDT`(与 `cbind` 中使用的 `data.table::data.table` 相反),虽然它们快一点,但它们会变慢在 `alloc.col` 调用时显着下降 (2认同)