R语言dplyr按多列分组批量统计多列计数与占比
问题描述
现有全因子类型数据框df,包含gender、country2个分组字段,以及a、b、c、d4个待统计字段,数据构造代码如下:
set.seed(123) gender <- sample(1:2,12,replace=T) country <- c('FIN', 'FIN', 'EST', 'NIG','NIG','JAM', 'FIN', 'NIG', 'EST', 'NIG','NIG','JAM','FIN', 'FIN', 'EST', 'NIG','NIG','JAM', 'FIN', 'NIG', 'EST', 'NIG','NIG','JAM') a <- sample(1:5,24,,replace=T) b <- sample(1:5,24,,replace=T) c <- sample(1:5,24,,replace=T) d <- sample(1:5,24,,replace=T) # 合并变量生成数据框 df <- data.frame(gender,country,a,b,c,d) df <- df %>% mutate_at(c("gender","country","a","b","c","d"), as.factor)
需求为按gender、country分组,统计a到d所有列的组内占比百分比与对应样本量n,要求不重复编写同类代码,批量完成4个字段的统计。
目前单字段(a列)的统计逻辑已验证可行:先按gender、country、a分组计算各组样本量totaln,再按country、gender分组计算组内百分比percentage,代码如下:
df %>% group_by(gender,country,a) %>% summarise(totaln=n()) %>% group_by(country,gender) %>% mutate(percentage=totaln/sum(totaln)*100)
a列统计输出结果如下:
gender country a totaln percentage <fct> <fct> <fct> <int> <dbl> 1 1 EST 1 2 50 2 1 EST 3 1 25 3 1 EST 4 1 25 4 1 FIN 1 1 25 5 1 FIN 2 3 75 6 1 NIG 1 1 25 7 1 NIG 2 1 25 8 1 NIG 3 1 25 9 1 NIG 4 1 25 10 2 FIN 1 1 50 11 2 FIN 3 1 50 12 2 JAM 1 2 50 13 2 JAM 3 2 50 14 2 NIG 3 1 16.7 15 2 NIG 4 1 16.7 16 2 NIG 5 4 66.7
实现方案
通过长表转换统一处理所有待统计字段,无需逐列重复编写统计代码,完整代码如下:
library(tidyverse) df %>% pivot_longer( cols = a:d, names_to = "var_name", values_to = "var_level" ) %>% group_by(gender, country, var_name, var_level) %>% summarise(totaln = n(), .groups = "drop_last") %>% mutate(percentage = totaln / sum(totaln) * 100) %>% ungroup()
逻辑说明:
- 用
pivot_longer将a-d四个待统计字段从宽格式转为长格式:var_name列标记当前统计的字段名(a/b/c/d),var_level列存储对应字段的因子取值 - 分组统计时将
var_name、var_level加入分组规则,所有字段的计数、占比计算一次性完成 summarise中设置.groups = "drop_last"会自动移除最内层的var_level分组,刚好匹配后续按gender、country、var_name分组计算组内占比的需求,无需重复调用group_by调整分组层级
输出结果中var_name为a的部分和单跑a列的结果完全一致,b、c、d列的统计逻辑完全相同。如果需要宽表格式的结果,可在上述代码末尾追加pivot_wider逻辑按需转换。
内容的提问来源于stack exchange,提问作者user19250276
相关产品推荐
相关产品推荐

