代码之家  ›  专栏  ›  技术社区  ›  JD Long

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

  •  262
  • JD Long  · 技术社区  · 14 年前

    我有一个代码,在某个地方最后得到一个数据帧列表,我真的想转换成一个大数据帧。

    我从一个 earlier question 它试图做一些类似但更复杂的事情。

    下面是一个我从什么开始的例子(这是非常简单的说明):

    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)
    
    9 回复  |  直到 7 年前
        1
  •  35
  •   joeklieg    7 年前

    使用dplyr包中的bind_rows():

    bind_rows(list_of_dataframes, .id = "column_label")
    
        2
  •  180
  •   Shane    14 年前

    另一种选择是使用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)使用矩阵而不是数据帧,(b)预先分配最终矩阵并分配给它,而不是增加它。

    编辑1 :

    根据哈德利的评论,这里是 rbind.fill 来自克兰:

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

    这比RBind更容易,速度也稍微快一点(这些计时可以在多次运行中保持)。据我所知, the version of plyr on github 比这还要快。

        3
  •  95
  •   Henrik plannapus    9 年前

    为了完整起见,我认为这个问题的答案需要更新。”我猜是用 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')
      ) 
    

                      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
    
        4
  •  52
  •   mindlessgreen    7 年前

    <>代码:

    库(微基准)
    
    dflist<-矢量(长度=10,模式=list)
    为(我在1:100)
    {
    dflist[[i]]<-data.frame(a=runif(n=260),b=runif(n=260),
    C=rep(字母,10),D=rep(字母,10)
    }
    
    
    mb<-微基准(
    plyr::r结束填充(dflist),
    dpylr::绑定_行(dflist),
    data.table::rBindList(dfList),
    plyr::ldply(dflist,data.frame)
    do.call(“rbind”,dflist),
    次数=1000)
    
    ggplot2::自动批处理(MB)
    < /代码> 
    
    

    会话:

    r version 3.3.0(2016-05-03)
    平台:x86 U 64-W64-MingW32/X64(64位)
    运行环境:Windows 7 x64(内部版本7601)Service Pack 1
    
    >包装版本(“PLYR”)
    [1]__1.8.4_
    >包装版本(“dplyr”)
    [1]__0.5.0_
    >包版本(“data.table”)
    [1]__1.9.6_
    < /代码> 
    
    

    update: 重新运行2018年1月31日。在同一台计算机上运行。软件包的新版本。为种子爱好者添加种子。

    set.seed(21)
    库(微基准)
    
    dflist<-矢量(长度=10,模式=list)
    为(我在1:100)
    {
    dflist[[i]]<-data.frame(a=runif(n=260),b=runif(n=260),
    C=rep(字母,10),D=rep(字母,10)
    }
    
    
    mb<-微基准(
    plyr::r结束填充(dflist),
    dpylr::绑定_行(dflist),
    data.table::rBindList(dfList),
    plyr::ldply(dflist,data.frame)
    do.call(“rbind”,dflist),
    次数=1000)
    
    ggplot2::autoplot(mb)+theme_bw()。
    
    
    R版本3.4.0(2017-04-21)
    平台:x86 U 64-W64-MingW32/X64(64位)
    运行环境:Windows 7 x64(内部版本7601)Service Pack 1
    
    >包装版本(“PLYR”)
    [1]__1.8.4_
    >包装版本(“dplyr”)
    [1]__0.7.2_
    >包版本(“data.table”)
    [1]__1.10.4_
    < /代码> 
    

    代码:

    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)
    

    会议:

    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’
    

    更新: 重新运行2018年1月31日。在同一台计算机上运行。软件包的新版本。为种子爱好者添加种子。

    enter image description here

    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’
    
        5
  •  44
  •   TheVTM    9 年前

    也有 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
    
        6
  •  12
  •   yeedle    7 年前

    这是另一种方法(将其添加到答案中,因为 reduce 是一个非常有效的功能性工具,作为循环的替代品常常被忽视。在这种特殊情况下,这两种方法都没有明显快于do.call)

    使用基R:

    df <- Reduce(rbind, listOfDataFrames)
    

    或者,使用tidyverse:

    library(tidyverse) # or, library(dplyr); library(purrr)
    df <- listOfDataFrames %>% reduce(bind_rows)
    
        7
  •  11
  •   Nick    7 年前

    如何在tidyverse中完成:

    df.dplyr.purrr <- listOfDataFrames %>% map_df(bind_rows)
    
        8
  •  7
  •   Nova    7 年前

    一个更新的视频为那些想比较最近的一些答案(我想比较purr与dplyr解决方案)。基本上,我把来自@thevtm和@rmf的答案结合起来。

    <>代码:

    库(微基准)
    库(data.table)
    图书馆(tidyverse)
    
    dflist<-矢量(长度=10,模式=list)
    为(我在1:100)
    {
    dflist[[i]]<-data.frame(a=runif(n=260),b=runif(n=260),
    C=rep(字母,10),D=rep(字母,10)
    }
    
    
    mb<-微基准(
    dpylr::绑定_行(dflist),
    data.table::rBindList(dfList),
    purr::map_df(dflist,bind_rows),
    do.call(“rbind”,dflist),
    次数=500)
    
    ggplot2::自动批处理(MB)
    < /代码> 
    
    

    会话信息:

    sessioninfo())
    R版本3.4.1(2017-06-30)
    平台:x86 U 64-W64-MingW32/X64(64位)
    运行环境:Windows 7 x64(内部版本7601)Service Pack 1
    < /代码> 
    
    

    包版本:

    包版本(“tidyverse”)。 [1]__1.1.1_ >包版本(“data.table”) [1]__1.10.0_ < /代码> 来自@thevtm和@rmf的ed答案。

    enter image description here

    代码:

    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)
    

    会话信息:

    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
    

    包版本:

    > packageVersion("tidyverse")
    [1] ‘1.1.1’
    > packageVersion("data.table")
    [1] ‘1.10.0’
    
        9
  •  6
  •   f0nzie    7 年前

    唯一的解决方案 data.table are missing是要知道数据来自列表中哪个数据帧的标识符列。

    像这样:

    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