R - 列表到数据框

Bti*_*rt3 470 r list dataframe

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

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

l <- replicate(
  132,
  list(sample(letters, 20)),
  simplify = FALSE
)
Run Code Online (Sandbox Code Playgroud)

Mar*_*rek 436

rbind

do.call(rbind.data.frame, your_list)
Run Code Online (Sandbox Code Playgroud)

编辑:以前的版本回报data.framelist的载体,而不是(如@IanSudbery在评论中指出).

  • @eykanal`do.call`将`your_list`的元素作为`rbind`的参数传递.它相当于`rbind(your_list [[1]],your_list [[2]],your_list [[3]],.....,your_list [[your_list]的长度])`. (26认同)
  • 这个方法似乎返回了正确的对象,但是在检查对象时,你会发现列是列表而不是向量,如果你不期望它可能会导致问题. (12认同)
  • 为什么这有效但是`rbind(your_list)`返回1x32列表矩阵? (4认同)
  • @FrankWANG但是这个方法并不是针对null的情况而设计的.要求`your_list`包含相同大小的向量.`NULL`的长度为0,因此它应该失败. (3认同)
  • 该方法遭受空状态的困扰。 (2认同)

nic*_*ico 344

假设您的列表列表被调用l:

df <- data.frame(matrix(unlist(l), nrow=length(l), byrow=T))
Run Code Online (Sandbox Code Playgroud)

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

df <- data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE)
Run Code Online (Sandbox Code Playgroud)

  • 如果您的数据不是同一类型,请在此处小心.通过矩阵意味着所有数据都将被强制转换为通用类型.即如果你有一列字符数据和一列数字数据,数字数据将被矩阵()强制转换为字符串,然后由data.frame()进行分解. (95认同)
  • 如果您有字符数据类型,请注意 - data.frame会将其转换为因子. (4认同)
  • 这个答案已经很老了,但也许这对其他人有用(@N.Varela 也要求它):如果你想保留列表元素名称,请尝试 ```names(df) &lt;- names(unlist(l[ 1]))``` 使用上述命令后。 (4认同)
  • @nico有没有办法将列表元素名称保留为df中的colnames或rownames? (3认同)
  • @Dave:对我有用……见这里 http://www.r-fiddle.org/#/fiddle?id=y8DW7lqL&amp;version=3 (2认同)

mro*_*opa 127

你可以使用这个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)
      )
Run Code Online (Sandbox Code Playgroud)

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

  library (plyr)
  df <- ldply (l, data.frame)
Run Code Online (Sandbox Code Playgroud)

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

  • Imho是最好的答案.它返回一个诚实的data.frame.所有数据类型(字符,数字等)都已正确转换.如果列表具有不同的数据类型,则它们将全部转换为具有"矩阵"方法的字符. (11认同)
  • 很好的答案.我能解释一下这是怎么回事吗?它只是为每个列表条目返回一个数据框? (7认同)
  • plyr 已被弃用,取而代之的是 dplyr (2认同)

Ale*_*own 90

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

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

  • 迄今为止最好的答案!其他解决方案都没有获得正确的类型/列名称.谢谢! (17认同)
  • 这不会生成列表的data.frame吗? (3认同)
  • 你想让 `c` 在这里扮演什么角色,列表数据的一个实例?哦等等,c 是连接函数吧?对@mnel 对 c 的使用感到困惑。我也同意@dchandler,在我的用例中,获得正确的列名是一个有价值的需求。出色的解决方案。 (2认同)

jde*_*eng 64

假设你的名单被调用L,

data.frame(Reduce(rbind, L))
Run Code Online (Sandbox Code Playgroud)

  • 好一个!@Alex Brown的解决方案与您的解决方案有一点不同,因为某些原因,您的路由会产生以下警告消息:`警告消息:在data.row.names(row.names,rowsi,i)中:某些row.names重复:3,4 - > row.names NOT used' (2认同)
  • 除非列表中只有一个元素,否则效果很好:`data.frame(Reduce(rbind,list(c('col1','col2')))))`产生一个具有** 2行,1列的数据帧*(我希望1行2列) (2认同)

mne*_*nel 56

该软件包data.table具有rbindlist一个超快速实现的功能do.call(rbind, list(...)).

它可以采取的一个列表 lists,data.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)
Run Code Online (Sandbox Code Playgroud)

这将返回一个data.table继承data.frame.

如果你真的想转换回data.frame使用as.data.frame(DT)


Mat*_*cho 30

tibble软件包具有enframe()通过将嵌套list对象强制转换为嵌套tibble("整洁"数据框架)对象来解决此问题的功能.以下是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]>
Run Code Online (Sandbox Code Playgroud)

由于列表中有多个嵌套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>
Run Code Online (Sandbox Code Playgroud)


Jac*_*yan 16

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

收益率:

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

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


sbh*_*bha 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
Run Code Online (Sandbox Code Playgroud)

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

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


Sav*_*SUS 11

此方法使用tidyverse包(purrr)。

列表:

x <- as.list(mtcars)
Run Code Online (Sandbox Code Playgroud)

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

library(purrr)
map_df(x, ~.x)
Run Code Online (Sandbox Code Playgroud)


Ahm*_*mad 11

以下简单的命令对我有用:

\n
myDf <- as.data.frame(myList)\n
Run Code Online (Sandbox Code Playgroud)\n

参考(Quora答案

\n
> myList <- list(a = c(1, 2, 3), b = c(4, 5, 6))\n> myList\n$a\n[1] 1 2 3\n \n$b\n[1] 4 5 6\n \n> myDf <- as.data.frame(myList)\n  a b\n1 1 4\n2 2 5\n3 3 6\n> class(myDf)\n[1] "data.frame"\n
Run Code Online (Sandbox Code Playgroud)\n

但是如果\xe2\x80\x99s 不明显如何将列表转换为数据框,这将会失败:

\n
> myList <- list(a = c(1, 2, 3), b = c(4, 5, 6, 7))\n> myDf <- as.data.frame(myList)\n
Run Code Online (Sandbox Code Playgroud)\n
\n

(function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, :\narguments 暗示不同的行数: 3, 4

\n
\n

注意:答案针对问题标题,可能会跳过问题的一些细节

\n


Ian*_*ery 9

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

最快的方式是,不会产生带有列表而不是列的向量的数据帧(来自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]])))
Run Code Online (Sandbox Code Playgroud)


小智 9

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

do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
Run Code Online (Sandbox Code Playgroud)


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

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

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


Joh*_*tha 9

如果您的列表具有相同尺寸的元素,您可以使用bind_rowstidyverse 中的函数。

# Load the tidyverse
Library(tidyverse)

# make a list with elements having same dimensions
My_list <- list(a = c(1, 4, 5), b = c(9, 3, 8))

## Bind the rows
My_list %>% bind_rows()

Run Code Online (Sandbox Code Playgroud)

结果是一个包含两行的数据框。


use*_*302 7

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

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

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

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

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

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

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