29

我需要 rbind 两个大数据框。现在我用

df <- rbind(df, df.extension)

但我(几乎)立即耗尽内存。我猜是因为 df 在内存中保存了两次。将来我可能会看到更大的数据帧,所以我需要某种就地 rbind。

所以我的问题是:有没有办法在使用 rbind 时避免内存中的数据重复?

我发现了这个问题,它使用了 SqlLite,但我真的很想避免将硬盘驱动器用作缓存。

4

4 回答 4

19

data.table是你的朋友!

参见http://www.mail-archive.com/r-help@r-project.org/msg175877.html


跟进 nikola 的评论,这里是?rbindlist描述(v1.8.2 中的新内容):

与 相同do.call("rbind",l),但要快得多。

于 2012-08-18T12:49:53.347 回答
18

首先:如果您想安全,请使用您链接到的其他问题的解决方案。由于 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()
于 2011-08-17T14:34:09.833 回答
11

现在我制定了以下解决方案:

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。我感谢对此解决方案的任何评论。

于 2011-08-18T08:43:36.667 回答
5

这是一个完美的候选人bigmemory。有关更多信息,请参见该网站。以下是需要考虑的三个使用方面:

  1. 使用 HD 没问题:到 HD 的内存映射比几乎任何其他访问都快得多,因此您可能看不到任何减速。有时我依赖大于 1TB 的内存映射矩阵,尽管大多数在 6 到 50GB 之间。此外,由于对象一个矩阵,这不需要重写代码以使用该对象的实际开销。
  2. 无论您是否使用文件支持的矩阵,您都可以使用separated = TRUE将列分开。由于我的第三个提示,我没有使用这么多:
  3. 您可以过度分配 HD 空间以允许更大的潜在矩阵大小,但仅加载感兴趣的子矩阵。这种方式没有必要做rbind

注意:虽然最初的问题涉及数据帧和大内存适用于矩阵,但如果确实有必要,可以轻松地为不同类型的数据创建不同的矩阵,然后组合 RAM 中的对象以创建数据帧。

于 2011-08-17T14:57:32.257 回答