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

des*_*hen 8 r tidyverse

我正在寻找一种动态方法来指定一些“条件参数”,然后将其提供给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))
Run Code Online (Sandbox Code Playgroud)

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

例如,它可能看起来像:

all_conditions <- list(1 = "x < 2",
                       2 = "x >= 2 & x < 5",
                       3 = "x >= 5 & x < 9",
                       4 = "TRUE")
Run Code Online (Sandbox Code Playgroud)

然后我可以做一些事情:

df |>
  mutate(x2 = do(case_when, all_conditions))
Run Code Online (Sandbox Code Playgroud)

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

Pau*_*ulS 8

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

\n

解释

\n
    \n
  • 首先,我们需要case_when使用列表all_conditions\xe2\x80\x94 创建一个包含 的完整代码的字符串,这就是 myimap所做的。

    \n
  • \n
  • 其次,使用rlang::parse_quo,我们将字符串转换为要在 中使用的表达式mutate

    \n
  • \n
\n

评论

\n

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

\n
library(tidyverse)\nlibrary(rlang)\n\ndf <- data.frame(x = 1:10)\n\nall_conditions <- list(`1` = "x < 2",\n                       `2` = "x >= 2 & x < 5",\n                       `3` = "x >= 5 & x < 9",\n                       `4` = "TRUE")\n\ncode <- imap(all_conditions, ~ str_c(.x, " ~ ", .y)) %>% \n          str_c(collapse = ", ") %>% str_c("case_when(",.,")")\n\ndf %>% \n  mutate(x2 = !!parse_quo(code, env = caller_env()))\n\n#>     x x2\n#> 1   1  1\n#> 2   2  2\n#> 3   3  2\n#> 4   4  2\n#> 5   5  3\n#> 6   6  3\n#> 7   7  3\n#> 8   8  3\n#> 9   9  4\n#> 10 10  4\n
Run Code Online (Sandbox Code Playgroud)\n

  • 这里 `caller_env()` 的作用是什么? (2认同)