4
votes
library(tidyverse)
library(ggplot2) for diamonds dataset

I'm having trouble getting my function to work. What I'm trying to do, using the diamonds dataset form ggplot2 for this example, is to dplyr::group_by "cut" and "color", then dplyr::summarise to get counts. I used rlang and purrr to output both summaries of counts into list, then rename one of the columns, and bind them with dplyr::map_df. Finally, I want to reorder the "Cut" column based on another vector called "Order". The function works until I try to incorporate the row reordering...

This might not make sense for this data, but this is just for an example and it makes sense for my real data.

Anyways, the code below works...

Groups<-list("cut","color")

 Groups<-Groups%>%
 map_df(function(group){

     syms<-syms(group)

     diamonds%>%
         group_by(!!!syms)%>%
         summarise(Count=n())%>%
         set_names(c("Cut","Count"))
 })

And next, I want to reorder the rows based on the "Order" vector, which also works.

Order<-c("Good","Very Good","Premium","Ideal","Fair","E","F","G","D","H","J","I")

Groups%>%slice(match(Order, Cut))

However, this is where I'm stuck. I'm trying to do all this in one function, but it doesn't seem to work. I feel like I'm missing something small...

Fun<-function(df){

Order<-c("Good","Very Good","Premium","Ideal","Fair","E","F","G","D","H","J","I")

Groups<-list("cut","color")

 Groups<-Groups%>%
 map_df(function(group){

     syms<-syms(group)

     df%>%
         group_by(!!!syms)%>%
         summarise(Count=n())%>%
         set_names(c("Cut","Count"))%>%
         slice(match(Order,Cut))
return(df)
})
}

Here is another attempt...

Fun<-function(df){

Order<-c("Good","Very Good","Premium","Ideal","Fair","E","F","G","D","H","J","I")

Groups<-list("cut","color")

 Groups<-Groups%>%
 map_df(function(group){

     syms<-syms(group)

     df%>%
         group_by(!!!syms)%>%
         summarise(Count=n())%>%
         set_names(c("Cut","Count"))

df<-df%>%slice(match(Order,Cut))
return(df)
})
}

What am I missing here?

3

3 Answers

3
votes

We don't need to apply syms within a loop. It can take a vector/list of length greater than 1 and convert it to symbols. Therefore, loop through the syms and then use map to do the group_by on each symbol object

Fun<-function(df){

Order<-c("Good","Very Good","Premium","Ideal","Fair","E","F","G","D","H","J","I")

Groups<-list("cut","color")

Groups %>%
       syms %>%
       map_df(~ df %>%
               group_by(!!!  .x) %>%
               summarise(Count=n()) %>%
               set_names(c("Cut","Count")) %>%
               slice(match(Order,Cut)) #%>%                    
               #mutate(Cut = as.character(Cut)) 
               #to avoid the warning coercion of factor to character 


      )




}

Fun(diamonds)
# A tibble: 12 x 2
#   Cut       Count
#   <chr>     <int>
# 1 Good       4906
# 2 Very Good 12082
# 3 Premium   13791
# 4 Ideal     21551
# 5 Fair       1610
# 6 E          9797
# 7 F          9542
# 8 G         11292
# 9 D          6775
#10 H          8304
#11 J          2808
#12 I          5422
2
votes

Your first attempt at Fun works except that the results are allocated to the Group variable and not returned. Try the following

Fun<-function(df){

Order<-c("Good","Very Good","Premium","Ideal","Fair","E","F","G","D","H","J","I")

Groups<-list("cut","color")

 Groups%>%
 map_df(function(group){

     syms<-syms(group)

     df%>%
         group_by(!!!syms)%>%
         summarise(Count=n())%>%
         set_names(c("Cut","Count"))%>%
         slice(match(Order,Cut))
return(df)
})
}

Fun(diamonds)
1
votes

The possible correction to the problem. For the simplicity I have created a temp_df variable and returned the same.

Fun<-function(df){

  Order<-c("Good","Very Good","Premium","Ideal","Fair","E","F","G","D","H","J","I")

  Groups<-list("cut","color")

  Groups<-Groups%>%
    map_df(function(group){

      syms<-syms(group)

      temp <- df%>%
        group_by(!!!syms)%>%
        summarise(Count=n())%>%
        set_names(c("Cut","Count"))
    })

  temp_df <- Groups%>%slice(match(Order, Cut))
  return(temp_df)
}

> x <- Fun(diamonds)
> x
# A tibble: 12 x 2
   Cut       Count
   <chr>     <int>
 1 Good       4906
 2 Very Good 12082
 3 Premium   13791
 4 Ideal     21551
 5 Fair       1610
 6 E          9797
 7 F          9542
 8 G         11292
 9 D          6775
10 H          8304
11 J          2808
12 I          5422