【发布时间】:2016-11-10 04:23:57
【问题描述】:
我想使用 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()
}
也就是说,我希望将列表列d$A 替换为列表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)
进入mutate_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().
【问题讨论】:
-
那么预期的输出究竟是什么?您想将 A 从列表列表更改为小标题列表吗?
-
你的函数没有向量化,它只接受一个列表。看看
tblfy(d$A)。因为d$A中有两个列表,所以出现错误。你不是在比较苹果和苹果。在您的lapply(d$A, tblfy)中,您一次为您的函数提供一个列表,这就是它起作用的原因。tblfy(d$A[[1]])和tblfy(d$A[[2]])。在您的 dplyr 函数中,您提供了两个列表。更改tblfy以接受多个列表,或更改 dplyr 调用。或者正如 MrFlick 所要求的,更广泛地考虑您正在构建的内容。 -
@MrFlick 我已经编辑了问题,以明确所需的输出。现在清楚了吗?
-
@PierreLafortune 好点。我已经尝试过矢量化,但仍然失败。请参阅已编辑的问题。大概我矢量化不正确。但是怎么做?奇怪的是,当我将
tblfy_vec()直接应用到d$A时,我得到了一个 4 的列表,这与我的理解完全不同,即矢量化创建了一个对列表(或向量)组件进行操作的函数。 -
尝试插入一个应用函数。地图或 lapply