我有代码,在一个地方以一个数据帧列表结束,我真的想转换成一个单一的大数据帧。
我从之前的一个问题中得到了一些提示,这个问题试图做一些类似但更复杂的事情。
下面是我开始的一个例子(为了说明,这是非常简化的):
listOfDataFrames <- vector(mode = "list", length = 100)
for (i in 1:100) {
listOfDataFrames[[i]] <- data.frame(a=sample(letters, 500, rep=T),
b=rnorm(500), c=rnorm(500))
}
我目前正在使用这个:
df <- do.call("rbind", listOfDataFrames)
唯一的方法就是用数据来解决问题。表中缺少的是标识符列,以知道数据来自列表中的哪个数据帧。
就像这样:
df_id <- data.table::rbindlist(listOfDataFrames, idcol = TRUE)
idcol参数添加一个列(.id),标识列表中包含的数据帧的来源。结果是这样的:
.id a b c
1 u -0.05315128 -1.31975849
1 b -1.00404849 1.15257952
1 y 1.17478229 -0.91043925
1 q -1.65488899 0.05846295
1 c -1.43730524 0.95245909
1 b 0.56434313 0.93813197
另一个选择是使用plyr函数:
df <- ldply(listOfDataFrames, data.frame)
这比原来的要慢一点:
> system.time({ df <- do.call("rbind", listOfDataFrames) })
user system elapsed
0.25 0.00 0.25
> system.time({ df2 <- ldply(listOfDataFrames, data.frame) })
user system elapsed
0.30 0.00 0.29
> identical(df, df2)
[1] TRUE
我猜是用do。Call ("rbind",…)将是你能找到的最快的方法,除非你能做到(a)使用矩阵而不是data.frames, (b)预分配最终矩阵并赋值给它,而不是增长它。
编辑1:
根据Hadley的评论,下面是rbind的最新版本。从CRAN填充:
> system.time({ df3 <- rbind.fill(listOfDataFrames) })
user system elapsed
0.24 0.00 0.23
> identical(df, df3)
[1] TRUE
这比rbind更简单,并且稍微快一些(这些计时在多次运行中都有效)。据我所知,github上的plyr版本甚至比这个还要快。
为了完整起见,我认为这个问题的答案需要更新。“我猜是用do。Call ("rbind",…)将是你能找到的最快的方法。"2010年5月和之后的一段时间可能是这样,但在2011年9月左右,数据中引入了一个新函数rbindlist。表包版本1.8.2,与注释“这是相同的do.call("rbind",l),但更快”。快了多少?
library(rbenchmark)
benchmark(
do.call = do.call("rbind", listOfDataFrames),
plyr_rbind.fill = plyr::rbind.fill(listOfDataFrames),
plyr_ldply = plyr::ldply(listOfDataFrames, data.frame),
data.table_rbindlist = as.data.frame(data.table::rbindlist(listOfDataFrames)),
replications = 100, order = "relative",
columns=c('test','replications', 'elapsed','relative')
)
test replications elapsed relative
4 data.table_rbindlist 100 0.11 1.000
1 do.call 100 9.39 85.364
2 plyr_rbind.fill 100 12.08 109.818
3 plyr_ldply 100 15.14 137.636