dplyr中代替eval parse的方法是什么?

6

有没有一种不使用 eval(parse()) 的方法来使用字符串作为参数进行过滤?

library("dplyr")

subset <- "carb == 4"
subset_df <- mtcars %>% filter(eval(parse(text = subset)))

2
你能解释一下为什么你想要这个吗?有简单的方法,比如编写自己的函数evalparse <- function(x) eval(parse(text = x), envir = parent.frame()),还有像下面答案中的tidyverse替代方案。这些是你想要的吗? - user2554330
我已经阅读了许多关于为什么不应该使用eval parse的帖子,我同意这一点。但是,能够传递文本以及dplyr使其更加动态,因此我的目标是实现相同级别的动态代码和安全性,而eval parse则无法做到这一点。 - hxalchemy
我怀疑这里所有的建议都有与“eval(parse())”相同的安全问题。 - user2554330
3个回答

7
1) rlang:如果你想知道tidyverse中是否存在eval/parse的替代函数,那么是的,存在。你也需要使用 rlang,它已被dplyr使用,但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,那么在问题的情况下,sqldf 就能胜任。

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") }

你认为这些选项是更安全/计算效率更高的替代方案吗? - hxalchemy

3

虽然它已经被弃用,但您仍然可以使用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

0
如果我们可以使用一个函数,那么我们可以将它作为未引用的参数传递,并在{{}}中进行评估,即我们不需要另一个包或执行任何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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接