如何加速rbind?

Kei*_*ark 18 r

我应该从MS-SQL服务器下载一个表.

行数大于600万.服务器无法一次返回整个数据.

所以,我写了一个代码,一次下载10,000行.并且,它绑定循环中的行.

假设getData()函数一次返回一个包含10000行的数据帧.(伪代码)

for(i in 1:600)
{
    tempValue <- getData()
    wannagetValue <- rbind(wannagetValue,tempValue)
    print(i)
}
Run Code Online (Sandbox Code Playgroud)

问题是随着时间的推移它会变慢.

我认为像这样使用rbind并不是一个好主意.

任何建议都会非常有帮助.先感谢您.

Dav*_*vid 34

以下是一些我认为可能会更好的选择:

library(data.table)
library(microbenchmark)

#function to generate your data
getData <- function(){
  data.frame(x=rnorm(10000),y=rnorm(10000),z=rnorm(10000))
}

#using data table's rbindlist each iteration
fDT1 <- function(n){
  dat <- getData()
  for(i in 1:n){
    dat <- rbindlist(list(dat,getData()))
  }
  return(data.frame(dat))
}

#using data table's rbindlist all at once
fDT2 <- function(n){
  return(data.frame(rbindlist(lapply(1:n,function(x) getData()))))
}

#pre-allocating a data frame
fPre <- function(n){
  dat <- data.frame(x=rep(0,n*10000),y=rep(0,n*10000),z=rep(0,n*10000))
  j <- 1
  for(i in 1:n){
    dat[j:(j+10000-1),] <- getData()
    j <- j + 10000
  }
  return(dat)
}

#standard do.call rbind
f2 <- function(n){
  return(do.call(rbind,lapply(1:n,function(x) getData())))
}

#current approach
f <- function(n){
  dat <- getData()
  for(i in 1:n){
    dat <- rbind(dat,getData())
  }
  return(dat)
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,使用data.table's rbindlist()是对基础R的一个很大的改进,rbind()并且在一次追加行而不是在交互中有很大的好处,但是如果存在内存问题则可能无法实现.您可能还会注意到,随着数据大小的增加,速度的提升远不及线性.

 > microbenchmark(fDT2(5),fDT1(5),fPre(5),f2(5),f(5),
+                fDT2(25),fDT1(25),fPre(25),f2(25),f(25),
+                fDT2(75),fDT1(75),fPre(75),f2(75),f(75),
+                times=10)
Unit: milliseconds
     expr        min         lq     median         uq         max neval
  fDT2(5)   18.31207   18.63969   24.09943   25.45590    72.01725    10
  fDT1(5)   27.65459   29.25147   36.34158   77.79446    88.82556    10
  fPre(5)   34.96257   39.39723   41.24445   43.30319    68.75897    10
    f2(5)   30.85883   33.00292   36.29100   43.53619    93.15869    10
     f(5)   87.40869   97.97500  134.50600  138.65354   147.67676    10
 fDT2(25)   89.42274   99.39819  103.90944  146.44160   156.01653    10
 fDT1(25)  224.65745  229.78129  261.52388  280.85499   300.93488    10
 fPre(25)  371.12569  412.79876  431.80571  485.37727  1046.96923    10
   f2(25)  221.03669  252.08998  265.17357  271.82414   281.47096    10
    f(25) 1446.32145 1481.01998 1491.59203 1634.99936  1849.00590    10
 fDT2(75)  326.66743  334.15669  367.83848  467.85480   520.27142    10
 fDT1(75) 1749.83842 1882.27091 2066.95241 2278.55589  2419.07205    10
 fPre(75) 3701.16220 3968.64643 4162.70585 4234.39716  4356.09462    10
   f2(75) 1174.47546 1183.98860 1314.64585 1421.09483  1537.42903    10
    f(75) 9139.36935 9349.24412 9510.90888 9977.24621 10861.51206    10
Run Code Online (Sandbox Code Playgroud)


coa*_*nil 5

正如上面所指出的,默认情况下,R 将其所有对象存储在 RAM 中,因此对于如此大量的数据,您将遇到一些问题。

我想补充两点: 1)一般来说,如果你不想使用data.table,你可以使用rbind.fillHadley's plyrpackage中的函数,它也非常快。永远不要使用rbind上面的方法,在“for”循环中,分别附加每一行。每次添加一行时,它都会强制 R 制作数据框对象的副本,这很慢。

2)与其中R比-RAM较大数据工作,看看在部分多内存和外的存储器中的数据http://cran.r-project.org/web/views/HighPerformanceComputing.html,也许这个bigmemory包是你需要的。

  • 这个问题有点老了,但我今天在搜索解决方案时仍然找到了它,所以我想补充一点,Hadley 较新的 `dplyr` 包具有类似于 `rbind.fill` 的函数 `bind_rows`。我对它进行了基准测试,它的运行速度比我机器上的 `do.call('rbind', ...)` 快 1000 倍。见[这个问题](/sf/ask/3112510901/)。 (4认同)