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.
Convert to sym
bol 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