quosure in case_when and/or ifelse

101 Views Asked by At

I am trying to sort out how to use a quosure (if that's the right tool) to pass variable names to either an if_else(...) or a case_when(...) inside a mutate command using a string argument passed from a function. A quick reproducible example that isolates my question:

#create a simple 3x3 tibble
library(tidyverse)
lev<-c("a","b","c")
a=seq(1,3)
test<-tibble("index"=lev,"raw"=as.numeric(a),"x2"=a*2, x3 = a*3)

Now, suppose I want to replace the value of "raw" with zero in cases where index=="a". I can do this with raw code:

test %>% 
  mutate(raw=case_when(
  (index=="a")~0,
  TRUE~raw
)
)

and I get output:

# A tibble: 3 x 4
  index   raw    x2    x3
  <chr> <dbl> <dbl> <dbl>
1 a         0     2     3
2 b         2     4     6
3 c         3     6     9

Perfect. I can do this in a function two different ways (if_else or case_when). First:

sending_test_cw<-function(data_sent)
{
  data_sent %>% 
    mutate(raw=case_when(
      (index=="a")~0,
      TRUE~raw)
    )
}

yielding output:

sending_test_cw(test)

R > sending_test_cw(test)
# A tibble: 3 x 4
  index   raw    x2    x3
  <chr> <dbl> <dbl> <dbl>
1 a         0     2     3
2 b         2     4     6
3 c         3     6     9

or, for case_when:

sending_test_ie<-function(data_sent)
{
  data_sent %>% 
    mutate(
    raw=ifelse(index=="a",0,raw))
}

R > sending_test_ie(test)
# A tibble: 3 x 4
  index   raw    x2    x3
  <chr> <dbl> <dbl> <dbl>
1 a         0     2     3
2 b         2     4     6
3 c         3     6     9

and, again, I get the intended output.

Now, I want to create a function that works when sending the name of the column in which the index is held, something like this:

sending_test_qu<-function(data_sent,index_id="index")
{
  index_quo<-enquo(index_id)
  data_sent %>% 
    #group_by(index)%>%
    mutate(
      raw=ifelse(!!index_quo=="a",0,raw),
      raw_2=case_when(
        (!!index_quo=="a")~0,
        TRUE~raw)
    )
}

sending_test_qu(test)

But, I can't get that work work.

sending_test_qu<-function(data_sent,index_id="index")
{
  index_quo<-enquo(index_id)
  data_sent %>% 
    #group_by(index)%>%
    mutate(
      raw=ifelse(!!index_quo=="a",0,raw),
      raw_2=case_when(
        (!!index_quo=="a")~0,
        TRUE~raw)
    )
}

sending_test_qu(test)

this produces output as follows:

R > sending_test_qu(test)
# A tibble: 3 x 5
  index   raw    x2    x3 raw_2
  <chr> <dbl> <dbl> <dbl> <dbl>
1 a         1     2     3     1
2 b         1     4     6     1
3 c         1     6     9     1

Any suggestions or quosure pointers welcome.

1

There are 1 best solutions below

0
On BEST ANSWER

Convert to symbol with ensym as the input is string (or can also be unquoted), If the input is unquoted, enquo with !! can be used or more directly {{}}.

sending_test_qu<-function(data_sent,index_id="index")
{
  index_sym<- rlang::ensym(index_id)
  data_sent %>% 
    #group_by(across(all_of(index_id)))%>%
    mutate(
      raw=ifelse(!!index_sym=="a",0,raw),
      raw_2=case_when(
        (!!index_sym=="a")~0,
        TRUE~raw)
    )
}

testing

# default argument value for index_id
> sending_test_qu(test)
 A tibble: 3 × 5
  index   raw    x2    x3 raw_2
  <chr> <dbl> <dbl> <dbl> <dbl>
1 a         0     2     3     0
2 b         2     4     6     2
3 c         3     6     9     3
# pass as unquoted
> sending_test_qu(test, index)
# A tibble: 3 × 5
  index   raw    x2    x3 raw_2
  <chr> <dbl> <dbl> <dbl> <dbl>
1 a         0     2     3     0
2 b         2     4     6     2
3 c         3     6     9     3
# pass as string
> sending_test_qu(test, "index")
# A tibble: 3 × 5
  index   raw    x2    x3 raw_2
  <chr> <dbl> <dbl> <dbl> <dbl>
1 a         0     2     3     0
2 b         2     4     6     2
3 c         3     6     9     3