想使用 dplyr 和 case_when
将一系列指标列折叠为一列。挑战是我希望能够在未指定/动态数量的列上折叠。
考虑以下数据集,gear
已被拆分为一系列指标列。
library(dplyr)
data(mtcars)
mtcars = mtcars %>%
mutate(g2 = ifelse(gear == 2, 1, 0),
g3 = ifelse(gear == 3, 1, 0),
g4 = ifelse(gear == 4, 1, 0)) %>%
select(g2, g3, g4)
我正在尝试编写一个相反的函数。
当我知道有多少种情况时,可以按如下方式完成:
combine_indices = function(db, cols, vals){
db %>% mutate(new_col = case_when(!!sym(cols[1]) == 1 ~ vals[1],
!!sym(cols[2]) == 1 ~ vals[2],
!!sym(cols[3]) == 1 ~ vals[3]))
}
cols = c("g2", "g3", "g4")
vals = c(2,3,4)
combine_indices(mtcars, cols, vals)
但是,我想要
combine_indices
函数来处理任意数量的索引列(现在它正好适用于三个)。根据文档(
?case_when
),“如果您的模式存储在列表中,您可以将其与 !!!
拼接”。但我无法让它工作:patterns = list(sym(cols[1] == 1 ~ vals[1],
sym(cols[2] == 1 ~ vals[2],
sym(cols[3] == 1 ~ vals[3])
mtcars %>% mutate(new_col = case_when(!!!patterns))
只生成一个填充 NA 的新列。
如
!!!patterns
工作,那么采用列表 cols
就很简单了。和 vals
并生成 patterns
.但是,我无法获得正确的 quosures。希望更熟悉quosures的人知道如何。注意 - 这里的一些类似问题是使用连接或其他函数解决的。 但是,我只能使用
case_when
因为它在使用 dbplyr 时如何转换为 sql。
最佳答案
我们可以创建一串条件,使用 parse_exprs
并将其拼接( !!!
)。
library(dplyr)
library(rlang)
combine_indices = function(db, cols, vals){
db %>% mutate(new_col = case_when(!!!parse_exprs(paste(cols, '== 1 ~', vals))))
}
cols = c("g2", "g3", "g4")
vals = c(2,3,4)
combine_indices(mtcars, cols, vals)
返回:
# g2 g3 g4 new_col
#1 0 0 1 4
#2 0 0 1 4
#3 0 0 1 4
#4 0 1 0 3
#5 0 1 0 3
#6 0 1 0 3
#....
哪里
paste
为 case_when
生成条件动态。paste(cols, '== 1 ~', vals)
#[1] "g2 == 1 ~ 2" "g3 == 1 ~ 3" "g4 == 1 ~ 4"
关于r - dplyr case_when 具有动态案例数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61789717/