以编程方式将 dplyr::case_when 与参数一起使用
Use dplyr::case_when with arguments programmatically
我希望能够以编程方式使用 dplyr
的 case_when
来替换基础 R cut()
函数。
目前,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
感谢您的帮助:)
这里有一个选项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
你不能在那里使用 !!
:
patterns <- list(
!!quo(x) <= 2 ~ "<=2",
!!quo(x) <= 4 ~ "2<->4",
!!quo(x) > 4 ~ ">4"
)
list()
和 ~
都不支持准引用。
- 如果它确实支持准引号,您需要注意运算符优先级并将
!!quo()
括在括号中。
- 最后,对
x
的引述将评估为一个字符串,您将比较数字与字符串(在您的示例中它将是 "cyl
),R 会很高兴地这样做,感谢隐式强制转换:/
所以你需要使用exprs()
而不是list()
,并使用x
.data
代词而不是 x
.
的引号
exprs()
将创建一个未计算表达式的列表。未评估
很好:如果你的公式被评估,它会携带一个环境
(这里是全局环境)并且该环境不包含任何
提供给 dplyr 的数据,特别是没有 .data
代词。另一方面,如果公式是 "context-less",它们
在我们想要的数据上下文中进行评估。
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"
我希望能够以编程方式使用 dplyr
的 case_when
来替换基础 R cut()
函数。
目前,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
感谢您的帮助:)
这里有一个选项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
你不能在那里使用 !!
:
patterns <- list(
!!quo(x) <= 2 ~ "<=2",
!!quo(x) <= 4 ~ "2<->4",
!!quo(x) > 4 ~ ">4"
)
list()
和~
都不支持准引用。- 如果它确实支持准引号,您需要注意运算符优先级并将
!!quo()
括在括号中。 - 最后,对
x
的引述将评估为一个字符串,您将比较数字与字符串(在您的示例中它将是"cyl
),R 会很高兴地这样做,感谢隐式强制转换:/
所以你需要使用exprs()
而不是list()
,并使用x
.data
代词而不是 x
.
exprs()
将创建一个未计算表达式的列表。未评估
很好:如果你的公式被评估,它会携带一个环境
(这里是全局环境)并且该环境不包含任何
提供给 dplyr 的数据,特别是没有 .data
代词。另一方面,如果公式是 "context-less",它们
在我们想要的数据上下文中进行评估。
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"