Indrajeet Patil
Indrajeet Patil

Reputation: 4889

inputting dots in dplyr without tilde or quotes

How to get the following code to work without quotes or tilde?

This is important to me because I am using this standalone code inside a custom function where introducing quotes or tilde complicates things.

Thanks.

dataframe <- as.data.frame(cbind(gender = c("male", "female", "female", "female", "male", "female", "male"),
                                 pet = c("dog", "cat", "dog", "cat", "cat", "cat", "dog")))

library(dplyr)

## with tilde

dplyr::group_by_(dataframe, .dots = c(~gender, ~pet)) %>%
  dplyr::summarize(counts = n()) %>%
  dplyr::mutate(perc = (counts / sum(counts)) * 100) %>%
  dplyr::arrange(desc(perc))
#> # A tibble: 4 x 4
#> # Groups: gender [2]
#>   gender pet   counts  perc
#>   <fct>  <fct>  <int> <dbl>
#> 1 female cat        3  75.0
#> 2 male   dog        2  66.7
#> 3 male   cat        1  33.3
#> 4 female dog        1  25.0

## with quotes

dplyr::group_by_(dataframe, .dots = c('gender', 'pet')) %>%
  dplyr::summarize(counts = n()) %>%
  dplyr::mutate(perc = (counts / sum(counts)) * 100) %>%
  dplyr::arrange(desc(perc))
#> # A tibble: 4 x 4
#> # Groups: gender [2]
#>   gender pet   counts  perc
#>   <fct>  <fct>  <int> <dbl>
#> 1 female cat        3  75.0
#> 2 male   dog        2  66.7
#> 3 male   cat        1  33.3
#> 4 female dog        1  25.0

## without tilde

dplyr::group_by_(dataframe, .dots = c(gender, pet)) %>%
  dplyr::summarize(counts = n()) %>%
  dplyr::mutate(perc = (counts / sum(counts)) * 100) %>%
  dplyr::arrange(desc(perc))
#> Error in compat_lazy_dots(.dots, caller_env(), ...): object 'gender' not found

Upvotes: 3

Views: 1485

Answers (3)

vsb
vsb

Reputation: 428

Two ways multiple grouping using dplyr programming:-
Way1

f1<-function(df,...){
 grp_vars<-quos(...) 

 df %>% 
 group_by(!!!grp_vars) %>%  
   summarize(counts= n()) %>% 
   mutate(perc = (counts/sum(counts))*100) %>% 
   arrange(desc(perc))
}

f1(dataframe, gender, pet)

Result1:

 # A tibble: 4 x 4
    # Groups:   gender [2]
      gender pet   counts  perc
      <fct>  <fct>  <int> <dbl>
    1 female cat        3  75.0
    2 male   dog        2  66.7
    3 male   cat        1  33.3
    4 female dog        1  25.0

Way2:

f2<-function(df, grp_vars){
  df %>% 
    group_by(!!!grp_vars) %>% 
    summarize(counts= n()) %>% 
    mutate(perc = (counts/sum(counts))*100) %>% 
    arrange(desc(perc))
}
f2(dataframe, quos(gender,pet))

Result2:

# A tibble: 4 x 4
# Groups:   gender [2]
  gender pet   counts  perc
  <fct>  <fct>  <int> <dbl>
1 female cat        3  75.0
2 male   dog        2  66.7
3 male   cat        1  33.3
4 female dog        1  25.0

Upvotes: 2

akrun
akrun

Reputation: 887501

If we need to use it in a function, then pass the groups as a quosure and evaluate with !!!

f1 <- function(dat, groups) {
 dat %>%
    group_by(!!! groups) %>%
    summarize(counts = n()) %>%
    mutate(perc = (counts / sum(counts)) * 100) %>% 
    arrange(desc(perc))
 }

f1(dataframe, quos(gender, pet))
# A tibble: 4 x 4
# Groups: gender [2]
#  gender pet    counts  perc
#  <fctr> <fctr>  <int> <dbl>
#1 female cat         3  75.0
#2 male   dog         2  66.7
#3 male   cat         1  33.3
#4 female dog         1  25.0

In addition to the above, we can have ... as argument for groups, convert it to strings with quo_name and pass it on group_by_at

f2 <- function(dat, ...) {
  groups <-  rlang::enquos(...) %>%
                    purrr::map_chr(quo_name)

 dat %>%
     group_by_at(vars(groups)) %>%
     summarize(counts = n()) %>%
     mutate(perc = (counts / sum(counts)) * 100) %>% 
    arrange(desc(perc))
}

f2(dataframe, gender, pet)

Upvotes: 3

MKR
MKR

Reputation: 20095

Use group_by instead:

dplyr::group_by(dataframe, gender, pet) %>%
  dplyr::summarize(counts = n()) %>%
  dplyr::mutate(perc = (counts / sum(counts)) * 100) %>%
  dplyr::arrange(desc(perc))

#The result:
# Groups: gender [2]
#  gender pet    counts  perc
#  <fctr> <fctr>  <int> <dbl>
#1 female cat         3  75.0
#2 male   dog         2  66.7
#3 male   cat         1  33.3
#4 female dog         1  25.0

Upvotes: 2

Related Questions