【问题标题】:Unnesting a data frame containing lists取消嵌套包含列表的数据框
【发布时间】:2019-11-10 16:01:36
【问题描述】:

我有一个包含列表的数据框,如下所示:

# Load packages
library(dplyr)

# Create data frame
df <- structure(list(ID = 1:3, 
                     A = structure(list(c(9, 8), c(7,6), c(6, 9)), ptype = numeric(0), class = c("vctrs_list_of", "vctrs_vctr")), 
                     B = structure(list(c(3, 5), c(2, 6), c(1, 5)), ptype = numeric(0), class = c("vctrs_list_of", "vctrs_vctr")), 
                     C = structure(list(c(6, 5), c(7, 6), c(8, 7)), ptype = numeric(0), class = c("vctrs_list_of", "vctrs_vctr")), 
                     D = structure(list(c(5, 3), c(4, 1), c(6,  5)), ptype = numeric(0), class = c("vctrs_list_of", "vctrs_vctr"))), 
                row.names = c(NA, -3L), class = c("tbl_df", "tbl", "data.frame"))

# Peek at data 
df
#> # A tibble: 3 x 5
#>      ID A         B         C         D        
#>   <int> <list>    <list>    <list>    <list>   
#> 1     1 <dbl [2]> <dbl [2]> <dbl [2]> <dbl [2]>
#> 2     2 <dbl [2]> <dbl [2]> <dbl [2]> <dbl [2]>
#> 3     3 <dbl [2]> <dbl [2]> <dbl [2]> <dbl [2]>

我想取消嵌套列表,可以使用 pmap_dfr 进行。

# Expand rows
df %>% purrr::pmap_dfr(function(...)data.frame(...))
#>   ID A B C D
#> 1  1 9 3 6 5
#> 2  1 8 5 5 3
#> 3  2 7 2 7 4
#> 4  2 6 6 6 1
#> 5  3 6 1 8 6
#> 6  3 9 5 7 5

reprex package (v0.3.0) 于 2019 年 6 月 28 日创建

这是预期的结果,但似乎是在重新发明轮子,因为 tidyr::unnest 旨在将列表列展平为常规列。但是,使用 tidyr::unnest 会产生以下错误:

df %>% unnest(cols = c(A, B, C, D))
#Error: No common type for `x` <tbl_df<A:double>> and `y` <double>.
#Call `rlang::last_error()` to see a backtrace

在这种情况下,我如何应用 unnest 来用列表列展平我的数据框?


版本信息

> packageVersion("tidyr")
[1] ‘0.8.3.9000’

【问题讨论】:

  • 我认为unnest(df)pmap_dfr(df, data.frame) 之间没有区别,两者都是您的预期输出(尽管后者不是tbl_df)。
  • @r2evans 很奇怪。 unnest 为我抛出错误。再说一次,我用的是tidyr的开发版...
  • 我在 tidyr 开发版本中遇到了同样的问题。将您的列变成普通列表为我解决了这个问题:df %&gt;% mutate_at(.vars = vars(A:D), as.list) %&gt;% unnest(cols = A:D)
  • 我认为暂时保留在这里实际上是相关的,因为其他人可能有类似的问题,并且看到这些 cmets 将非常有用。根据 github 上的响应时间(不确定开发人员的注意力何时会回滚到 tidyr),您可能会在此处发布一个答案,说明(1)这是一个当前的错误,并且(2)这里有一个或两个暂时的解决方法。然后稍后您可以 (3) 在 github/CRAN 版本修复后进行更新。谢谢,很好的发现!
  • 玩了一会儿后,我得出的结论是,可能没有任何问题,我认为nest 刚刚变得更加专注,chop 已经接管了它的一些职责。请在下面查看我的回答,让我知道您的想法。

标签: r tidyr unnest


【解决方案1】:

注意:Hadley Wickham 已在 github 上将此问题标记为 tidyr 版本 0.8.3.9000 中的错误(请参阅 here)。在问题得到解决之前,我将保留以下答案作为潜在的解决方法。

看起来nest 更专门用于在 0.8.3.9000 中创建数据帧的列表列。来自文档:嵌套创建一个列表列数据框;取消嵌套会将其展平成常规列。。例如,尝试:

df <- tibble(x = c(1, 1, 1, 2, 2, 3), y = 1:6, z = 6:1) %>% 
    nest(data = c(y, z))

返回:

# A tibble: 3 x 2
      x           data
  <dbl> <list<df[,2]>>
1     1            [2]
2     2            [2]
3     3            [2]

那就看df$data

<list_of<
  tbl_df<
    y: integer
    z: integer
  >
>[3]>
[[1]]
# A tibble: 3 x 2
      y     z
  <int> <int>
1     1     6
2     2     5
3     3     4

[[2]]
# A tibble: 2 x 2
      y     z
  <int> <int>
1     4     3
2     5     2

[[3]]
# A tibble: 1 x 2
      y     z
  <int> <int>
1     6     1

您的数据框的列是向量的列表列,它们似乎属于chop 的权限范围,这会缩短数据框同时保留其宽度。例如,尝试:

df <- tibble(x = c(1, 1, 1, 2, 2, 3), y = 1:6, z = 6:1) %>% 
    chop(c(y, z))

返回:

# A tibble: 3 x 3
      x y         z        
  <dbl> <list>    <list>   
1     1 <int [3]> <int [3]>
2     2 <int [2]> <int [2]>
3     3 <int [1]> <int [1]>

看看df$y

[[1]]
[1] 1 2 3

[[2]]
[1] 4 5

[[3]]
[1] 6

知道了这一点,您的数据的适当方法将是 chop 的对应方法 unchop,所以给定您的数据框:

# A tibble: 3 x 5
     ID           A           B           C           D
  <int> <list<dbl>> <list<dbl>> <list<dbl>> <list<dbl>>
1     1         [2]         [2]         [2]         [2]
2     2         [2]         [2]         [2]         [2]
3     3         [2]         [2]         [2]         [2]

尝试unchop(df, c(A, B, C, D))unchop(df, A:D),应该会返回:

# A tibble: 6 x 5
     ID     A     B     C     D
  <int> <dbl> <dbl> <dbl> <dbl>
1     1     9     3     6     5
2     1     8     5     5     3
3     2     7     2     7     4
4     2     6     6     6     1
5     3     6     1     8     6
6     3     9     5     7     5

【讨论】:

  • +1 表示周到的解决方案,但 Hadley 现在已将其标记为错误。感谢您花时间考虑这个问题。
  • 感谢@Lyngbakr 回复我。我添加了一条注释,指出这可能是一个错误,但我会留下答案以防万一它对某人有所帮助。
猜你喜欢
  • 2019-09-09
  • 2016-12-16
  • 1970-01-01
  • 2020-05-10
  • 2023-04-06
  • 2021-11-06
  • 2021-08-07
  • 2018-07-10
  • 2020-09-28
相关资源
最近更新 更多