R:如何在不耗尽内存的情况下重新绑定两个巨大的数据帧

时间:2011-01-21 16:19:22

标签: r memory memory-management data.table sqldf

我有两个数据框df1df2,每个数据框大约有1000万行和4列。我使用RODBC / sqlQuery将它们读入R并没有任何问题,但当我尝试rbind时,我得到了最可怕的R错误消息:cannot allocate memory。必须有更有效的方法来更有效地rbind - 任何人都有他们想要分享的最喜欢的技巧吗?例如,我在sqldf的文档中找到了此示例:

# rbind
a7r <- rbind(a5r, a6r)
a7s <- sqldf("select * from a5s union all select * from a6s")

这是最佳/推荐的方式吗?

更新 我使用上面dbname = tempfile()调用中的关键sqldf参数让它工作,正如JD Long在他对this question

的回答中所建议的那样

4 个答案:

答案 0 :(得分:26)

不是在开头将它们读入R然后组合它们,而是让SQLite读取它们并在将它们发送到R之前将它们组合起来。这样,文件永远不会单独加载到R中。

# create two sample files
DF1 <- data.frame(A = 1:2, B = 2:3)
write.table(DF1, "data1.dat", sep = ",", quote = FALSE)
rm(DF1)

DF2 <- data.frame(A = 10:11, B = 12:13)
write.table(DF2, "data2.dat", sep = ",", quote = FALSE)
rm(DF2)

# now we do the real work
library(sqldf)

data1 <- file("data1.dat")
data2 <- file("data2.dat")

sqldf(c("select * from data1", 
 "insert into data1 select * from data2", 
 "select * from data1"), 
 dbname = tempfile())

这给出了:

>  sqldf(c("select * from data1", "insert into data1 select * from data2", "select * from data1"), dbname = tempfile())
   A  B
1  1  2
2  2  3
3 10 12
4 11 13

如果行顺序不重要,则此较短版本也可以使用:

sqldf("select * from data1 union select * from data2", dbname = tempfile())

有关详细信息,请参阅sqldf主页http://sqldf.googlecode.com?sqldf。请特别注意文件格式参数,因为它们接近但与read.table不同。在这里,我们使用了默认值,因此它不是一个问题。

答案 1 :(得分:18)

请注意data.table R包,以便对数百万条记录的对象进行有效操作。

该软件包的1.8.2版提供了rbindlist功能,您可以通过该功能非常有效地实现您想要的功能。因此,您可以代替rbind(a5r, a6r)

library(data.table)
rbindlist(list(a5r, a6r))

答案 2 :(得分:1)

尝试创建所需大小的data.frame,因此使用下标导入数据。

dtf <- as.data.frame(matrix(NA, 10, 10))
dtf1 <- as.data.frame(matrix(1:50, 5, 10, byrow=TRUE))
dtf2 <- as.data.frame(matrix(51:100, 5, 10, byrow=TRUE))
dtf[1:5, ] <- dtf1
dtf[6:10, ] <- dtf2

我想rbind在不预先分配其维度的情况下增长对象...我不确定,这只是猜测。我今晚将梳理“The R Inferno”或“R操纵数据”。也许merge可以做到这一点......

修改

你应该记住(也许)你的系统和/或R无法应对那么大的事情。试试RevolutionR,也许你会设法节省一些时间/资源。

答案 3 :(得分:1)

为了完成这个主题的联合:大文件,请尝试在文件上使用shell命令来组合它们。在带有“/ B”标志的“COPY”命令的窗口中。示例:

system(command =
         paste0(
           c("cmd.exe /c COPY /Y"
             , '"file_1.csv" /B'
             , '+ "file_2.csv" /B'
             , '"resulting_file.csv" /B'
           ), collapse = " "
         )
)#system

要求文件没有标题和相同的分隔符等。 shell命令的速度和多功能性有时是一个很大的好处,因此在映射数据流时不要忘记CLI命令。