循环中使用dplyr的group_by_at/summarise_at后如何保留空组?
解决dplyr分组后保留空组的问题
我来帮你搞定这个困扰!你遇到的核心问题是:使用group_by_at()分组时,dplyr默认会丢弃没有数据的空组,之后用complete()补全时又因为索引的问题找不到正确的分组变量取值范围。这里有几个实用的解决办法:
方法1:分组时直接保留空组(最推荐)
dplyr的分组函数(包括group_by_at())有一个.drop=FALSE参数,设置它就能在分组阶段直接保留所有可能的分组,不管该组有没有数据。这样后续汇总后就不会丢失空组,再用complete()补全缺失列就很顺畅了:
library(dplyr) library(tidyr) # 推荐用tidyr的complete,功能更完善 df2 <- mtcars %>% # 按第10列分组,同时保留所有空组 group_by_at(vars(10), .drop = FALSE) %>% # 汇总第1列的均值,同时取消分组(.groups="drop") summarise_at(vars(1), mean, na.rm = TRUE, .groups = "drop") %>% # 补全gear的所有组,给Gewicht列填充默认值1 complete(gear, fill = list(Gewicht = 1)) df2
如果你用的是较新版本的dplyr(1.0.0+),更推荐用across()替代group_by_at()和summarise_at(),写法更直观:
df2 <- mtcars %>% group_by(across(10), .drop = FALSE) %>% summarise(Mittelwert = mean(across(1), na.rm = TRUE), .groups = "drop") %>% complete(gear, fill = list(Gewicht = 1))
方法2:补全时指定分组变量的所有可能值
如果不想修改分组逻辑,也可以在complete()里明确指定分组变量的所有取值范围,直接从原始数据中获取:
df2 <- mtcars %>% group_by_at(10) %>% summarise_at(1, mean, na.rm = TRUE) %>% # 明确gear的取值为原始mtcars中所有存在的gear值 complete(gear = unique(mtcars$gear), fill = list(Gewicht = 1))
为什么你的原始代码不行?
你原来的complete(gear, ...)之所以没生效,是因为经过group_by_at()和summarise_at()后,空组已经被丢弃了,此时结果里的gear列只有有数据的取值,complete()不知道要补哪些空组。而上面两种方法要么从源头保留空组,要么告诉complete()所有可能的分组取值,就能解决问题啦。
内容的提问来源于stack exchange,提问作者user7353167
相关产品推荐
相关产品推荐

