有没有tidyverse比使用更惯用的方法将多个列组合成一个列表列mapply?
例如给出以下内容
tibble(.rows = 9) %>%
mutate(foo = runif(n()),
a_1 = runif(n()),
a_2 = runif(n()),
a_3 = runif(n())) ->
Z
Run Code Online (Sandbox Code Playgroud)
(其中Z可能包含其他列,并且也可能包含超过 3 as)可以做
Z %>% mutate(A = mapply(c, a_1, a_2, a_3, SIMPLIFY = FALSE))
Run Code Online (Sandbox Code Playgroud)
效果很好,尽管能够说starts_with('a_')而不是a_1, a_2, a_3.
另一种可能性是
Z %>%
rowid_to_column() %>%
pivot_longer(cols = starts_with('a_')) %>%
group_by(rowid) %>%
summarise(foo = unique(foo),
A = list(value)) %>%
select(-rowid)
Run Code Online (Sandbox Code Playgroud)
这在技术上是可行的,但引入了其他问题(例如,它使用了一个丑陋的foo = unique(foo);此外,如果不是只有一个而是foo有很多foos ,它会变得更加复杂)。
根据之前的一个答案(现已删除)和评论,我对不同的解决方案进行了比较:
FUN_mapply <- function() { Z %>% mutate(A = mapply(c, a_1, a_2, a_3, SIMPLIFY = FALSE)) }
FUN_asplit <- function() { Z %>% mutate(A = asplit(.[,grepl("^a", colnames(.))], 1)) }
FUN_pmap <- function() { Z %>% mutate(A = pmap(.[,grepl("^a", colnames(.))], c)) }
FUN_transpose <- function() { Z %>% mutate(A = transpose(.[,grepl("^a", colnames(.))])) }
FUN_asplit_tidy <- function() { Z %>% mutate(A = asplit(select(., starts_with("a")), 1)) }
FUN_pmap_tidy <- function() { Z %>% mutate(A = pmap(select(., starts_with("a")), c)) }
FUN_transpose_tidy <- function() { Z %>% mutate(A = transpose(select(., starts_with("a")))) }
all(unlist(pmap(list(FUN_mapply()$A, FUN_asplit()$A, FUN_pmap()$A, FUN_transpose()$A), ~all(mapply(all.equal, .x, .y, MoreArgs = list(attributes = F)))))) # All A columns are equal?
mb <- microbenchmark::microbenchmark(
FUN_mapply(),
FUN_asplit(),
FUN_pmap(),
FUN_transpose(),
FUN_asplit_tidy(),
FUN_pmap_tidy(),
FUN_transpose_tidy(),
times = 1000L
)
ggplot2::autoplot(mb)
Run Code Online (Sandbox Code Playgroud)
编辑:替换select(., starts_with("a"))为Z[,grepl("^a", colnames(Z))]
| 归档时间: |
|
| 查看次数: |
2147 次 |
| 最近记录: |