Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass an expression in a string to a verb in dplyr 0.7.2

Tags:

r

dplyr

rlang

I am trying to implement advice I am finding in the web but I am halfway where I want to go.

Here is a reproducible example:

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)

The filter expression works fine.

The mutate expression works as well but the new variable has the name gear_carb = gear*carb instead of the intended gear_carb.

Finally, the select expression returns an exception.

like image 929
user8270077 Avatar asked Apr 12 '18 17:04

user8270077


People also ask

How does the filter () function in dplyr work?

The filter () function in dplyr (and other similar functions from the package) use something called non-standard evaluation (NSE). In NSE, names are treated as string literals.

How to convert a string to an expression in your programming?

Convert a String to an Expression in R Programming – parse () Function parse () function in R Language is used to convert an object of character class to an object of expression class. Syntax: parse (text = character)

What is parse() function in Your Language?

Last Updated : 24 Jun, 2020. parse () function in R Language is used to convert an object of character class to an object of expression class. Syntax: parse (text = character) Parameters: character: Object of character class. Example 1: x <- "sin (pi / 2)" class(x)

How do I pass a string instead of a name in tidy?

If we don’t want to pass a string but a name instead, the tidyverse has recently introduced a { {}} (#curly-curly’) operator for tidy evaluation. See now we can pass the variable name climbing to the group_by function using the { {}} operator.


1 Answers

As mentioned in the comments, the underscore versions of dplyr verbs are now deprecated. The correct approach is to use quasiquotation.

To address your issue with select, you simply need to modify select_expr to contain multiple expressions:

## 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 ;

Use rlang::parse_expr to convert these strings to unevaluated expressions:

## 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 )

Given the unevaluated expressions, we can now pass them to the dplyr verbs. Writing filter( filter_expr ) won't work because filter will look for a column named filter_expr in your data frame. Instead, we want to access the expression stored inside filter_expr. To do this we use the !! operator to let dplyr verbs know that the argument should be expanded to its contents (which is the unevaluated expressions we are interested in):

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

In case of select, we have multiple expressions, which is handled by !!! instead:

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

P.S. It's also worth mentioning that select works directly with string vectors, without having to rlang::parse_expr() them first:

mtcars %>% select( c("mpg", "cyl") )
#                      mpg cyl
# Mazda RX4           21.0   6
# Mazda RX4 Wag       21.0   6
# Datsun 710          22.8   4
like image 180
Artem Sokolov Avatar answered Oct 25 '22 09:10

Artem Sokolov