6

我想使用 dplyr 的mutate_if()函数将 list-columns 转换为 data-frame-columns,但是当我尝试这样做时遇到了一个令人费解的错误。我正在使用 dplyr 0.5.0、purrr 0.2.2、R 3.3.0。

基本设置如下所示:我有一个数据框d,其中一些列是列表:

d <- dplyr::data_frame(
  A = list(
    list(list(x = "a", y = 1), list(x = "b", y = 2)),
    list(list(x = "c", y = 3), list(x = "d", y = 4))
  ),
  B = LETTERS[1:2]
)

我想d$A使用以下函数将列表列(在本例中为 )转换为数据框列:

tblfy <- function(x) {
  x %>%
    purrr::transpose() %>%
    purrr::simplify_all() %>%
    dplyr::as_data_frame()
}

也就是说,我希望将 list-columnd$A替换为 list lapply(d$A, tblfy),即

[[1]]
#  A tibble: 2 x 2
      x     y
  <chr> <dbl>
1     a     1
2     b     2

[[2]]
# A tibble: 2 x 2
      x     y
  <chr> <dbl>
1     c     3
2     d     4

当然,在这种简单的情况下,我可以做一个简单的重新分配。然而,关键是我想以编程方式执行此操作,理想情况下使用 dplyr,以一种可以处理任意数量的列表列的普遍适用的方式。

这是我绊倒的地方:当我尝试使用以下应用程序将列表列转换为数据框列时

d %>% dplyr::mutate_if(is.list, funs(tblfy))

我收到一条我不知道如何解释的错误消息:

Error: Each variable must be named.
Problem variables: 1, 2

为什么会mutate_if()失败?如何正确应用它以获得所需的结果?

评论

一位评论者指出,该函数tblfy()应该是矢量化的。这是一个合理的建议。但是——除非我向量化不正确——这似乎不是问题的根源。插入 的矢量化版本tblfy()

tblfy_vec <- Vectorize(tblfy)

intomutate_if()失败并出现错误

Error: wrong result size (4), expected 2 or 1

更新

在获得了一些 purrr 的经验之后,我现在发现以下方法很自然,虽然有些冗长:

d %>%
  map_if(is.list, ~ map(., ~ map_df(., identity))) %>%
  as_data_frame()

这或多或少与下面的@alistaire 解决方案相同,但map_if()分别使用 、 。map(), 代替mutate_if(), 分别。Vectorize().

4

2 回答 2

7

无需任何复制的就地转换:

library(data.table)

for (col in d) if (is.list(col)) lapply(col, setDF)

d
#Source: local data frame [2 x 2]
#
#                A B
#1 <S3:data.frame> A
#2 <S3:data.frame> B
于 2016-07-07T20:00:34.563 回答
7

原来的tblfy函数对我来说是错误的(即使它的元素是直接链接的),所以让我们重新构建它,同时添加矢量化,这样我们就可以避免之前必要的rowwise()调用:

tblfy <- Vectorize(function(x){x %>% purrr::map_df(identity) %>% list()})

现在我们可以mutate_if很好地使用:

d %>% mutate_if(purrr::is_list, tblfy)
## Source: local data frame [2 x 2]
## 
##                A     B
##           <list> <chr>
## 1 <tbl_df [2,2]>     A
## 2 <tbl_df [2,2]>     B

...如果我们想看看那里有什么,

d %>% mutate_if(purrr::is_list, tblfy) %>% tidyr::unnest()
## Source: local data frame [4 x 3]
## 
##       B     x     y
##   <chr> <chr> <dbl>
## 1     A     a     1
## 2     A     b     2
## 3     B     c     3
## 4     B     d     4

几点注意事项:

  • map_df(identity)在构建 tibble 方面似乎比任何替代配方都更有效。我知道这个identity电话似乎没有必要,但其他大多数事情都会中断。
  • 我不确定会有多大的用处tblfy,因为它在某种程度上取决于列表列中列表的结构,这可能会有很大差异。如果你有很多类似的结构,我想它很有用。
  • 可能有一种方法可以使用pmap而不是Vectorize,但我无法通过一些粗略的尝试来实现它。
于 2016-07-07T20:03:30.980 回答