Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing mutate within a function called with variables

I'd like to call a function several times with different variables, each time setting a value to a new variable in the data frame. Here is my failed attempt. I appreciate any help!

dat <- tibble(score1 = runif(10), score2 = score1 * 2)

call_mutate_with_vars <- function(df, var1, var2, var3) {
  df <- 
    df %>%
    mutate({{var3}} := ifelse({{var1}} >= {{var2}},0,{{var2}} - {{var1}}))
  df
}

call_mutate_with_vars(dat,"score1","score2","newscore")

I receive this error:

Error: Problem with `mutate()` column `newscore`.
i `newscore = ifelse("score1" >= "score2", 0, "score2" - "score1")`.
x non-numeric argument to binary operator
Run `rlang::last_error()` to see where the error occurred.
like image 497
John Williams Avatar asked Sep 12 '25 23:09

John Williams


1 Answers

The embracing operator {{ is meant for variables passed as symbols (i.e., fx(var), not fx("var")). If you need to pass your variables as characters, you can instead use the .data pronoun.

So you can either pass symbols to your current function:

library(dplyr)
set.seed(1)

call_mutate_with_vars <- function(df, var1, var2, var3) {
  df %>%
    mutate(
      {{var3}} := ifelse(
        {{var1}} >= {{var2}},
        0,
        {{var2}} - {{var1}}
      )
    )
}

call_mutate_with_vars(dat, score1, score2, newscore)

#> # A tibble: 10 x 3
#>    score1 score2 newscore
#>     <dbl>  <dbl>    <dbl>
#>  1 0.266   0.531   0.266 
#>  2 0.372   0.744   0.372 
#>  3 0.573   1.15    0.573 
#>  4 0.908   1.82    0.908 
#>  5 0.202   0.403   0.202 
#>  6 0.898   1.80    0.898 
#>  7 0.945   1.89    0.945 
#>  8 0.661   1.32    0.661 
#>  9 0.629   1.26    0.629 
#> 10 0.0618  0.124   0.0618

Or rewrite the function to handle characters:

call_mutate_with_chr_vars <- function(df, var1, var2, var3) {
  df %>% 
    mutate(
      !!var3 := ifelse(                  # note use of !! unquote operator
        .data[[var1]] >= .data[[var2]],  # to use character as name
        0,
        .data[[var2]] - .data[[var1]]
      )
    )
}

call_mutate_with_chr_vars(dat, "score1", "score2", "newscore")

#> # A tibble: 10 x 3
#>    score1 score2 newscore
#>     <dbl>  <dbl>    <dbl>
#>  1 0.266   0.531   0.266 
#>  2 0.372   0.744   0.372 
#>  3 0.573   1.15    0.573 
#>  4 0.908   1.82    0.908 
#>  5 0.202   0.403   0.202 
#>  6 0.898   1.80    0.898 
#>  7 0.945   1.89    0.945 
#>  8 0.661   1.32    0.661 
#>  9 0.629   1.26    0.629 
#> 10 0.0618  0.124   0.0618

Created on 2022-03-07 by the reprex package (v2.0.1)

The "Programming with dplyr" vignette is a nice reference for these sorts of problems.

like image 163
zephryl Avatar answered Sep 14 '25 14:09

zephryl