Group by multiple columns in dplyr, using string vector input Group by multiple columns in dplyr, using string vector input r r

Group by multiple columns in dplyr, using string vector input


Just so as to write the code in full, here's an update on Hadley's answer with the new syntax:

library(dplyr)df <-  data.frame(    asihckhdoydk = sample(LETTERS[1:3], 100, replace=TRUE),    a30mvxigxkgh = sample(LETTERS[1:3], 100, replace=TRUE),    value = rnorm(100))# Columns you want to group bygrp_cols <- names(df)[-3]# Convert character vector to list of symbolsdots <- lapply(grp_cols, as.symbol)# Perform frequency countsdf %>%    group_by_(.dots=dots) %>%    summarise(n = n())

output:

Source: local data frame [9 x 3]Groups: asihckhdoydk  asihckhdoydk a30mvxigxkgh  n1            A            A 102            A            B 103            A            C 134            B            A 145            B            B 106            B            C 127            C            A  98            C            B 129            C            C 10


The support for this in dplyr is currently pretty weak, eventually I think the syntax will be something like:

df %.% group_by(.groups = c("asdfgfTgdsx", "asdfk30v0ja"))

But that probably won't be there for a while (because I need to think through all the consequences).

In the meantime, you can use regroup(), which takes a list of symbols:

library(dplyr)df <-  data.frame(  asihckhdoydk = sample(LETTERS[1:3], 100, replace=TRUE),  a30mvxigxkgh = sample(LETTERS[1:3], 100, replace=TRUE),  value = rnorm(100))df %.%  regroup(list(quote(asihckhdoydk), quote(a30mvxigxkgh))) %.%  summarise(n = n())

If you have have a character vector of column names, you can convert them to the right structure with lapply() and as.symbol():

vars <- setdiff(names(df), "value")vars2 <- lapply(vars, as.symbol)df %.% regroup(vars2) %.% summarise(n = n())


Since this question was posted, dplyr added scoped versions of group_by (documentation here). This lets you use the same functions you would use with select, like so:

data = data.frame(    asihckhdoydkhxiydfgfTgdsx = sample(LETTERS[1:3], 100, replace=TRUE),    a30mvxigxkghc5cdsvxvyv0ja = sample(LETTERS[1:3], 100, replace=TRUE),    value = rnorm(100))# get the columns we want to average withincolumns = names(data)[-3]library(dplyr)df1 <- data %>%  group_by_at(vars(one_of(columns))) %>%  summarize(Value = mean(value))#compare plyr for referencedf2 <- plyr::ddply(data, columns, plyr::summarize, value=mean(value))table(df1 == df2, useNA = 'ifany')## TRUE ##  27 

The output from your example question is as expected (see comparison to plyr above and output below):

# A tibble: 9 x 3# Groups:   asihckhdoydkhxiydfgfTgdsx [?]  asihckhdoydkhxiydfgfTgdsx a30mvxigxkghc5cdsvxvyv0ja       Value                     <fctr>                    <fctr>       <dbl>1                         A                         A  0.040950022                         A                         B  0.249439353                         A                         C -0.257838924                         B                         A  0.151618055                         B                         B  0.271899746                         B                         C  0.208588977                         C                         A  0.195022218                         C                         B  0.568375489                         C                         C -0.22682998

Note that since dplyr::summarize only strips off one layer of grouping at a time, you've still got some grouping going on in the resultant tibble (which can sometime catch people by suprise later down the line). If you want to be absolutely safe from unexpected grouping behavior, you can always add %>% ungroup to your pipeline after you summarize.