1

One area in R that I struggle with is specifying variable names in functions. I have seen examples and sometimes gotten them to work using {{argument}} or other approaches, but I don't really understand why some things work and others don't. For example, I just tried to make a function that would use 2 variable values to generate a new variable. Reproducible example below:

look<-cars
twotoone<-function(v1,v2,nv){
  look<-look %>% mutate(nv=case_when(
    v1 > 4 & v2 > 4 ~ 1,
    TRUE ~ 0
  ))
  look<<-look
}
twotoone(speed,dist,allover4)

I get an error:

Error: Problem with mutate() column nv. i nv = case_when(v1 > 4 & v2 > 4 ~ 1, TRUE ~ 0). x object 'speed' not found

If I put all arguments in quotes:

twotoone('speed','dist','allover4')

there is no error, but the output data frame has the new variable nv instead of'allover4', and it's always =1 (no 0 assigned even when one of speed or distance are below 4). The same result happens if I just quote the first two arguments:

twotoone('speed','dist',allover4)

Any assistance to help me understand how I can expand the use of functions to help with recodes and composite variables, would be much appreciated. Thanks!!

moonwhaler
  • 21
  • 3

2 Answers2

1

We may use {{}} - curly-curly operator which does the non-standard evaluation of passing unquoted arguments - previously it was done with enquo + !!. Generally, the = cannot do evaluation of expression on the lhs whereas the := operator in tidyverse can do it and that is the reason we use :=

twotoone<-function(dat, v1,v2,nv){
  dat %>%
    mutate({{nv}} := case_when(
    {{v1}} > 4 & {{v2}} > 4 ~ 1,
    TRUE ~ 0
  ))
}

-testing

twotoone(cars, speed,dist,allover4)
   speed dist allover4
1     4    2        0
2     4   10        0
3     7    4        0
4     7   22        1
5     8   16        1
6     9   10        1
...
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Thank you - can you help me understand why this works / what the {{}} is doing? Part of my inquiry is better understanding what I'm doing to improve my ability. – moonwhaler Apr 24 '22 at 18:06
  • 1
    Actually - I found some details here that were helpful in understanding the purpose behind {{}} and := Thanks again! https://stackoverflow.com/questions/64065003/how-do-double-curly-brackets-work-in-dplyr – moonwhaler Apr 24 '22 at 18:10
1

Here is the version with ensym and !!:

twotoone<-function(df, v1,v2,nv){
  v1 <- rlang::ensym(v1)
  v2 <- rlang::ensym(v2)
  nv <- rlang::ensym(nv)
  
  df %>% 
    mutate(!!nv := case_when(
    !!v1 > 4 & !!v2 > 4 ~ 1,
    TRUE ~ 0
  ))
}
twotoone(cars, speed,dist,allover4)
   speed  dist allover4
   <dbl> <dbl>    <dbl>
 1     4     2        0
 2     4    10        0
 3     7     4        0
 4     7    22        1
 5     8    16        1
 6     9    10        1
 7    10    18        1
 8    10    26        1
 9    10    34        1
10    11    17        1
# ... with 40 more rows
TarJae
  • 72,363
  • 6
  • 19
  • 66