内存有效替代rbind-in-place rbind?

时间:2011-08-17 13:50:16

标签: r dataframe rbind

我需要重新绑定两个大数据帧。现在我用

df <- rbind(df, df.extension)

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

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

我找到了这个使用SqlLite的question,但我真的想避免将硬盘用作缓存。

4 个答案:

答案 0 :(得分:18)

data.table是你的朋友!

C.f。 http://www.mail-archive.com/r-help@r-project.org/msg175877.html


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

  

do.call("rbind",l)相同,但速度更快。

答案 1 :(得分:17)

首先:如果您想要安全,请使用您链接的其他问题的解决方案。由于R是按值调用,因此忘记了不会将数据帧复制到内存中的“就地”方法。

一个不可取的方法可以节省相当多的内存,就是假装你的数据帧是列表,用for-loop强制列表(应用会吃掉像地狱一样的内存)并让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"

它会删除你实际拥有的rownames(你可以重建它们,但检查重复的rownames!)。它也没有执行rbind中包含的所有其他测试。

在我的测试中节省了大约一半的内存,在我的测试中,dtfcomb和dtf都相等。红色框是rbind,黄色框是我基于列表的方法。

enter image description here

测试脚本:

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()

答案 2 :(得分:10)

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

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

答案 3 :(得分:5)

这是bigmemory的完美候选人。有关详细信息,请参阅the site。以下是需要考虑的三个使用方面:

  1. 可以使用HD:内存映射到HD比几乎任何其他访问快得多,因此您可能看不到任何减速。有时我依赖&gt; 1TB的内存映射矩阵,但大多数介于6到50GB之间。此外,由于对象一个矩阵,因此不需要为了使用该对象而重写代码的实际开销。
  2. 无论您是否使用文件支持的矩阵,都可以使用separated = TRUE将列分开。我没有用过这么多,因为我的第三个提示:
  3. 您可以过度分配HD空间以允许更大的潜在矩阵大小,但只加载感兴趣的子矩阵。这样就不需要rbind
  4. 注意:尽管解决数据帧和bigmemory的原始问题适用于矩阵,但是可以轻松地为不同类型的数据创建不同的矩阵,然后将这些对象组合在RAM中以创建数据帧(如果确实有必要的话)。