允许不同数量的条件和条件本身的动态“case_when”

Dynamic `case_when` that allows for different number of conditions and conditions itself

我正在寻找一种动态方式来指定一些“条件参数”,然后将其提供给 case_when 操作或其他更适合该问题的方法。

我的目标是将条件规范与 case_when 调用分开,例如这样用户就可以在文本文件或 R 中的列表中输入条件,然后我会获取该信息并将其提供给 case_when(或者更合适的任何其他功能)。

假设我想创建一个附加变量来重新编码 x 的以下数据,我可以这样做:

df <- data.frame(x = 1:10)

df |>
  mutate(x2 = case_when(x < 4 ~ 1,
                        x >= 4 & x <=7 ~ 2,
                        TRUE ~ 3))

现在,我想要实现的是使这段代码变得灵活,以便我可以在外部指定 case_when 条件,然后进行重新编码。

例如它可能看起来像:

all_conditions <- list(1 = "x < 2",
                       2 = "x >= 2 & x < 5",
                       3 = "x >= 5 & x < 9",
                       4 = "TRUE")

然后我可以做一些事情:

df |>
  mutate(x2 = do(case_when, all_conditions))

虽然该示例显示了@Mael 的解决方案适用的数字类型变量,但该解决方案也适用于条件可能类似于 x == "abc" | x == "def".

的字符变量

基于 rlang 的可能解决方案如下。

解释

  • 首先,我们需要用 case_when 的完整代码创建一个字符串,使用列表 all_conditions — 这就是我的 imap 所做的。

  • 其次,使用rlang::parse_quo,我们将字符串转换为要在mutate.

    中使用的表达式

备注

列表 all_conditions 的元素名称必须用反引号括起来。

library(tidyverse)
library(rlang)

df <- data.frame(x = 1:10)

all_conditions <- list(`1` = "x < 2",
                       `2` = "x >= 2 & x < 5",
                       `3` = "x >= 5 & x < 9",
                       `4` = "TRUE")

code <- imap(all_conditions, ~ str_c(.x, " ~ ", .y)) %>% 
          str_c(collapse = ", ") %>% str_c("case_when(",.,")")

df %>% 
  mutate(x2 = !!parse_quo(code, env = caller_env()))

#>     x x2
#> 1   1  1
#> 2   2  2
#> 3   3  2
#> 4   4  2
#> 5   5  3
#> 6   6  3
#> 7   7  3
#> 8   8  3
#> 9   9  4
#> 10 10  4