Grouping all possible combinations of several variables with dplyr

Given a situation such as:

library(dplyr) myData <- tbl_df(data.frame( var1 = rnorm(100), var2 = letters[1:3] %>% sample(100, replace = TRUE) %>% factor(), var3 = LETTERS[1:3] %>% sample(100, replace = TRUE) %>% factor(), var4 = month.abb[1:3] %>% sample(100, replace = TRUE) %>% factor())) 

I would like to group `myData 'so that I can find a summary grouping of the data with all possible combinations of var2, var3 and var4.

I can create a list with all possible combinations of variables as character values ​​using

 groupNames <- names(myData)[2:4] myGroups <- Map(combn, list(groupNames), seq_along(groupNames), simplify = FALSE) %>% unlist(recursive = FALSE) 

My plan was to make separate datasets for each combination of variables with a for () loop, something like

 ### This Does Not Work for (i in 1:length(myGroups)){ assign( myGroups[i]%>% unlist() %>% paste0(collapse = "")%>% paste0("Data"), myData %>% group_by_(lapply(myGroups[[i]], as.symbol)) %>% summarise( n = length(var1), avgVar2 = var2 %>% mean())) } 

Admittedly, I am not very good at listing, and finding this problem was a bit tricky as dpyr updates changed how grouping works a bit.

If there is a better way to do this than separate datasets I would like to know.

I have a loop like the above when I only group by one variable.

Any help is appreciated! Thanks!

+7
r dplyr summary
source share
3 answers

It seems convinced, and there is probably a way to simplify or come up with it with do , but it works. Using myData and myGroups ,

 results = lapply(myGroups, FUN = function(x) { do.call(what = group_by_, args = c(list(myData), x)) %>% summarise( n = length(var1), avgVar1 = mean(var1)) } ) > results[[1]] Source: local data frame [3 x 3] var2 n avgVar1 1 a 31 0.38929738 2 b 31 -0.07451717 3 c 38 -0.22522129 > results[[4]] Source: local data frame [9 x 4] Groups: var2 var2 var3 n avgVar1 1 a A 11 -0.1159160 2 a B 11 0.5663312 3 a C 9 0.7904056 4 b A 7 0.0856384 5 b B 13 0.1309756 6 b C 11 -0.4192895 7 c A 15 -0.2783099 8 c B 10 -0.1110877 9 c C 13 -0.2517602 > results[[7]] # I won't paste them here, but it has all 27 rows, grouped by var2, var3 and var4. 

I changed your summarise call to middle var1 since var2 not numeric.

+7
source share

I created a function based on @Gregor's answer and the following comments:

 library(magrittr) myData <- tbl_df(data.frame( var1 = rnorm(100), var2 = letters[1:3] %>% sample(100, replace = TRUE) %>% factor(), var3 = LETTERS[1:3] %>% sample(100, replace = TRUE) %>% factor(), var4 = month.abb[1:3] %>% sample(100, replace = TRUE) %>% factor())) 

combSummarise function

 combSummarise <- function(data, variables=..., summarise=...){ # Get all different combinations of selected variables (credit to @Michael) myGroups <- lapply(seq_along(variables), function(x) { combn(c(variables), x, simplify = FALSE)}) %>% unlist(recursive = FALSE) # Group by selected variables (credit to @konvas) df <- eval(parse(text=paste("lapply(myGroups, function(x){ dplyr::group_by_(data, .dots=x) %>% dplyr::summarize_( \"", paste(summarise, collapse="\",\""),"\")})"))) %>% do.call(plyr::rbind.fill,.) groupNames <- c(myGroups[[length(myGroups)]]) newNames <- names(df)[!(names(df) %in% groupNames)] df <- cbind(df[, groupNames], df[, newNames]) names(df) <- c(groupNames, newNames) df } 

Call combSummarise

 combSummarise (myData, var=c("var2", "var3", "var4"), summarise=c("length(var1)", "mean(var1)", "max(var1)")) 

or

 combSummarise (myData, var=c("var2", "var4"), summarise=c("length(var1)", "mean(var1)", "max(var1)")) 

or

 combSummarise (myData, var=c("var2", "var4"), summarise=c("length(var1)")) 

etc.

+3
source share

Inspired by the answers of Gregor and dimitris_ps, I wrote a dplyr style function that works to summarize for all combinations of group variables.

 summarise_combo <- function(data, ...) { groupVars <- group_vars(data) %>% map(as.name) groupCombos <- map( 0:length(groupVars), ~combn(groupVars, ., simplify=FALSE) ) %>% unlist(recursive = FALSE) results <- groupCombos %>% map(function(x) {data %>% group_by(!!! x) %>% summarise(...)} ) %>% bind_rows() results %>% select(!!! groupVars, everything()) } 

Example

 library(tidyverse) mtcars %>% group_by(cyl, vs) %>% summarise_combo(cyl_n = n(), mean(mpg)) 
+2
source share

All Articles