【问题标题】:Use dplyr::case_when with arguments programmatically以编程方式将 dplyr::case_when 与参数一起使用
【发布时间】:2017-12-02 23:38:33
【问题描述】:

我希望能够以编程方式使用dplyrcase_when 来替换基本R cut()function。

目前,case_when 可以通过 NSE 与外部参数一起使用,例如:

library(dplyr)
library(rlang)

patterns <- list(
  x <= 2 ~ "<=2",
  x <= 4 ~ "2<->4",
  x > 4 ~ ">4"
 )
 x <- 1:10
 case_when(!!!patterns)

我想要做的是:在 mutate 中将它与另一个变量一起使用

这个想法是这样的,虽然我不知道如何让它发挥作用:

library(dplyr)
patterns_lazy <- list(
  !!quo(x) <= 2 ~ "<=2",
  !!quo(x) <= 4 ~ "2<->4",
  !!quo(x) > 4 ~ ">4"
)
x <- "cyl"
mtcars %>% mutate(ABC = case_when(!!!patterns_lazy))

我希望能够定义我想要过滤的列(在字符串内),并检索类似这样的内容(此示例不起作用,因为它是所需的语法):

x <- "cyl"
mtcars %>%
  select(cyl) %>%
  mutate(ABC = case_when(!!!patterns_lazy)) %>%
  head()

  cyl ABC
1   6 >4
2   6 >4
3   4 2<->4
4   6 >4
5   8 >4
6   6 >4

感谢您的帮助:)

【问题讨论】:

    标签: r dplyr rlang


    【解决方案1】:

    你不能在那里使用!!

    patterns <- list(
      !!quo(x) <= 2 ~ "<=2",
      !!quo(x) <= 4 ~ "2<->4",
      !!quo(x) > 4 ~ ">4"
    )
    
    1. list()~ 都不支持准引用。
    2. 如果它确实支持准引用,则需要注意运算符优先级并将 !!quo() 括在括号中。
    3. 最后,x 的引用将评估为字符串,您将使用字符串比较数字(在您的示例中为 "cyl),由于隐式强制,R 会很高兴地做到这一点:/李>

    所以你需要使用exprs()而不是list(),并使用x.data 代词而不是引用 x

    exprs() 将创建一个未计算的表达式列表。未评估 很好:如果您的公式被评估,它将带有一个环境 (这里是全局环境)并且该环境不包含任何 提供给 dplyr 的数据,特别是没有 .data 代词。另一方面,如果公式是“无上下文”的,它们 在我们想要的数据上下文中进行评估。

    patterns_lazy <- exprs(
      .data[[x]] <= 2 ~ "<=2",
      .data[[x]] <= 4 ~ "2<->4",
      .data[[x]] > 4 ~ ">4"
    )
    
    x <- "cyl"
    pull(mutate(mtcars, case_when(!!!patterns_lazy)))
    #>  [1] ">4"    ">4"    "2<->4" ">4"    ">4"    ">4"    ">4"    "2<->4" "2<->4"
    #> [10] ">4"    ">4"    ">4"    ">4"    ">4"    ">4"    ">4"    ">4"    "2<->4"
    #> [19] "2<->4" "2<->4" "2<->4" ">4"    ">4"    ">4"    ">4"    "2<->4" "2<->4"
    #> [28] "2<->4" ">4"    ">4"    ">4"    "2<->4"
    

    【讨论】:

      【解决方案2】:

      这是ifelse的一个选项

      f1 <- function(data, x){
             x <- enquo(x)       
             f2 <- function(y) ifelse(y <= 2, "<=2", ifelse(y <=4, "2<->4", ">4"))
      
        data %>%
                mutate( ABC = f2(UQ(x)))
       }
      
      f1(mtcars, cyl) %>%
                    head()
      #   mpg cyl disp  hp drat    wt  qsec vs am gear carb   ABC
      #1 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4    >4
      #2 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4    >4
      #3 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1 2<->4
      #4 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1    >4
      #5 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2    >4
      #6 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1    >4
      

      【讨论】:

      • 感谢您的回答,但我选择了 case_when 语法,因为我发现它比嵌套的 ifelse 更具可读性:)
      猜你喜欢
      • 1970-01-01
      • 2021-01-19
      • 1970-01-01
      • 1970-01-01
      • 2022-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-02
      相关资源
      最近更新 更多