使用dplyr按组统计后添加子组计数的技术实现问题
最近我碰到了一个需求:用dplyr做分组统计后,给每个子组的因子级别新增对应列来展示计数,同时还要保留分组后的各类统计指标(比如均值、标准差这些)。试了好几种方法都踩坑了,后来在@Akrun的帮助下解决了,把过程和方案分享给大家:
问题背景
我需要实现的效果是:对主分组(比如性别sexo)做基础统计后,为每个子组级别(比如学历Escolaridade)单独生成一列,展示该子组在主分组内的计数,同时避免代码冗余,不需要用到gather函数。
踩过的坑:无效/有问题的尝试
一开始我直接用group_by加summarise,虽然接近目标,但出现了输出重复的问题:
descritivos %>% group_by(sexo) %>% summarise(n=n(),Idade_media = mean(idade, na.rm=T), idade_sd=sd(idade, na.rm=T), qtde_sexo = n(), Proporção_sexo = n()/nrow(.), Pontuação_media=mean(total), pontuacao_sd=sd(total), n_unique = n_distinct(Escolaridade))
后来尝试结合group_by和spread来转置子组列,但输出完全不符合预期:
descritivos %>% group_by(sexo, Escolaridade) %>% summarise(n=n(),Idade_media = mean(idade, na.rm=T), idade_sd=sd(idade, na.rm=T), qtde_sexo = n(), Proporção_sexo = n()/nrow(.), Pontuação_media=mean(total), pontuacao_sd=sd(total), n_unique = n_distinct(Escolaridade)) %>% spread(Escolaridade, n) spread(count(Escolaridade), n, fill=0)
为了方便测试,我准备了复现数据:
library(tidyverse) ds <- data.frame(sex=c(0,1), schooling=c("k12","high","college","university"), age=rnorm(mean=20,sd=2, n=40)) ds %>% group_by(sex, schooling) %>% summarise(mean(age), n=n()) %>% spread(schooling, n) ds %>% group_by(sex, schooling) %>% summarise(n()) %>% t()
最终解决方法
核心思路是嵌套分组:先按主分组字段分组,再用add=TRUE参数保留主分组的同时,加入子组字段和需要保留的统计指标,最后用spread将子组级别转为列。
针对实际数据集的可行代码
descritivos %>% group_by(sexo) %>% group_by(Escolaridade, Idade_media = mean(idade, na.rm=T), idade_sd=sd(idade, na.rm=T), qtde_sexo = n(), Proporção_sexo = n()/nrow(.), Pontuação_media=mean(total), pontuacao_sd=sd(total), add=TRUE) %>% summarise(n=n()) %>% spread(Escolaridade, n)
针对复现数据集的可行代码
ds %>% group_by(sex) %>% group_by(schooling = paste0("school", schooling), Mean = mean(age), ndist = n_distinct(schooling), add = TRUE) %>% summarise(n = n()) %>% spread(schooling, n)
这个方法既保留了所有需要的统计指标,又把每个子组级别转为了单独的列,完全符合预期,而且代码简洁不需要额外的gather操作。
内容的提问来源于stack exchange,提问作者Luis
相关产品推荐
相关产品推荐

