我需要 rbind 两个大数据框。现在我用
df <- rbind(df, df.extension)
但我(几乎)立即耗尽内存。我猜是因为 df 在内存中保存了两次。将来我可能会看到更大的数据帧,所以我需要某种就地 rbind。
所以我的问题是:有没有办法在使用 rbind 时避免内存中的数据重复?
我发现了这个问题,它使用了 SqlLite,但我真的很想避免将硬盘驱动器用作缓存。
data.table
是你的朋友!
参见http://www.mail-archive.com/r-help@r-project.org/msg175877.html
跟进 nikola 的评论,这里是?rbindlist
描述(v1.8.2 中的新内容):
与 相同
do.call("rbind",l)
,但要快得多。
首先:如果您想安全,请使用您链接到的其他问题的解决方案。由于 R 是按值调用的,因此请忘记不会将数据帧复制到内存中的“就地”方法。
节省大量内存的一种不可取的方法是假装您的数据帧是列表,使用 for 循环强制列表(应用会像地狱一样吃掉内存)并使 R 相信它实际上是一个数据帧。
我会再次警告你:在更复杂的数据帧上使用它会带来麻烦和难以发现的错误。因此,请确保您测试得足够好,如果可能,请尽可能避免这种情况。
您可以尝试以下方法:
n1 <- 1000000
n2 <- 1000000
ncols <- 20
dtf1 <- as.data.frame(matrix(sample(n1*ncols), n1, ncols))
dtf2 <- as.data.frame(matrix(sample(n2*ncols), n1, ncols))
dtf <- list()
for(i in names(dtf1)){
dtf[[i]] <- c(dtf1[[i]],dtf2[[i]])
}
attr(dtf,"row.names") <- 1:(n1+n2)
attr(dtf,"class") <- "data.frame"
它会删除您实际拥有的行名(您可以重建它们,但检查是否有重复的行名!)。它也不执行 rbind 中包含的所有其他测试。
在我的测试中为您节省了大约一半的内存,并且在我的测试中 dtfcomb 和 dtf 是相等的。红色框是 rbind,黄色的是我的基于列表的方法。
测试脚本:
n1 <- 3000000
n2 <- 3000000
ncols <- 20
dtf1 <- as.data.frame(matrix(sample(n1*ncols), n1, ncols))
dtf2 <- as.data.frame(matrix(sample(n2*ncols), n1, ncols))
gc()
Sys.sleep(10)
dtfcomb <- rbind(dtf1,dtf2)
Sys.sleep(10)
gc()
Sys.sleep(10)
rm(dtfcomb)
gc()
Sys.sleep(10)
dtf <- list()
for(i in names(dtf1)){
dtf[[i]] <- c(dtf1[[i]],dtf2[[i]])
}
attr(dtf,"row.names") <- 1:(n1+n2)
attr(dtf,"class") <- "data.frame"
Sys.sleep(10)
gc()
Sys.sleep(10)
rm(dtf)
gc()
现在我制定了以下解决方案:
nextrow = nrow(df)+1
df[nextrow:(nextrow+nrow(df.extension)-1),] = df.extension
# we need to assure unique row names
row.names(df) = 1:nrow(df)
现在我没有内存不足。我认为这是因为我存储
object.size(df) + 2 * object.size(df.extension)
而使用 rbind R 则需要
object.size(rbind(df,df.extension)) + object.size(df) + object.size(df.extension).
之后我使用
rm(df.extension)
gc(reset=TRUE)
释放我不再需要的内存。
这暂时解决了我的问题,但我觉得有一种更高级的方法来执行内存高效的 rbind。我感谢对此解决方案的任何评论。
这是一个完美的候选人bigmemory
。有关更多信息,请参见该网站。以下是需要考虑的三个使用方面:
separated = TRUE
将列分开。由于我的第三个提示,我没有使用这么多:rbind
。注意:虽然最初的问题涉及数据帧和大内存适用于矩阵,但如果确实有必要,可以轻松地为不同类型的数据创建不同的矩阵,然后组合 RAM 中的对象以创建数据帧。