提问



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


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


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

最佳参考


假设您的列表列表被调用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)

其它参考1


随着rbind


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


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

其它参考2


您可以使用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将矩阵转换为数据帧。

其它参考4


假设你的名单被称为L


data.frame(Reduce(rbind, L))

其它参考5


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


如果 真的 想要转换回data.frame,请as.data.frame(DT)

其它参考6


tibble包有一个函数enframe(),它通过将嵌套的list对象强制转换为嵌套的tibble(整齐的数据框)对象来解决这个问题。这是R for Data Science的一个简短例子:[63]


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()将输出排除在单级整洁数据框中,该数据框有两列(一组用于组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>

其它参考7


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()中完成这一切。

其它参考8


更多答案,以及这个问题答案的时间安排:
将列表强制转换为数据框的最有效方法是什么?


最快的方法是,不会产生带有列表而不是列的向量的数据框(来自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**])))

其它参考9


对于深层嵌套列表的一般情况,具有3个或更多级别,例如从嵌套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

其它参考10


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


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

其它参考11


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


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

其它参考12


这最终对我有用:


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

其它参考13


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

其它参考14


此方法使用tidyverse包( purrr )。


列表:


x <- as.list(mtcars)


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


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

其它参考15


根据列表的结构,有一些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

其它参考16



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



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