Is this what you're trying to do:
library(tidyverse)
df %>%
group_by(cls,grd,typ) %>%
summarise(pnts = sum(pnts)) %>%
mutate(pct = pnts/sum(pnts)) %>%
bind_rows(df %>%
group_by(cls, grd) %>%
summarise(pnts = sum(pnts)) %>%
mutate(pct = pnts/sum(pnts),
typ = "All")) %>%
bind_rows(df %>%
group_by(cls) %>%
summarise(pnts = sum(pnts)) %>%
mutate(pct = pnts/sum(pnts),
grd = "All",
typ = "All"))
cls grd typ pnts pct
<fct> <chr> <chr> <int> <dbl>
1 A A1 m 1 1
2 A A2 m 2 0.222
3 A A2 o 7 0.778
4 B B1 m 1 0.25
5 B B1 p 3 0.75
6 B B2 n 2 0.333
7 B B2 p 4 0.667
8 A A1 All 1 0.1
9 A A2 All 9 0.9
10 B B1 All 4 0.4
11 B B2 All 6 0.6
12 A All All 10 0.5
13 B All All 10 0.5
This can be shortened to the following:
groups = c("cls","grd","typ")
map_df(length(groups):1,
~ df %>%
group_by_at(groups[1:.x]) %>%
summarise(pnts = sum(pnts)) %>%
mutate(pct = pnts/sum(pnts))) %>%
map_if(~!is.numeric(.), fct_explicit_na, "All") %>%
bind_cols()
And generalized with tidy evaluation:
my_summary = function(data, value.var, ...) {
groups = enquos(...)
map_df(length(groups):1,
~ data %>%
group_by_at(groups[1:.x]) %>%
summarise({{value.var}} := sum({{value.var}})) %>%
mutate(pct = {{value.var}}/sum({{value.var}}))) %>%
map_if(~!is.numeric(.), fct_explicit_na, "All") %>%
bind_cols()
}
my_summary(df, pnts, cls, grd, typ)
my_summary(diamonds, price, cut, color)