使用 dplyr 解析 eval 的替代方法
alternatives to eval parse with dplyr
有没有办法在不使用 eval(parse()) 的情况下使用字符串作为参数进行过滤?
library("dplyr")
subset <- "carb == 4"
subset_df <- mtcars %>% filter(eval(parse(text = subset)))
1) rlang 如果你问的是在 tidyverse 中是否有 eval/parse 的对应物,那么,是的,有。您还需要 dplyr 已使用的 rlang,但 dplyr 不会导出所需的函数,因此请使用库语句加载它。
library(dplyr)
library(rlang)
subset <- "carb == 4"
mtcars %>% filter(eval_tidy(parse_expr(subset)))
给予:
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
1a) 这也有效:
mtcars %>% filter(!!parse_quo(subset, .GlobalEnv))
2) sqldf 如果您正在寻找一种不使用 eval/parse 或任何直接替代方法的方法,并且不需要使用 tidyverse然后 sqldf 可以做到这一点,前提是 subset
包含有效的 SQL,在问题的情况下它确实如此。
library(sqldf)
subset <- "carb == 4"
fn$sqldf("select * from mtcars where $subset")
给予:
mpg cyl disp hp drat wt qsec vs am gear carb
1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
3 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
4 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
5 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
6 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
7 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
8 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
9 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
10 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
2a)这也可以用管道的形式写成这样:
mtcars %>% { fn$sqldf("select * from '.' where $subset") }
它已被弃用,但您可以使用 filter_
代码
mtcars %>%
filter_("carb == 4")
输出
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
如果我们可以使用一个函数,那么我们可以将它作为未引用的传递并在 {{}}
中对其进行评估,即我们不需要另一个包,也不需要任何 eval/parse
library(dplyr)
f1 <- function(data, expr) {
data %>%
filter({{expr}})
}
-测试
> f1(mtcars, carb == 4)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
此外,如果我们想从一个对象传递,而不是创建一个字符串,quote
它
expr1 <- quote(carb == 4)
f1(mtcars, !!expr1)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
有没有办法在不使用 eval(parse()) 的情况下使用字符串作为参数进行过滤?
library("dplyr")
subset <- "carb == 4"
subset_df <- mtcars %>% filter(eval(parse(text = subset)))
1) rlang 如果你问的是在 tidyverse 中是否有 eval/parse 的对应物,那么,是的,有。您还需要 dplyr 已使用的 rlang,但 dplyr 不会导出所需的函数,因此请使用库语句加载它。
library(dplyr)
library(rlang)
subset <- "carb == 4"
mtcars %>% filter(eval_tidy(parse_expr(subset)))
给予:
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
1a) 这也有效:
mtcars %>% filter(!!parse_quo(subset, .GlobalEnv))
2) sqldf 如果您正在寻找一种不使用 eval/parse 或任何直接替代方法的方法,并且不需要使用 tidyverse然后 sqldf 可以做到这一点,前提是 subset
包含有效的 SQL,在问题的情况下它确实如此。
library(sqldf)
subset <- "carb == 4"
fn$sqldf("select * from mtcars where $subset")
给予:
mpg cyl disp hp drat wt qsec vs am gear carb
1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
3 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
4 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
5 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
6 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
7 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
8 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
9 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
10 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
2a)这也可以用管道的形式写成这样:
mtcars %>% { fn$sqldf("select * from '.' where $subset") }
它已被弃用,但您可以使用 filter_
代码
mtcars %>%
filter_("carb == 4")
输出
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
如果我们可以使用一个函数,那么我们可以将它作为未引用的传递并在 {{}}
中对其进行评估,即我们不需要另一个包,也不需要任何 eval/parse
library(dplyr)
f1 <- function(data, expr) {
data %>%
filter({{expr}})
}
-测试
> f1(mtcars, carb == 4)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
此外,如果我们想从一个对象传递,而不是创建一个字符串,quote
它
expr1 <- quote(carb == 4)
f1(mtcars, !!expr1)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4