首页 文章

R - 列表到数据框

提问于
浏览
409

我有一个嵌套的数据列表 . 它的长度为132,每个项目都是长度为20的列表 . 是否有一种快速的方法将此结构转换为具有132行和20列数据的数据框?

以下是一些可用的示例数据:

l <- replicate(
  132,
  list(sample(letters, 20)),
  simplify = FALSE
)

17 回答

  • 46

    假设您的列表列表名为 l

    df <- data.frame(matrix(unlist(l), nrow=132, byrow=T))
    

    以上将所有字符列转换为因子,为避免这种情况,您可以向data.frame()调用添加一个参数:

    df <- data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE)
    
  • 8

    您可以使用 plyr 包 . 例如,表单的嵌套列表

    l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
          , b = list(var.1 = 4, var.2 = 5, var.3 = 6)
          , c = list(var.1 = 7, var.2 = 8, var.3 = 9)
          , d = list(var.1 = 10, var.2 = 11, var.3 = 12)
          )
    

    现在长度为4, l 中的每个列表都包含另一个长度为3的列表 . 现在你可以运行了

    library (plyr)
      df <- ldply (l, data.frame)
    

    并且应该得到与答案@Marek和@nico相同的结果 .

  • -3

    data.frame(t(sapply(mylistlist,c)))

    sapply 将其转换为矩阵 . data.frame 将矩阵转换为数据帧 .

  • 79

    随着 rbind

    do.call(rbind.data.frame, your_list)
    

    编辑:以前的版本返回 listlist 而不是向量(如评论中指出的@IanSudbery) .

  • 4

    test1 < - list(c(a ='a',b ='b',c ='c'),c(a ='d',b ='e',c ='f'))as . data.frame(test1)abc 1 abc 2 def

    test2 < - list(c('a','b','c'),c(a ='d',b ='e',c ='f'))

    as.data.frame(test2)a b c 1 a b c 2 d e f

    test3 < - list('Row1'= c(a ='a',b ='b',c ='c'),'row2'= c(a ='d',var2 ='e',var3 = 'F'))

    as.data.frame(test3)a b c var2 var3 Row1 a b c Row2 d e f

  • 287

    这最终对我有用:

    do.call("rbind", lapply(S1, as.data.frame))

  • 382

    Reshape2产生的输出与上面的plyr示例相同:

    library(reshape2)
    l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
              , b = list(var.1 = 4, var.2 = 5, var.3 = 6)
              , c = list(var.1 = 7, var.2 = 8, var.3 = 9)
              , d = list(var.1 = 10, var.2 = 11, var.3 = 12)
    )
    l <- melt(l)
    dcast(l, L1 ~ L2)
    

    收益率:

    L1 var.1 var.2 var.3
    1  a     1     2     3
    2  b     4     5     6
    3  c     7     8     9
    4  d    10    11    12
    

    如果你几乎没有像素,你可以在1行w / recast()中完成所有这些操作 .

  • 15
    l <- replicate(10,list(sample(letters, 20)))
    a <-lapply(l[1:10],data.frame)
    do.call("cbind", a)
    
  • 113

    更多答案,以及这个问题答案的时间安排:What is the most efficient way to cast a list as a data frame?

    最快的方法是,不会产生带有列表而不是列的向量的数据帧(来自Martin Morgan的答案):

    l <- list(list(col1="a",col2=1),list(col1="b",col2=2))
    f = function(x) function(i) unlist(lapply(x, `[[`, i), use.names=FALSE)
    as.data.frame(Map(f(l), names(l[[1]])))
    
  • 54

    延伸@ Marek的答案:如果你想避免字符串被转化为因素和效率不是一个值得关注的尝试

    do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
    
  • 4

    假设您的列表名为 L

    data.frame(Reduce(rbind, L))
    
  • 3

    有时您的数据可能是相同长度的矢量列表的列表 .

    lolov = list(list(c(1,2,3),c(4,5,6)), list(c(7,8,9),c(10,11,12),c(13,14,15)) )
    

    (内部向量也可以是列表,但我正在简化以使其更容易阅读) .

    然后您可以进行以下修改 . 请记住,您可以一次取消一个级别:

    lov = unlist(lolov, recursive = FALSE )
    > lov
    [[1]]
    [1] 1 2 3
    
    [[2]]
    [1] 4 5 6
    
    [[3]]
    [1] 7 8 9
    
    [[4]]
    [1] 10 11 12
    
    [[5]]
    [1] 13 14 15
    

    现在使用其他答案中提到的您最喜欢的方法:

    library(plyr)
    >ldply(lov)
      V1 V2 V3
    1  1  2  3
    2  4  5  6
    3  7  8  9
    4 10 11 12
    5 13 14 15
    
  • 6

    根据列表的结构,有一些 tidyverse 选项可以很好地处理不等长度列表:

    l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
            , b = list(var.1 = 4, var.2 = 5)
            , c = list(var.1 = 7, var.3 = 9)
            , d = list(var.1 = 10, var.2 = 11, var.3 = NA))
    
    df <- dplyr::bind_rows(l)
    df <- purrr::map_df(l, dplyr::bind_rows)
    df <- purrr::map_df(l, ~.x)
    
    # all create the same data frame:
    # A tibble: 4 x 3
      var.1 var.2 var.3
      <dbl> <dbl> <dbl>
    1     1     2     3
    2     4     5    NA
    3     7    NA     9
    4    10    11    NA
    

    您还可以混合矢量和数据框:

    library(dplyr)
    bind_rows(
      list(a = 1, b = 2),
      data_frame(a = 3:4, b = 5:6),
      c(a = 7)
    )
    
    # A tibble: 4 x 2
          a     b
      <dbl> <dbl>
    1     1     2
    2     3     5
    3     4     6
    4     7    NA
    
  • 8

    tibble 包有一个函数 enframe() ,它通过将嵌套的 list 对象强制转换为嵌套的 tibble ("tidy"数据帧)对象来解决此问题 . 以下是R for Data Science的简短示例:

    x <- list(
        a = 1:5,
        b = 3:4, 
        c = 5:6
    ) 
    
    df <- enframe(x)
    df
    #> # A tibble: 3 × 2
    #>    name     value
    #>   <chr>    <list>
    #>    1     a <int [5]>
    #>    2     b <int [2]>
    #>    3     c <int [2]>
    

    由于列表中有多个嵌套 l ,因此可以使用 unlist(recursive = FALSE) 删除不必要的嵌套以获取单个分层列表,然后传递给 enframe() . 我使用 tidyr::unnest() 来取消输出到单级"tidy"数据框,它有两列(一组用于组 name ,一组用于组 value 的观察) . 如果您想要宽的列,可以使用 add_column() 添加一个列,只重复值的顺序132次 . 然后只是 spread() 的值 .

    library(tidyverse)
    
    l <- replicate(
        132,
        list(sample(letters, 20)),
        simplify = FALSE
    )
    
    l_tib <- l %>% 
        unlist(recursive = FALSE) %>% 
        enframe() %>% 
        unnest()
    l_tib
    #> # A tibble: 2,640 x 2
    #>     name value
    #>    <int> <chr>
    #> 1      1     d
    #> 2      1     z
    #> 3      1     l
    #> 4      1     b
    #> 5      1     i
    #> 6      1     j
    #> 7      1     g
    #> 8      1     w
    #> 9      1     r
    #> 10     1     p
    #> # ... with 2,630 more rows
    
    l_tib_spread <- l_tib %>%
        add_column(index = rep(1:20, 132)) %>%
        spread(key = index, value = value)
    l_tib_spread
    #> # A tibble: 132 x 21
    #>     name   `1`   `2`   `3`   `4`   `5`   `6`   `7`   `8`   `9`  `10`  `11`
    #> *  <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
    #> 1      1     d     z     l     b     i     j     g     w     r     p     y
    #> 2      2     w     s     h     r     i     k     d     u     a     f     j
    #> 3      3     r     v     q     s     m     u     j     p     f     a     i
    #> 4      4     o     y     x     n     p     i     f     m     h     l     t
    #> 5      5     p     w     v     d     k     a     l     r     j     q     n
    #> 6      6     i     k     w     o     c     n     m     b     v     e     q
    #> 7      7     c     d     m     i     u     o     e     z     v     g     p
    #> 8      8     f     s     e     o     p     n     k     x     c     z     h
    #> 9      9     d     g     o     h     x     i     c     y     t     f     j
    #> 10    10     y     r     f     k     d     o     b     u     i     x     s
    #> # ... with 122 more rows, and 9 more variables: `12` <chr>, `13` <chr>,
    #> #   `14` <chr>, `15` <chr>, `16` <chr>, `17` <chr>, `18` <chr>,
    #> #   `19` <chr>, `20` <chr>
    
  • 2

    data.table 具有 rbindlist 函数,它是 do.call(rbind, list(...)) 的超快实现 .

    它可以采用 listsdata.framesdata.tables 列表作为输入 .

    library(data.table)
    ll <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
      , b = list(var.1 = 4, var.2 = 5, var.3 = 6)
      , c = list(var.1 = 7, var.2 = 8, var.3 = 9)
      , d = list(var.1 = 10, var.2 = 11, var.3 = 12)
      )
    
    DT <- rbindlist(ll)
    

    这将返回 data.table 继承自 data.frame .

    如果 really 想要转换回data.frame,请使用 as.data.frame(DT)

  • 18

    对于深层嵌套列表的一般情况 with 3 or more levels ,就像从嵌套JSON获得的那样:

    {
    "2015": {
      "spain": {"population": 43, "GNP": 9},
      "sweden": {"population": 7, "GNP": 6}},
    "2016": {
      "spain": {"population": 45, "GNP": 10},
      "sweden": {"population": 9, "GNP": 8}}
    }
    

    考虑 melt() 的方法首先将嵌套列表转换为高格式:

    myjson <- jsonlite:fromJSON(file("test.json"))
    tall <- reshape2::melt(myjson)[, c("L1", "L2", "L3", "value")]
        L1     L2         L3 value
    1 2015  spain population    43
    2 2015  spain        GNP     9
    3 2015 sweden population     7
    4 2015 sweden        GNP     6
    5 2016  spain population    45
    6 2016  spain        GNP    10
    7 2016 sweden population     9
    8 2016 sweden        GNP     8
    

    然后是 dcast() 然后再次变宽到一个整洁的数据集,其中每个变量形成一个列,每个观察形成一行:

    wide <- reshape2::dcast(tall, L1+L2~L3) 
    # left side of the formula defines the rows/observations and the 
    # right side defines the variables/measurements
        L1     L2 GNP population
    1 2015  spain   9         43
    2 2015 sweden   6          7
    3 2016  spain  10         45
    4 2016 sweden   8          9
    
  • 8

    此方法使用 tidyverse 包( purrr ) .

    列表:

    x <- as.list(mtcars)
    

    将其转换为数据框(更具体地说是 tibble ):

    library(purrr)
    map_df(x, ~.x)
    

相关问题