使用dplyr进行分组汇总时如何为无值的类别填充0?
实现方法
默认group_by()分组统计的逻辑是自动剔除无观测值的交叉分组,要补全所有年龄-教育水平的交叉配对、给空组合赋值0计数,常用两种落地方式:
方法1:count()搭配tidyr::complete()自动补全
这是最简洁的实现,不需要手动维护分类水平列表:
set.seed(2021) age <- floor(runif(35, min = 20, max = 25)) data.frame(age = age) %>% mutate(education = sample( c("Low", "Mid-level", "High"), size = nrow(.), prob = c(0.55, 0.2, 0.25), replace = TRUE )) %>% # 第一步:正常统计有观测的交叉组合计数 count(age, education, name = "n") %>% # 第二步:补全所有年龄和教育水平的交叉组合,缺失位置的n值填0 tidyr::complete( age, education, fill = list(n = 0) )
这个方法会自动提取数据中所有出现过的唯一age值、唯一education值做全量交叉,不会额外补充数据里完全不存在的取值,适配这个案例的离散年龄取值场景。
方法2:纯dplyr实现,利用因子分组的.drop = FALSE参数
如果不想依赖tidyr的函数,可以手动给分类变量设定全量水平,再关闭分组时自动丢空组的逻辑:
set.seed(2021) age <- floor(runif(35, min = 20, max = 25)) data.frame(age = age) %>% mutate( education = sample( c("Low", "Mid-level", "High"), size = nrow(.), prob = c(0.55, 0.2, 0.25), replace = TRUE ), # 必须提前把education转为因子,明确所有需要保留的水平 education = factor(education, levels = c("Low", "Mid-level", "High")) ) %>% # 分组时设置.drop=FALSE,不丢弃没有观测的空分组 group_by(age, education, .drop = FALSE) %>% summarise(n = n(), .groups = "drop")
常见踩坑点
group_by()的.drop参数默认是TRUE,会自动剔除没有观测的分组,不手动设为FALSE的话,哪怕是因子变量也会丢失空组合- 如果不把字符型的
education转为带全量水平的因子,就算加了.drop = FALSE也无法补全缺失组合——字符型变量没有预先定义的“应存在但无观测”的水平规则 - 这个方法灵活性更强,如果需要补充数据中完全没出现过的取值(比如新增25岁年龄组的三类教育水平记录),只需要在
factor()的levels参数里加上对应取值即可,不需要额外写补全逻辑 - 如果交叉用的变量是连续型数值(不是离散整数),用
complete()会自动生成变量取值范围内的冗余连续值,这种场景下更推荐用方法2的固定水平方式,精准控制需要补全的组合范围。
内容的提问来源于stack exchange,提问作者johnny
相关产品推荐
相关产品推荐

