将数据帧列表转换为一个数据帧

JD *_*ong 297 r list dataframe

我有一些代码,在一个地方最终得到一个数据帧列表,我真的想转换为一个大数据帧.

我从之前的一个问题中得到了一些指示,这个问题试图做类似但更复杂的事情.

这是我开始的一个例子(为了说明,这是非常简化的):

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))
}
Run Code Online (Sandbox Code Playgroud)

我目前正在使用这个:

  df <- do.call("rbind", listOfDataFrames)
Run Code Online (Sandbox Code Playgroud)

Sha*_*ane 181

另一个选择是使用plyr函数:

df <- ldply(listOfDataFrames, data.frame)
Run Code Online (Sandbox Code Playgroud)

这比原来慢一点:

> 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
Run Code Online (Sandbox Code Playgroud)

我的猜测是,do.call("rbind", ...)除非你可以做一些像(a)使用矩阵而不是data.frames和(b)预先分配最终矩阵并分配给它而不是增长它,所以使用将是最快的方法. .

编辑1:

根据Hadley的评论,这是rbind.fillCRAN 的最新版本:

> system.time({ df3 <- rbind.fill(listOfDataFrames) })
   user  system elapsed 
   0.24    0.00    0.23 
> identical(df, df3)
[1] TRUE
Run Code Online (Sandbox Code Playgroud)

这比rbind更容易,并且速度稍快(这些时间在多次运行中保持不变).据我了解,on github 的版本plyr甚至比这更快.

  • 最新版本的plyr中的rbind.fill比do.call和rbind快得多 (26认同)
  • 重塑中也有`melt.list`(2) (4认同)
  • 根据[rmd的回答](/sf/answers/2695677981/),`bind_rows()`是最快的,我认为它是最直接的。它还具有添加[id列]的功能(/sf/answers/3431194581/) (2认同)

and*_*kos 106

为了完整起见,我认为这个问题的答案需要更新."我的猜测是使用do.call("rbind", ...)将是你发现的最快的方法......"2010年5月和之后的某个时间可能是这样,但是在2011年9月左右rbindlist,data.table包版本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')
  ) 
Run Code Online (Sandbox Code Playgroud)
                  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
Run Code Online (Sandbox Code Playgroud)

  • 还有一个完整性:`dplyr :: rbind_all(listOfDataFrames)`也可以做到这一点. (10认同)
  • 非常感谢你 - 因为我的数据集过于庞大而无法完成一堆长而融化的数据帧,所以我正在把头发拉出来.无论如何,通过使用你的`rbindlist`建议,我得到了令人难以置信的加速. (3认同)
  • 有没有相当于`rbindlist`但是按列附加数据框?像cbindlist这样的东西? (2认同)
  • @ rafa.pereira最近有一个功能请求:[添加功能cbindlist](https://github.com/Rdatatable/data.table/issues/2576) (2认同)

小智 84

使用dplyr包中的bind_rows():

bind_rows(list_of_dataframes, .id = "column_label")
Run Code Online (Sandbox Code Playgroud)

  • 由于它是2018年,并且`dplyr`既快速又可靠,可以使用,因此我将其更改为可接受的答案。岁月,他们飞逝! (8认同)
  • 好的解决方案 `.id ="column_label"`根据列表元素名称添加唯一的行名称. (4认同)
  • 奇怪,但它不能与 tibbles 列表一起正常工作 (2认同)

rmf*_*rmf 66

绑定积

码:

library(microbenchmark)

dflist <- vector(length=10,mode="list")
for(i in 1:100)
{
  dflist[[i]] <- data.frame(a=runif(n=260),b=runif(n=260),
                            c=rep(LETTERS,10),d=rep(LETTERS,10))
}


mb <- microbenchmark(
plyr::rbind.fill(dflist),
dplyr::bind_rows(dflist),
data.table::rbindlist(dflist),
plyr::ldply(dflist,data.frame),
do.call("rbind",dflist),
times=1000)

ggplot2::autoplot(mb)
Run Code Online (Sandbox Code Playgroud)

会议:

R version 3.3.0 (2016-05-03)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

> packageVersion("plyr")
[1] ‘1.8.4’
> packageVersion("dplyr")
[1] ‘0.5.0’
> packageVersion("data.table")
[1] ‘1.9.6’
Run Code Online (Sandbox Code Playgroud)

更新:重新运行2018年1月31日.跑在同一台电脑上.新版本的软件包.为种子爱好者添加种子.

在此输入图像描述

set.seed(21)
library(microbenchmark)

dflist <- vector(length=10,mode="list")
for(i in 1:100)
{
  dflist[[i]] <- data.frame(a=runif(n=260),b=runif(n=260),
                            c=rep(LETTERS,10),d=rep(LETTERS,10))
}


mb <- microbenchmark(
  plyr::rbind.fill(dflist),
  dplyr::bind_rows(dflist),
  data.table::rbindlist(dflist),
  plyr::ldply(dflist,data.frame),
  do.call("rbind",dflist),
  times=1000)

ggplot2::autoplot(mb)+theme_bw()


R version 3.4.0 (2017-04-21)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

> packageVersion("plyr")
[1] ‘1.8.4’
> packageVersion("dplyr")
[1] ‘0.7.2’
> packageVersion("data.table")
[1] ‘1.10.4’
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案.我运行相同的东西(相同的操作系统,相同的包,不同的随机化,因为你没有`set.seed`),但看到了最坏情况性能的一些差异.`rbindlist`实际上在我的结果中有最好的最坏情况和最好的典型情况 (2认同)

The*_*VTM 47

也有bind_rows(x, ...)dplyr.

> system.time({ df.Base <- do.call("rbind", listOfDataFrames) })
   user  system elapsed 
   0.08    0.00    0.07 
> 
> system.time({ df.dplyr <- as.data.frame(bind_rows(listOfDataFrames)) })
   user  system elapsed 
   0.01    0.00    0.02 
> 
> identical(df.Base, df.dplyr)
[1] TRUE
Run Code Online (Sandbox Code Playgroud)


yee*_*dle 13

这是另一种方法可以做到(只是将它添加到答案中,因为它reduce是一个非常有效的功能工具,经常被忽略作为循环的替代.在这种特殊情况下,这些都不比do.call快得多)

使用基数R:

df <- Reduce(rbind, listOfDataFrames)
Run Code Online (Sandbox Code Playgroud)

或者,使用tidyverse:

library(tidyverse) # or, library(dplyr); library(purrr)
df <- listOfDataFrames %>% reduce(bind_rows)
Run Code Online (Sandbox Code Playgroud)


Nic*_*ick 11

如何在tidyverse中完成:

df.dplyr.purrr <- listOfDataFrames %>% map_df(bind_rows)
Run Code Online (Sandbox Code Playgroud)

  • 如果`bind_rows`可以获取数据帧列表,为什么还要使用“ map”? (2认同)

Nov*_*ova 9

想要比较一些最近答案的人的更新视觉(我想比较purrr到dplyr解决方案).基本上我结合了@TheVTM和@rmf的答案.

在此输入图像描述

码:

library(microbenchmark)
library(data.table)
library(tidyverse)

dflist <- vector(length=10,mode="list")
for(i in 1:100)
{
  dflist[[i]] <- data.frame(a=runif(n=260),b=runif(n=260),
                            c=rep(LETTERS,10),d=rep(LETTERS,10))
}


mb <- microbenchmark(
  dplyr::bind_rows(dflist),
  data.table::rbindlist(dflist),
  purrr::map_df(dflist, bind_rows),
  do.call("rbind",dflist),
  times=500)

ggplot2::autoplot(mb)
Run Code Online (Sandbox Code Playgroud)

会话信息:

sessionInfo()
R version 3.4.1 (2017-06-30)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1
Run Code Online (Sandbox Code Playgroud)

包版本:

> packageVersion("tidyverse")
[1] ‘1.1.1’
> packageVersion("data.table")
[1] ‘1.10.0’
Run Code Online (Sandbox Code Playgroud)


f0n*_*zie 7

data.table缺少解决方案的唯一事情是标识符列,以了解数据来自列表中的哪个数据帧.

像这样的东西:

df_id <- data.table::rbindlist(listOfDataFrames, idcol = TRUE)
Run Code Online (Sandbox Code Playgroud)

idcol参数添加一个column(.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  
Run Code Online (Sandbox Code Playgroud)