1

In dplyr 0.8.0, the wrapper funs() (used within mutate_at() or summarise_at()) is soft-deprecated.

The new recommended syntax is to use ~sum(.) instead of funs(sum(.)), which is the "old style" I would have previously used. My aim is to translate the old syntax to the new syntax , however I have been experiencing issues when the function call within funs() uses (!!sym()) to convert a character input for a column name to a symbol that can be recognised within the function.

Here's a made-up example of how I would write a function in the old dplyr style.

var is a character string that refers to the column name, and at funs() it is multiplied by Sepal.Length.

multiply_by <- function(var){
  iris %>%
    mutate_at("Sepal.Length",funs(.*!!sym(var)))
}
multiply_by("Sepal.Width") # This works

My question is that I cannot figure out how to translate this to the new ~ syntax without encountering an error. If I run the following it triggers an 'invalid argument type' error:

multiply_by2 <- function(var){
  iris %>%
    mutate_at("Sepal.Length",~.*!!sym(var))
}
multiply_by2("Sepal.Width")
# Error in !sym(var) : invalid argument type 

Can someone help? At the moment I can get by with using funs(), but since it is being soft-deprecated I would like to migrate my code to a stable format if/when it becomes fully hard-deprecated. Thank you!

cyun
  • 95
  • 1
  • 2
  • 7
  • 1
    Tryb `mutate_at("Sepal.Length", list(~.*!!sym(var)))` – akrun Mar 06 '19 at 12:09
  • Thanks - but this seems to trigger the same error - " Error in !sym(var) : invalid argument type " – cyun Mar 06 '19 at 12:16
  • 1
    Try `iris %>% mutate_at("Sepal.Length", list( ~ .* .data[[var]]))` as mentioned in the [issues](https://github.com/tidyverse/dplyr/issues/4199) – akrun Mar 06 '19 at 12:18
  • 1
    Thanks - works like a charm! It's less of a 'dplyr' solution but solves my problem. – cyun Mar 06 '19 at 12:23
  • In the issue, there is also the `eval_bare` (`iris %>% mutate_at(vars(Sepal.Length), list( ~ eval_bare(expr(.* !! sym(var)))))`) but it would be better to use a simple solution – akrun Mar 06 '19 at 12:23
  • 1
    Agreed. It defeats the point of readability and using pipes when you need to use 3-4 extra functions to wrap a function call! – cyun Mar 06 '19 at 12:28
  • @akrun Why do we need to use !!sym() and not just !!(), sym() or get()? – skan Feb 09 '22 at 20:39
  • @skan it is an old solution. Some of the code blocks may not relevant i.e. `_at` – akrun Feb 09 '22 at 20:43

1 Answers1

2

One option as mentioned in the issues would be to use .data

multiply_by2 <- function(var){
 iris %>% 
       mutate_at("Sepal.Length", list( ~ .* .data[[var]]))

}

multiply_by2("Sepal.Width")
akrun
  • 874,273
  • 37
  • 540
  • 662