Search code examples
rdplyrexpressionevaluationnon-standard-evaluation

How to use an expression in dplyr::mutate in R


I want to add a new column based on a given character vector. For example, in the example below, I want to add column d defined in expr:

library(magrittr)

data <- tibble::tibble(
  a = c(1, 2),
  b = c(3, 4)
)

expr <- "d = a + b"

just as below:

data %>%
  dplyr::mutate(d = a + b)

# # A tibble: 2 x 3
#       a     b     d
#   <dbl> <dbl> <dbl>
# 1     1     3     4
# 2     2     4     6

However, in the codes below, while the calculations themselves (i.e., adding) work, the names of the new columns are different from what I expected.

data %>%
  dplyr::mutate(!!rlang::parse_expr(expr))

# # A tibble: 2 x 3
#       a     b `d = a + b`
#   <dbl> <dbl>       <dbl>
# 1     1     3           4
# 2     2     4           6

data %>%
  dplyr::mutate(!!rlang::parse_quo(expr, env = rlang::global_env()))

# # A tibble: 2 x 3
#       a     b `d = a + b`
#   <dbl> <dbl>       <dbl>
# 1     1     3           4
# 2     2     4           6

data %>%
  dplyr::mutate(rlang::eval_tidy(rlang::parse_expr(expr)))

# # A tibble: 2 x 3
#       a     b `rlang::eval_tidy(rlang::parse_expr(expr))`
#   <dbl> <dbl>                                       <dbl>
# 1     1     3                                           4
# 2     2     4                                           6

How can I properly use an expression in dplyr::mutate?

My question is similar to this, but in my example, the new variable (d) and its definition (a + b) are given in a single character vector (expr).


Solution

  • Any of these work. The second is similar to the first but does not require that rlang be on the search path. The third and fourth also work if the d= part is not present in expr in which case default names are used. The last one uses only base R and is also the shortest.

    data %>% mutate(within(., !!parse_expr(expr)))
    
    data %>% mutate(within(., !!parse(text = expr)))
    
    data %>% mutate(data, !!parse_expr(sprintf("tibble(%s)", expr)))
    
    data %>% { eval_tidy(parse_expr(sprintf("mutate(., %s)", expr))) }
    
    within(data, eval(parse(text = expr)))  # base R
    

    Note

    Assume this premable:

    library(dplyr)
    library(rlang)
    
    # input
    data <- tibble(a = c(1, 2), b = c(3, 4))
    expr <- "d = a + b"