R 将列合并到列表列中
是否有比使用R 将列合并到列表列中,r,dplyr,R,Dplyr,是否有比使用mapply更惯用的方法将多个列组合成一个列表列 举个例子,如下所示 tibble(.rows = 9) %>% mutate(foo = runif(n()), a_1 = runif(n()), a_2 = runif(n()), a_3 = runif(n())) -> Z (其中Z可能包含其他列,也可能包含3个以上的as) Z %>% mutate(A = mapply(c, a_1, a_2
mapply
更惯用的方法将多个列组合成一个列表列
举个例子,如下所示
tibble(.rows = 9) %>%
mutate(foo = runif(n()),
a_1 = runif(n()),
a_2 = runif(n()),
a_3 = runif(n())) ->
Z
(其中Z
可能包含其他列,也可能包含3个以上的a
s)
Z %>% mutate(A = mapply(c, a_1, a_2, a_3, SIMPLIFY = FALSE))
这很好,不过如果能说以('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)
这在技术上是可行的,但也带来了其他问题(例如,它使用了一个丑陋的
foo=unique(foo)
;此外,如果不是只有一个foo
,而是有许多foo
,它会变得更复杂一些)。根据以前的答案(现在已删除)和评论,我对不同的解决方案进行了比较:
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)
FUN\u mapply%mutate(A=mapply(c,A\u 1,A\u 2,A\u 3,SIMPLIFY=FALSE))]
FUN_asplit%mutate(A=asplit([,grepl(^A),colnames(.)]),1))]
FUN_pmap%变异(A=pmap([,grepl(“^A”,colnames(.))],c))}
FUN_转置%mutate(A=转置([,grepl(^A),colnames()]))
FUN\u asplit\u tidy%mutate(A=asplit(选择(,以(“A”)开头),1))]
FUN_pmap_tidy%mutate(A=pmap(选择(,以“A”)开头),c))]
FUN_transpose_tidy%mutate(A=transpose(选择(,以“A”)开头)}
全部(未列出(pmap(列表(FUN_-mapply()$A,FUN_-asplit()$A,FUN_-pmap()$A,FUN_-transpose()$A),~all(mapply(all.equal,.x,.y,MoreArgs=list(attributes=F(')))#所有A列都相等吗?
mb检查这里的线程-,可能类似于transpose(select(,start_with('a_'))
应该在mutate
中工作,它确实看起来像Z%>%mutate(a=transpose(start_with('a_'))
应该工作(或者使用pmap
)但在这两种情况下,我都得到了错误:没有注册任何tidyselect变量
。您需要转置(选择(,以('a_'))开始)
。使用Z%>%mutate(a=transpose(选择(,以('a_'))开始)
您是对的,这是有效的(很抱歉错过了选择(,…)
)。我认为这可能是“答案”@arg0naut91如果您将您的评论提升为答案,我将接受。关于编辑(将…开始部分替换为
…grepl
),我认为这会使代码更快,对吗?但是(IMO)新版本对管道的友好程度较低,而且不太符合tidyverse的习惯用法。作为记录,我觉得最初的答案是我想要接受的(尽管我不会改变我的接受)。这是非常正确的grepl
将Z子集以仅获取所需的列<代码>以
开始,但速度要慢得多。根据你的评论,我觉得我需要修改我的答案,使之更加友好。例如,如果要在变异之前进行一些修改,则Z可能已更改,因此结果将不正确。使用
而不是Z
将解决此问题。一种可能性是,您可以重新添加使用启动的函数(可能会在它们的名称后面添加类似\u tidyverse
)。那么答案将包括我的问题和速度问题。我想你的意思是在比较中添加start\u和函数?如果是,我更新了我的答案。