Deepak Agarwal
Deepak Agarwal

Reputation: 399

Group_by inside a function

I am trying to use the group_by function inside of a function but it doesn't seem to work. I found an example in another post as below (this works) :-

dat <- mtcars[c(2:4,11)]


grp <- function(x) {
  group_by(dat,!!as.name(x)) %>%
  summarise(n=n()) %>% 
  mutate(pc=scales::percent(n/sum(n))) %>% 
  arrange(desc(n)) %>% head()
}


lapply(colnames(dat), grp)

What I don't understand is why do I need to data frame name in the group_by function - doesn't group_by function work this way :-

data %>% group_by(lgID) %>% summarise(mean_run = mean(HR))

where the data is piped to the group_by function?

Also, why do I need '!!as.name(x)' - what does this do?

Further, why does the version shown above work and this version shown below doesn't?

grp <- function(x) {
  group_by(x) %>%
  summarise(n=n()) %>% 
  mutate(pc=scales::percent(n/sum(n))) %>% 
  arrange(desc(n)) %>% head()
}


lapply(colnames(dat), grp)

Obviously I am missing something here!

Best regards

Deepak

Upvotes: 0

Views: 121

Answers (1)

akrun
akrun

Reputation: 887951

If we need to pass both index and strings as 'x', wrap it inside across within group_by

library(dplyr) # version >= 1.0.0

f1 <- function(data, x) {
    data %>%
     group_by(across(all_of(x))) %>%
     summarise(n=n(), .groups = 'drop') %>% 
     mutate(pc=scales::percent(n/sum(n))) %>% 
     arrange(desc(n)) %>% 
     head()
}

If we have an older version, use group_by_at(x)

-apply the function

out1 <- lapply(colnames(dat), function(x) f1(dat, x))

Or use index

out2 <- lapply(seq_along(dat), function(i) f1(dat, i))

identical(out1, out2)
#[1] TRUE

-output

out1[[1]]
# A tibble: 3 x 3
#    cyl     n pc   
#  <dbl> <int> <chr>
#1     8    14 43.8%
#2     4    11 34.4%
#3     6     7 21.9%

out2[[1]]
# A tibble: 3 x 3
#    cyl     n pc   
#  <dbl> <int> <chr>
#1     8    14 43.8%
#2     4    11 34.4%
#3     6     7 21.9%

Upvotes: 1

Related Questions