首页 > 解决方案 > dplyr case_when 具有动态案例数

问题描述

想要使用 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可行,那么获取列表colsvals生成patterns. 但是,我无法得到正确的说法。希望更熟悉quosures的人知道如何。

注意 - 这里的一些类似的问题是使用连接或其他功能解决的。但是,由于在使用 dbplyr 时它如何转换为 sql ,我只能使用它。case_when

标签: rdplyrquosure

解决方案


我们可以创建一串条件,使用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
#....

where动态paste生成条件case_when

paste(cols, '== 1 ~', vals)
#[1] "g2 == 1 ~ 2" "g3 == 1 ~ 3" "g4 == 1 ~ 4"

推荐阅读