Reputation: 21357
Suppose I have this code:
> df<-data.frame(a=c(1,1,1,2,2,2), b=c(T,T,F,F,F,T))
> df %>% group_by(a) %>% summarize(trues=sum(b), falses=sum(!b))
# A tibble: 2 x 3
a trues falses
<dbl> <int> <int>
1 1 2 1
2 2 1 2
and I want to use a string variable to give b
(in a for loop, for example). It's exactly like this question I think, but I can't seem to get it to work.
Some failed attempts:
var <- 'b'
df %>% group_by(a) %>% summarize_(trues=sum(var), falses=sum(!var))
df %>% group_by(a) %>% summarize(trues=sum({{var}}), falses=sum(!{{var}}))
df %>% group_by(a) %>% summarize_(trues=sum({{var}}), falses=sum(!{{var}}))
foo1 <- function(df, var) {
df %>% group_by(a) %>% summarize(trues=sum({{var}}), falses=sum(!{{var}}))
}
foo1(df, 'b')
foo2 <- function(df, var) {
var <- enquo(var)
df %>% group_by(a) %>% summarize(trues=sum(!!var), falses=sum(! !!var))
}
foo2(df, 'b')
Perhaps I could use the lazyeval
package in the other question, but I'd rather know how to do it with just the tidyverse.
Upvotes: 3
Views: 206
Reputation: 886938
In this case, it is better to use ensym
as we are passing a string. Also, the ensym
works with unquoted argument as well
foo2 <- function(df, var) {
var <- ensym(var)
df %>%
group_by(a) %>%
summarize(trues=sum(!!var),
falses=sum(! (!!var)))
}
foo2(df, 'b')
# A tibble: 2 x 3
# a trues falses
#* <dbl> <int> <int>
#1 1 2 1
#2 2 1 2
foo2(df, b)
# A tibble: 2 x 3
# a trues falses
#* <dbl> <int> <int>
#1 1 2 1
#2 2 1 2
If the argument passed is an object, evaluate (!!
) while passing into the function to avoid the literal evaluation
foo2(df, !!var)
# A tibble: 2 x 3
# a trues falses
#* <dbl> <int> <int>
#1 1 2 1
#2 2 1 2
Upvotes: 3