R: Using a String as an Argument to Mutate Verb in Dplyr

R: Using a string as an argument to mutate verb in dplyr

We can use rlang::parse_quosure() together with !! (bang bang) to produce the same result:

  • parse_quosure: parses the supplied string and converts it into a quosure

  • !!: unquotes a quosure so it can be evaluated by tidyeval verbs

Note that parse_quosure() was soft-deprecated and renamed to parse_quo() in rlang 0.2.0 per its documentation. If we use parse_quo(), we need to specify the environment for the quosures e.g. parse_quo(input_from_shiny, env = caller_env())

library(rlang)
library(tidyverse)

input_from_shiny <- "Petal.ratio = Petal.Length/Petal.Width"
iris_mutated <- iris %>% mutate_(input_from_shiny)

iris_mutated2 <- iris %>%
mutate(!!parse_quosure(input_from_shiny))
head(iris_mutated2)

#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
#> Petal.ratio = Petal.Length/Petal.Width
#> 1 7.00
#> 2 7.00
#> 3 6.50
#> 4 7.50
#> 5 7.00
#> 6 4.25

identical(iris_mutated, iris_mutated2)
#> [1] TRUE

Edit: to separate LHS & RHS

lhs <- "Petal.ratio"
rhs <- "Petal.Length/Petal.Width"

iris_mutated3 <- iris %>%
mutate(!!lhs := !!parse_quosure(rhs))
head(iris_mutated3)

> head(iris_mutated3)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
Petal.ratio
1 7.00
2 7.00
3 6.50
4 7.50
5 7.00
6 4.25

Created on 2018-03-24 by the reprex package (v0.2.0).

Pass a string as variable name in dplyr::mutate

This operation can be carried out with := while evaluating (!!) and using the conversion to symbol and evaluating on the rhs of assignment

library(dplyr)
my_mtcars <- mtcars %>%
mutate(!! var := factor(!! rlang::sym(var)))
class(my_mtcars$vs)
#[1] "factor"

Or without thinking too much, use mutate_at, which can take strings in vars and apply the function of interest

my_mtcars2 <- mtcars %>% 
mutate_at(vars(var), factor)

Using strings as arguments in custom dplyr function using non-standard evaluation

You can either use sym to turn "y" into a symbol or parse_expr to parse it into an expression, then unquote it using !!:

library(rlang)

testFun(data.frame(x = c("a", "b", "c"), y = 1:3), !!sym(myVar))

testFun(data.frame(x = c("a", "b", "c"), y = 1:3), !!parse_expr(myVar))

Result:

  x   y
1 a 0
2 b 100
3 c 200

Check my answer in this question for explanation of difference between sym and parse_expr.

Using mutate in custom function with mutation condition as argument

If your formula is always like origianl = do_something_original(), this may helps.(for dplyr version >= 1.0)

library(dplyr)
library(stringr)

update_mut <- function(df, mutation){
xx <- word(mutation, 1)
df %>%
mutate("{xx}" := eval(parse(text = mutation)))
}
update_mut(gapminder, "year = 2*year")

country continent year lifeExp pop gdpPercap
<fct> <fct> <dbl> <dbl> <int> <dbl>
1 Afghanistan Asia 3904 28.8 8425333 779.
2 Afghanistan Asia 3914 30.3 9240934 821.
3 Afghanistan Asia 3924 32.0 10267083 853.
4 Afghanistan Asia 3934 34.0 11537966 836.
5 Afghanistan Asia 3944 36.1 13079460 740.
6 Afghanistan Asia 3954 38.4 14880372 786.
7 Afghanistan Asia 3964 39.9 12881816 978.
8 Afghanistan Asia 3974 40.8 13867957 852.
9 Afghanistan Asia 3984 41.7 16317921 649.
10 Afghanistan Asia 3994 41.8 22227415 635.

Passing string as an argument in R

Well this is just a copy-paste from the tidyverse website: link:(https://dplyr.tidyverse.org/articles/programming.html#programming-recipes).

my_summarise <- function(df, group_var) {
group_var <- enquo(group_var)
print(group_var)
df %>%
group_by(!! group_var) %>%
summarise(a = mean(a))
}
my_summarise(df, g1)
#> <quosure>
#> expr: ^g1
#> env: global
#> # A tibble: 2 x 2
#> g1 a
#> <dbl> <dbl>
#> 1 1 2.5
#> 2 2 3.33

But I think i illustrates your problem. I think what you really want to do is like the code above, i.e. create a function.

How to include strings in dplyr mutate experssions?

Would this work?

ddf %>% mutate(pr = !!sym(v))

This gives the same input shown in your example:

a  b pr
1 10 1
2 11 2
3 12 3
4 13 4
5 14 5

How to refer to an argument as character in dplyr filter inside a function

Use rlang::ensym() to capture x as a symbol, which you can then convert using as.character():

library(tidyverse)

per.gender <- function(x) {
new_name <- codebook_e1 %>%
filter(Variable == as.character(ensym(x))) %>%
select(Label) %>%
pull()

e1_done %>%
group_by(koen_new) %>%
mutate(total_n_gender = n()) %>%
group_by(koen_new,{{x}}) %>%
mutate(n_frvl = n()) %>%
select(n_frvl, total_n_gender) %>%
mutate(procentandel = n_frvl/total_n_gender) %>%
distinct(koen_new, {{x}}, procentandel,.keep_all = TRUE) %>%
filter({{x}} == 1) %>%
ungroup() %>%
select(koen_new, !!new_name := procentandel)
}

per.gender(frvlg_1)

Result:

# A tibble: 2 x 2
koen_new `Frvlg: Kultur (Fx Museer, Lokalhistoriske Arkiver, Sangkor, Teater)`
<chr> <dbl>
1 Kvinde 0.0417
2 Mand 0.115

Also note use of !! and := operators to use the value referred to by new_name in the final select() statement — otherwise the column would just be named "new_name".

dplyr / tidyevaluation: How to pass an expression in mutate as a string?

We can have a quosure/quote as expression and then do the evaluation (!!). Also, the lhs of := can take string, so we don't need to convert the 'new_var' to symbol

library(tidyverse)
library(rlang)

expression <- quo(A + B)
example_fun <- function(new_var, expression) {

df %>%
mutate(!! new_var := !! expression)
}

example_fun(new_var, expression)
# A tibble: 10 x 3
# A B C
# <int> <int> <int>
# 1 1 1 2
# 2 2 2 4
# 3 3 3 6
# 4 4 4 8
# 5 5 5 10
# 6 6 6 12
# 7 7 7 14
# 8 8 8 16
# 9 9 9 18
#10 10 10 20

If we really wanted to pass as character strings, then use parse_expr

expression <- "A + B"
example_fun <- function(new_var, expression) {

df %>%
mutate(!! new_var := !! parse_expr(expression))
}

example_fun(new_var, expression)
# A tibble: 10 x 3
# A B C
# <int> <int> <int>
# 1 1 1 2
# 2 2 2 4
# 3 3 3 6
# 4 4 4 8
# 5 5 5 10
# 6 6 6 12
# 7 7 7 14
# 8 8 8 16
# 9 9 9 18
#10 10 10 20


Related Topics



Leave a reply



Submit