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和
函数?如果是,我更新了我的答案。