data.frame方法最有效的列表?

刚刚和同事谈了这件事情,我们认为值得看看SO土地上的人不得不说什么。 假设我有一个包含N个元素的列表,其中每个元素都是一个长度为X的向量。现在假设我想将其转换为一个data.frame。 与R中的大多数事物一样,有许多方法可以将谚语猫皮肤化,比如as.dataframe ,使用plyr软件包,与cbind结合使用do.call ,预先分配DF并填充它们等等。

提出的问题是当N或X(在我们的例子中是X)变得非常大时会发生什么。 有效的猫(特别是在记忆方面)的本质是否有一种猫皮方法明显优越?

由于data.frame已经是一个列表,并且您知道每个列表元素的长度(X)是相同的,所以最快的事情可能是更新classrow.names属性:

 set.seed(21) n <- 1e6 x <- list(x=rnorm(n), y=rnorm(n), z=rnorm(n)) x <- c(x,x,x,x,x,x) system.time(a <- as.data.frame(x)) system.time(b <- do.call(data.frame,x)) system.time({ d <- x # Skip 'c' so Joris doesn't down-vote me! ;-) class(d) <- "data.frame" rownames(d) <- 1:n names(d) <- make.unique(names(d)) }) identical(a, b) # TRUE identical(b, d) # TRUE 

更新 – 这比创buildd

 system.time({ e <- x attr(e, "row.names") <- c(NA_integer_,n) attr(e, "class") <- "data.frame" attr(e, "names") <- make.names(names(e), unique=TRUE) }) identical(d, e) # TRUE 

更新2 – 我忘记了内存消耗。 最后的更新使e两个副本。 使用attributesfunction将其减less到只有一个副本。

 set.seed(21) f <- list(x=rnorm(n), y=rnorm(n), z=rnorm(n)) f <- c(f,f,f,f,f,f) tracemem(f) system.time({ # makes 2 copies attr(f, "row.names") <- c(NA_integer_,n) attr(f, "class") <- "data.frame" attr(f, "names") <- make.names(names(f), unique=TRUE) }) set.seed(21) g <- list(x=rnorm(n), y=rnorm(n), z=rnorm(n)) g <- c(g,g,g,g,g,g) tracemem(g) system.time({ # only makes 1 copy attributes(g) <- list(row.names=c(NA_integer_,n), class="data.frame", names=make.names(names(g), unique=TRUE)) }) identical(f,g) # TRUE 

这似乎需要一个data.tablebuild议,因为需要大数据集的效率。 值得注意的是setattr通过引用设置,不复制

 library(data.table) set.seed(21) n <- 1e6 h <- list(x=rnorm(n), y=rnorm(n), z=rnorm(n)) h <- c(h,h,h,h,h,h) tracemem(h) system.time({h <- as.data.table(h) setattr(h, 'names', make.names(names(h), unique=T))}) 

as.data.table ,但是做一个副本。


编辑 – 不复制版本

使用@ MatthewDowle的build议setattr(h,'class','data.frame')将通过引用转换为data.frame( 没有副本

 set.seed(21) n <- 1e6 i <- list(x=rnorm(n), y=rnorm(n), z=rnorm(n)) i <- c(i,i,i,i,i,i) tracemem(i) system.time({ setattr(i, 'class', 'data.frame') setattr(i, "row.names", c(NA_integer_,n)) setattr(i, "names", make.names(names(i), unique=TRUE)) })