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 bytidyeval
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 sym
bol 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
What Does the Function Invisible() Do
How to Add Rtools\Bin to the System Path in R
How to Modify an Existing a Sheet in an Excel Workbook Using Openxlsx Package in R
Group Data and Plot Multiple Lines
How to Calculate the Probability for a Given Quantile in R
How to Get the Number of Rows in a CSV File Without Opening It
R Command Line Passing a Filename to Script in Arguments (Windows)
An Na in Subsetting a Data.Frame Does Something Unexpected
How to Remove Rows with 0 Values Using R
Run Sweave or Knitr with Objects from Existing R Session
What's the Difference Between Identical(X, Y) and Istrue(All.Equal(X, Y))
Format Numbers to Significant Figures Nicely in R
Extract File Extension from File Path
Removing Specific Rows from a Dataframe
Print Pretty Data.Frames/Tables to Console
Installing Package - Cannot Open File - Permission Denied