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.
CodePudding user response:
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