取消嵌套数据框列中的列表列表

Unnesting a list of lists in a data frame column

要取消嵌套数据框,我可以使用:

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)

错误:

Each column must either be a list of vectors or a list of data frames [y]

注意:忽略原文和Update 1;更新 2 对于 tidyverse 的当前状态更好。


原文:

使用 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

更新二:

自从有人提出这个问题后,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

为了连贯性,我将保留之前的答案,但这更简单。

自从 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 package (v0.3.0)

于 2019-09-14 创建

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

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

如你所愿

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

虽然更长。我真的没有看到在一个操作中取消嵌套多个列表列的好案例,因为在同一行内处理不同大小的列表会导致问题。