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

Seb*_*ian 28 r dataframe rbind

我需要rbind两个大数据帧.现在我用

df <- rbind(df, df.extension)
Run Code Online (Sandbox Code Playgroud)

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

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

我发现这个问题,使用SqlLite,但我真的想避免使用硬盘作为缓存.

Ari*_*man 18

data.table 是你的朋友!

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


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

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

  • 另外,`data.table`的1.8.2版本有`rbindlist`功能,在那里会有所帮助. (5认同)
  • 请注意,rbindlist不会检查列名,这是它更快的部分原因.`dplyr`的rbind_all稍慢,但对列名检查有效,所以有时它会更有用. (2认同)

Jor*_*eys 17

首先:如果您想要安全,请使用您链接的其他问题的解决方案.由于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"
Run Code Online (Sandbox Code Playgroud)

它会删除你实际拥有的rownames(你可以重建它们,但检查重复的rownames!).它也没有执行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()
Run Code Online (Sandbox Code Playgroud)


Seb*_*ian 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)
Run Code Online (Sandbox Code Playgroud)

现在我的内存不足.我认为这是因为我存储

object.size(df) + 2 * object.size(df.extension)
Run Code Online (Sandbox Code Playgroud)

而rbind R则需要

object.size(rbind(df,df.extension)) + object.size(df) + object.size(df.extension). 
Run Code Online (Sandbox Code Playgroud)

之后,我使用

rm(df.extension)
gc(reset=TRUE)
Run Code Online (Sandbox Code Playgroud)

释放我不再需要的记忆.

这解决了我现在的问题,但我觉得有一种更先进的方法来做一个内存有效的rbind.我感谢对此解决方案的任何评论.


Ite*_*tor 5

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

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

注意:虽然解决数据帧和bigmemory的原始问题适用于矩阵,但是可以轻松地为不同类型的数据创建不同的矩阵,然后将这些对象组合在RAM中以创建数据帧(如果确实有必要的话).