如何将字符串中的表达式传递给dplyr 0.7.2中的动词

6

我正在尝试实施网上找到的建议,但我只完成了一半。

这里是一个可重复的示例:

library(tidyverse)
library(dplyr)
library(rlang)

data(mtcars)

filter_expr = "am == 1"

mutate_expr = "gear_carb = gear*carb"

select_expr = "mpg , cyl"

mtcars %>% filter_(filter_expr) %>% mutate_(mutate_expr) %>% select_(select_expr)
过滤器表达式运行正常。 变异表达式也可以,但新变量的名称是gear_carb = gear*carb,而不是预期的gear_carb。 最后,选择表达式返回异常。

这个建议来自哪里? - Arthur Yip
此外,下划线版本现已弃用:“已弃用主要动词的SE版本”dplyr曾经为每个动词提供带有下划线后缀的双版本。这些版本具有标准评估(SE)语义:它们不像NSE动词那样通过代码获取参数,而是通过值获取参数。它们的目的是使使用dplyr进行编程成为可能。但是,dplyr现在使用整洁的评估语义。NSE动词仍然捕获其参数,但现在可以取消引用这些参数的某些部分。这为NSE动词提供了完全的可编程性。因此,下划线版本现在已经过时。 - Arthur Yip
这里可能有答案...https://dev59.com/ZXI-5IYBdhLWcg3wpqMK#40164111。同时建议观看关于整洁评估的教程。https://www.rstudio.com/resources/videos/tidy-eval-programming-with-dplyr-tidyr-and-ggplot2/ - Jacob Nelson
1个回答

7

如评论中所提到的,dplyr动词的下划线版本现已被弃用。正确的方法是使用准引用

要解决您在select方面的问题,您只需要修改select_expr以包含多个表达式:

## I renamed your variables to *_str because they are, well, strings.
filter_str <- "am == 1"
mutate_str <- "gear_carb = gear*carb"
select_str <- "mpg; cyl"                # Note the ;

使用 rlang::parse_expr 将这些字符串转换为未求值的表达式:
## Notice the plural parse_exprs, which parses a list of expressions
filter_expr <- rlang::parse_expr( filter_str )
mutate_expr <- rlang::parse_expr( mutate_str )
select_expr <- rlang::parse_exprs( select_str )

有了未评估的表达式,我们现在可以将它们传递给 dplyr 动词。写成 filter( filter_expr ) 是行不通的,因为 filter 会在您的数据框中查找名为 filter_expr 的列。相反,我们想要访问存储在 filter_expr 中的表达式。为此,我们使用 !! 运算符,让 dplyr 动词知道参数应该扩展为其内容(即我们感兴趣的未评估的表达式):

mtcars %>% filter( !!filter_expr )
#     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  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
# 4  32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1

mtcars %>% mutate( !!mutate_expr )
#     mpg cyl  disp  hp drat    wt  qsec vs am gear carb gear_carb = gear * carb
# 1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4                      16
# 2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4                      16
# 3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1                       4
# 4  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1                       3

select的情况下,我们有多个表达式,这些由!!!进行处理:

mtcars %>% select( !!!select_expr )
#                      mpg cyl
# Mazda RX4           21.0   6
# Mazda RX4 Wag       21.0   6
# Datsun 710          22.8   4

值得一提的是,select 直接与字符串向量配合使用,无需先使用 rlang::parse_expr()

mtcars %>% select( c("mpg", "cyl") )
#                      mpg cyl
# Mazda RX4           21.0   6
# Mazda RX4 Wag       21.0   6
# Datsun 710          22.8   4

这似乎比使用select_(字符串)更复杂。为什么要改变它? - Sacha Epskamp
@SachaEpskamp:我的理解是这个变化是为了将所有内容都纳入一个共同的tidyeval框架之下。值得指出的是,select_( string )虽然在概念上更简单,但不能使用提供为字符串的任意表达式。 - Artem Sokolov

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