R 将多个变异函数压缩为单个函数

R 将多个变异函数压缩为单个函数,r,dplyr,R,Dplyr,我在R中有一个表和向量列表,如下所示: > table ID value 1 1 B 2 2 D 3 3 H 4 4 A 5 5 F 目前,我有一系列的变异函数,如果值在category中,则为每个category添加一列TRUE,否则为NA > table %>% + mutate(catA = if_else(value %in% categories$catA, T, NA)) %>% +

我在R中有一个表和向量列表,如下所示:

> table
  ID value
1  1     B
2  2     D
3  3     H
4  4     A
5  5     F
目前,我有一系列的变异函数,如果值在category中,则为每个category添加一列TRUE,否则为NA

> table %>%
+      mutate(catA = if_else(value %in% categories$catA, T, NA)) %>%
+      mutate(catB = if_else(value %in% categories$catB, T, NA)) %>%
+      mutate(catC = if_else(value %in% categories$catC, T, NA))

  ID value catA catB catC
1  1     B TRUE   NA   NA
2  2     D   NA TRUE   NA
3  3     H   NA   NA TRUE
4  4     A TRUE   NA TRUE
5  5     F   NA TRUE   NA

然而,在现实中,我有更多的类别,必须分别创建每个专栏并不理想。我曾试图将它们压缩成一个函数,但我正在努力循环遍历类别列表,并正确命名新列。我怀疑我需要使用quosures,但在阅读了dplyr vignette中的编程之后,我仍在努力让它们工作。

这里的想法是将类别列表转换为data.frame,然后执行简单的联接操作,将值表与各自的类别合并

为了使其工作,我们将3个类别(“宽格式”)概括为长格式data.frame,其中1列表示类别,1列表示其各自的值。为此,我们使用
tidyr
pivot\u longer
。在这种情况下,3个类别将成为一个包含9行的data.frame

当合并到一起时,我们可以使用
pivot\u wide
将其旋转回来

library(dplyr)
library(tidyr)

table <- data.frame(ID=1:5, value=c('B','D','H','A','F'))
categories <- list(catA=c('A','B','C'), catB=c('D','E','F'), catC=LETTERS[c(7,8,1)])

bind_cols(categories) %>% 
  pivot_longer(cols=everything()) %>%
  right_join(table, by=c('value')) %>%
  pivot_wider(names_from=name, values_from=value)
库(dplyr)
图书馆(tidyr)
表%
右连接(表,by=c('value'))%>%
枢轴(名称从=名称,值从=值)

如果你设置了一个函数,最简单的方法是设计一个递归函数,它会像这样变化,我会在每次调用函数时添加类别列表中第一个不在传递的TIB中的成员,直到类别列表中没有不在列中的项为止。请注意列名的bang-bang(
!!
)以及调用的
:=
,这允许我们在mutate的左侧使用字符串。因为我们正在提取用于命名类别的字符串,所以不需要quosures(因为它已经被引用)


多亏@GenesRus朝着正确的方向推动了我,我成功地使我的原始功能正常工作

classify <- function(data, categories){
     for (i in 1:length(categories)){
          cat_name <- names(categories)[[i]]
          data <- mutate(data, !!cat_name := if_else(value %in% categories[[cat_name]], T, NA))
     }
     return(data)
}

classify我不确定以下代码是否是您想要的,它只在
base R
中使用
sapply()
match()

r <- cbind(table,with(table,sapply(categories, function(v) match(value,v)>0)))

谢谢,但我特别感兴趣的是如何使用函数来缩短我的方法。谢谢!我设法用你的答案来修复我最初的尝试,使用for循环来循环列表中的每个项目,我认为这稍微容易一点,我将自己添加它作为答案。如果没有你的回答,我是不会明白的!
classify <- function(data, categories){
     for (i in 1:length(categories)){
          cat_name <- names(categories)[[i]]
          data <- mutate(data, !!cat_name := if_else(value %in% categories[[cat_name]], T, NA))
     }
     return(data)
}
r <- cbind(table,with(table,sapply(categories, function(v) match(value,v)>0)))
> r
  ID value catA catB catC
1  1     B TRUE   NA   NA
2  2     D   NA TRUE   NA
3  3     H   NA   NA TRUE
4  4     A TRUE   NA TRUE
5  5     F   NA TRUE   NA