我想使用dplyr的mutate_if()函数将列表列转换为数据帧列,但是当我尝试这样做时会遇到令人费解的错误.我使用的是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]
)
Run Code Online (Sandbox Code Playgroud)
我想d$A使用以下函数将列的列(在本例中为)转换为数据帧列:
tblfy <- function(x) {
x %>%
purrr::transpose() %>%
purrr::simplify_all() %>%
dplyr::as_data_frame()
}
Run Code Online (Sandbox Code Playgroud)
也就是说,我希望list-column 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
Run Code Online (Sandbox Code Playgroud)
当然,在这个简单的例子中,我可以做一个简单的重新分配.然而,重点是我想以编程方式,理想情况下使用dplyr,以一种通用的方式处理任意数量的列表列.
这是我绊倒的地方:当我尝试使用以下应用程序将list-columns转换为data-frame-columns时
d %>% dplyr::mutate_if(is.list, funs(tblfy))
Run Code Online (Sandbox Code Playgroud)
我收到一条错误消息,我不知道如何解释:
Error: Each variable must be named.
Problem variables: 1, 2
Run Code Online (Sandbox Code Playgroud)
为什么mutate_if()失败?如何正确应用它以获得所需的结果?
备注
一位意见提供者指出该功能tblfy()应该是矢量化的.这是一个合理的建议.但是 - 除非我的矢量化不正确 - 这似乎并没有找到问题的根源.插入矢量化版本tblfy(),
tblfy_vec <- Vectorize(tblfy)
Run Code Online (Sandbox Code Playgroud)
到mutate_if()失败,出现错误
Error: wrong result size (4), expected 2 or 1
Run Code Online (Sandbox Code Playgroud)
更新
在获得purrr的一些经验之后,我现在发现以下方法是自然的,如果有点啰嗦:
d %>%
map_if(is.list, ~ map(., ~ map_df(., identity))) %>%
as_data_frame()
Run Code Online (Sandbox Code Playgroud)
这与@ alistaire的解决方案或多或少完全相同,下面,但是使用map_if(),分别是.分别map()代替mutate_if(),Vectorize().
没有任何复制的就地转换:
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
Run Code Online (Sandbox Code Playgroud)
原来的tblfy功能出现了错误,我(即使它的元素直接链接),所以让我们重建了一点,添加矢量为好,这让我们避免否则,需要事先rowwise()电话:
tblfy <- Vectorize(function(x){x %>% purrr::map_df(identity) %>% list()})
Run Code Online (Sandbox Code Playgroud)
现在我们可以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
Run Code Online (Sandbox Code Playgroud)
......如果我们不知道那里有什么,
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
Run Code Online (Sandbox Code Playgroud)
几个笔记:
map_df(identity)似乎比任何替代配方更有效地建立一个tibble.我知道这个identity电话似乎没必要,但其他大部分都没有.tblfy,因为它在某种程度上取决于列表列中列表的结构,这可能会有很大差异.如果你有很多类似的结构,我认为它是有用的.pmap代替Vectorize,但我不能让它与一些粗略的尝试一起工作.| 归档时间: |
|
| 查看次数: |
3369 次 |
| 最近记录: |