如何加快rbind?
Posted
技术标签:
【中文标题】如何加快rbind?【英文标题】:How to speed up rbind? 【发布时间】:2013-10-31 02:56:20 【问题描述】:我应该从 MS-SQL 服务器下载一个表。
行数大于 600 万。服务器无法一次返回全部数据。
所以,我编写了一个一次下载 10,000 行的代码。并且,它在循环中绑定行。
假设getData()
函数返回的数据帧一次包含 10000 行。 (伪代码)
for(i in 1:600)
tempValue <- getData()
wannagetValue <- rbind(wannagetValue,tempValue)
print(i)
问题是随着时间的推移它会变慢。
我认为像那样使用 rbind 不是一个好主意。
任何建议都会很有帮助。提前谢谢你。
【问题讨论】:
如果您知道最终的数据框有多大,那么预先分配它并随时填写值会快得多。尽管可能会有更快的解决方案使用不同的数据结构来发布。 wannagetValue 谢谢大卫!你救了我..罗伯特//我不知道~~我只知道有超过 500GB 的数据。 您确实意识到 R 将所有内容都存储在内存中,对吧?如果您有 500GB 的数据,则至少需要这么多内存,理想情况下是两倍。 @HongOoi // 整个原始数据将超过 500GB,但如果存储为二进制数据,总共将是 5~10GB。此外,每个表包含 1~2GB。我可以分开处理。幸运的是,我的电脑有 64GB DDR3 ECC RAM。我认为这还不够。顺便说一句,谢谢你的建议。 【参考方案1】:以下是一些我确信可能会更好的选项:
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)
正如您所见,使用 data.table
的 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
【讨论】:
+1 - 请添加do.call(rbind, lapply(1:25,function(...) getData()))
非常感谢您提供的详细信息。~它对我很有帮助。【参考方案2】:
正如上面所指出的,R 默认情况下将其所有对象都存储在 RAM 中,所以对于这么多的数据,你会遇到一些问题。
我想补充两点:
1)一般如果不想使用data.table,可以使用Hadley的plyr
包中的rbind.fill
函数,速度也挺快的。 永远不要像上面那样使用rbind
,在“for”循环中分别附加每一行。每次追加一行时,它都会强制 R 复制数据框对象,这很慢。
2) 要使用 R 处理大于 RAM 的数据,请查看 http://cran.r-project.org/web/views/HighPerformanceComputing.html 的 Large memory and out-of-memory data 部分,可能是 bigmemory
包是你需要的。
【讨论】:
整个原始数据将超过500GB,但如果存储为二进制数据,总共将是5~10GB。此外,每个表包含 1~2GB。我可以分开处理。幸运的是,我的电脑有 64GB DDR3 ECC RAM。我认为这还不够。顺便说一句,谢谢你的建议。 这个问题有点老了,但我今天在寻找解决方案时仍然发现它,所以我想补充一下,Hadley 较新的dplyr
包具有bind_rows
的功能,类似于@ 987654329@。我对它进行了基准测试,它在我的机器上的运行速度比 do.call('rbind', ...)
快了大约 1000 倍。见this question。【参考方案3】:
也许您可以执行SELECT COUNT(*) FROM table_name WHERE ...
,然后为您的数据框预分配空间。
实际上,我认为每 10k 行查询数据库并不是一个好主意。尝试通过将数据导出到本地磁盘并从那里读取来避免这种情况。它也会提高速度。存储很便宜,但网络带宽和内存却不便宜。
【讨论】:
以上是关于如何加快rbind?的主要内容,如果未能解决你的问题,请参考以下文章