根据Creating an R dataframe row-by-row,使用rbind附加到data.frame并不理想,因为它会创建整个数据的副本.每次都要画框.我如何在R中积累数据,从而得到data.frame而不产生这种惩罚?中间格式不需要是data.frame.

推荐答案

First approach

我try 访问预分配数据的每个元素.框架:

res <- data.frame(x=rep(NA,1000), y=rep(NA,1000))
tracemem(res)
for(i in 1:1000) {
  res[i,"x"] <- runif(1)
  res[i,"y"] <- rnorm(1)
}

但TraceMe会变得疯狂(例如,每次都会将data.frame复制到一个新地址).

Alternative approach (doesn't work either)

一种方法(不确定是否更快,因为我还没有进行基准测试)是创建一个数据列表.框,然后将它们全部放在一起:

makeRow <- function() data.frame(x=runif(1),y=rnorm(1))
res <- replicate(1000, makeRow(), simplify=FALSE ) # returns a list of data.frames
library(taRifx)
res.df <- stack(res)

不幸的是,在创建列表时,我认为您将很难预先分配.例如:

> tracemem(res)
[1] "<0x79b98b0>"
> res[[2]] <- data.frame()
tracemem[0x79b98b0 -> 0x71da500]: 

换句话说,替换列表中的一个元素会导致列表被复制.我假设整个列表,但可能只是列表中的那个元素.我对R的内存管理细节不太熟悉.

Probably the best approach

与当今许多速度或内存有限的进程一样,最好的方法可能是使用data.table而不是data.frame.由于data.table具有:= assign by reference运算符,因此它可以在不重新复制的情况下进行更新:

library(data.table)
dt <- data.table(x=rep(0,1000), y=rep(0,1000))
tracemem(dt)
for(i in 1:1000) {
  dt[i,x := runif(1)]
  dt[i,y := rnorm(1)]
}
# note no message from tracemem

但正如@MatthewDowle所指出的,set()是在循环中实现这一点的合适方式.这样做会更快:

library(data.table)
n <- 10^6
dt <- data.table(x=rep(0,n), y=rep(0,n))

dt.colon <- function(dt) {
  for(i in 1:n) {
    dt[i,x := runif(1)]
    dt[i,y := rnorm(1)]
  }
}

dt.set <- function(dt) {
  for(i in 1:n) {
    set(dt,i,1L, runif(1) )
    set(dt,i,2L, rnorm(1) )
  }
}

library(microbenchmark)
m <- microbenchmark(dt.colon(dt), dt.set(dt),times=2)

(结果如下所示)

Benchmarking

循环运行10000次后,数据表几乎快了整整一个数量级:

Unit: seconds
          expr        min         lq     median         uq        max
1    test.df()  523.49057  523.49057  524.52408  525.55759  525.55759
2    test.dt()   62.06398   62.06398   62.98622   63.90845   63.90845
3 test.stack() 1196.30135 1196.30135 1258.79879 1321.29622 1321.29622

基准

:=set()的比较:

> m
Unit: milliseconds
          expr       min        lq    median       uq      max
1 dt.colon(dt) 654.54996 654.54996 656.43429 658.3186 658.3186
2   dt.set(dt)  13.29612  13.29612  15.02891  16.7617  16.7617

请注意,这里的n是10^6,而不是上面绘制的基准中的10^5.所以有一个数量级的工作量,结果是以毫秒而不是秒来衡量的.的确令人印象深刻.

R相关问答推荐

检测(并替换)字符串中的数学符号

按R中的组查找相邻列的行累积和的最大值

如何在R中添加截止点到ROC曲线图?

为什么横向页面会导致officeverse中的页码/节头/页脚出现问题?

在R中为马赛克图中的每个字段着色

在R中,如何将变量(A,B和C)拟合在同一列中,如A和B,以及A和C在同一面板中?

将饼图插入条形图

在R中按行按列范围查找最大值的名称

ComplexHEAT:使用COLUMN_SPLIT时忽略COLUMN_ORDER

以字符格式导入的ExcelElectron 表格日期列标题

是否有新方法来更改Facet_WRAP(Ggplot2)中条文本的文本 colored颜色 ?

在带有`R`中的`ggmosaic`的马赛克图中使用图案而不是 colored颜色

如何使用For-R循环在向量中找到一系列数字

减go R中列表的所有唯一元素对

变长向量的矢量化和

删除在R中的write.table()函数期间创建的附加行

Ggplot2如何找到存储在对象中的残差和拟合值?

roxygen2正在处理太多的文件

在shiny 表格中输入的文本在第一次后未更新

如何准确地指出Read_delim所面临的问题?