在数据框列中展开一个列表的列表

23

我可以使用以下代码将数据框变成非嵌套形式:

df <- data_frame(
    x = 1,
    y = list(a = 1, b = 2)
)

tidyr::unnest(df)

但是我该如何解嵌套一个数据框列中的列表内的列表?

df <- data_frame(
    x = 1,
    y = list(list(a = 1, b = 2))
)
tidyr::unnest(df)

错误:

每列必须是向量列表或数据框架列表 [y]


2
结果应该是什么样子? - Rich Scriven
与第一个代码块完全相同。data_frame(x = c(1, 1), y = c(1, 2)) - emehex
如果你想要扩展数据,可以使用以下代码:df %>% mutate(y = list(as.data.frame(y))) %>% unnest() 如果你想要将数据转换为长格式,可以使用以下代码之一:df %>% do(data_frame(x = .$x, y = unlist(.$y))) 或者 df %>% mutate(y = data_frame(unlist(y))) %>% unnest() - alistaire
unnest(unnest(df))有什么问题? - val
3个回答

27

注意: 忽略原始内容和 Update 1; 在当前 tidyverse 的状态下,Update 2 更好。


翻译:

使用 purrr 处理列表非常方便。

library(purrr)

df %>% dmap(unlist)
## # A tibble: 2 x 2
##       x     y
##   <dbl> <dbl>
## 1     1     1
## 2     1     2

这个大致相当于

as.data.frame(lapply(df, unlist))
##   x y
## a 1 1
## b 1 2

更新1:

dmap已被弃用并移动到purrrlyr,这是有趣但命运多舛的函数的家园,现在这些函数将向您发出许多弃用警告。您可以将基本的R习惯用法转换为tidyverse:


df %>% map(unlist) %>% as_tibble()

这个方法对于这种情况可以正常工作,但是对于多行的情况就不行了(所有这些方法都面临这个问题)。更加健壮的解决方案可能是

library(tidyverse)

df %>% bind_rows(df) %>%    # make larger sample data
    mutate_if(is.list, simplify_all) %>%    # flatten each list element internally 
    unnest()    # expand
#> # A tibble: 4 × 2
#>       x     y
#>   <dbl> <dbl>
#> 1     1     1
#> 2     1     2
#> 3     1     1
#> 4     1     2

更新2:

自提问之后的某个时间点,tidyr::unnest()已经得到更新,不再出现错误,因此您只需执行以下操作:

df %>%
    unnest(y) %>% 
    unnest(y)
#> # A tibble: 2 × 2
#>       x     y
#>   <dbl> <dbl>
#> 1     1     1
#> 2     1     2

如果你关心列表中的名称,请先将它们提取出来,然后同时展开名称和列表:

df %>%
    mutate(label = map(y, names)) %>%
    unnest(c(y, label)) %>% 
    unnest(y)
#> # A tibble: 2 × 3
#>       x     y label
#>   <dbl> <dbl> <chr>
#> 1     1     1 a    
#> 2     1     2 b

我将保留之前的答案以保持连贯性,但这个更简单。


2
dmap似乎不在purrr中。 - jzadra
as_data_frame()在tibble 2.0.0中已被弃用。我建议将“更新”放在帖子的顶部,因为大多数新搜索都来自最近发布软件包的用户,并且会遇到“dmap”错误。 - runr
有一些变化,我在我的回答中进行了处理。由于这个问题仍然出现,但是之前的答案已经不再适用,我建议再次更新答案。 - Lukas

5

自从 tidyr 1.0.0 版本以后,使用 unnest_longer() 可以轻松地完成此操作:

df <- tibble::tibble(
  x = 1,
  y = list(list(a = 1, b = 2))
)

library(tidyr)
unnest_longer(df,y,indices_include = FALSE)
#> # A tibble: 2 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     1     1
#> 2     1     2

该示例由 reprex软件包(v0.3.0)于2019-09-14创建。


1

所有的答案现在都有点过时了;对于给定的任务,我看到两个解决方案:

tidyr::unnest(df, y) %>% tidyr::unnest(y)

它做你想要的,就像

dplyr::mutate(df, y = purrr::map(y, unlist)) |> tidyr::unnest(y)

虽然这可能会更长,但我并没有看到在一个操作中取消嵌套超过一个列表列的好处,因为在同一行内处理不同大小的列表将导致问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接