我应该从MS-SQL服务器上下载一个表。
行数大于600万。服务器不能一次返回全部数据。
因此,我编写了一段一次下载10,000行的代码。而且,它在循环中绑定行。
假设getData()函数一次返回一个包含10000行的数据帧。(伪代码)
for(i in 1:600)
{
tempValue <- getData()
wannagetValue <- rbind(wannagetValue,tempValue)
print(i)
}问题是,随着时间的推移,它变得越来越慢。
我认为这样使用rbind不是一个好主意。
任何建议都会很有帮助。提前谢谢你。
发布于 2013-10-31 11:52:25
这里有几个我确信可以更好的选择:
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()比使用base 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发布于 2013-10-31 13:53:17
如上所述,默认情况下,R将其所有对象存储在RAM中,因此对于如此大量的数据,您将遇到一些问题。
我想补充两件事: 1)一般来说,如果您不想使用data.table,您可以使用Hadley的plyr包中的rbind.fill函数,这也是相当快的。永远不要像上面那样使用rbind,在“for”循环中,单独追加每一行。它强制R在您每次追加一行时复制数据框对象,这是很慢的。
2)要使用R处理大于内存的数据,请查看http://cran.r-project.org/web/views/HighPerformanceComputing.html上的“Large memory out-memory data”一节,也许bigmemory包就是您需要的。
发布于 2017-07-04 14:29:11
也许你可以执行SELECT COUNT(*) FROM table_name WHERE ...,然后为你的数据帧预先分配空间。
实际上,我不认为每10k行查询您的数据库是一个好主意。尝试通过将数据导出到本地磁盘并从本地磁盘读取数据来避免这种情况。这也会提高速度。存储很便宜,但网络带宽和内存却不便宜。
https://stackoverflow.com/questions/19697700
复制相似问题