在R语言中计算分组汇总列相对频率的问题求助
解决R语言dplyr分组汇总后计算相对频率的问题
这个问题我太熟悉了!你遇到的核心问题是分组上下文的干扰——当你在group_by(x)的环境里直接计算p时,sum(total)只会计算当前分组内的总和,而不是所有分组汇总后的总金额,所以每个分组的total除以自己自然就得到100%啦。
为什么你的写法会出错?
在你尝试的两种写法里:
data %>% group_by(x) %>% summarise(total = sum(dollars), p = scales::percent(total/sum(total)))
summarise是针对每个分组单独执行的,每一次迭代中total是当前分组的求和结果,而sum(total)其实就是这个分组自己的total(因为每个分组只生成一行汇总数据),所以total/sum(total)恒等于1,最终显示100%。
正确的解决思路
我们需要先完成分组汇总,再跳出分组上下文计算全局的相对频率,有几种简单的实现方式:
方法1:先汇总,再取消分组计算百分比
这是最直观的方式,先用group_by()+summarise()得到每个分组的总金额,然后用ungroup()取消分组,再用mutate()计算相对频率:
library(dplyr) library(scales) data %>% group_by(x) %>% summarise(total = sum(dollars)) %>% ungroup() %>% # 关键步骤:取消分组,让sum(total)计算所有分组的总金额 mutate(p = percent(total / sum(total), accuracy = 0.01)) # accuracy控制小数位数
运行后会得到你期望的结果:
x total p <chr> <dbl> <chr> 1 expense 1 3600 46.45% 2 expense 2 2150 27.74% 3 expense 3 2000 25.81%
方法2:先计算全局总金额,再直接引用
如果不想处理分组状态,可以先算出整个数据集的总金额,再在汇总时直接使用:
total_global <- sum(data$dollars, na.rm = TRUE) # na.rm避免空值干扰 data %>% group_by(x) %>% summarise(total = sum(dollars), p = percent(total / total_global, accuracy = 0.01))
这种方式逻辑更直接,适合需要重复使用全局总金额的场景。
方法3:使用窗口函数指定全局范围(进阶)
如果你想在不取消分组的情况下完成计算,可以用窗口函数的.by = NULL参数指定计算全局总和:
data %>% group_by(x) %>% summarise(total = sum(dollars), p = percent(total / sum(total, .by = NULL), accuracy = 0.01))
.by = NULL会强制sum(total)计算整个数据集的总和,而不是当前分组的。
补充说明
scales::percent()函数可以帮你自动格式化百分比字符串,accuracy参数可以控制小数位数(比如accuracy=0.01就是保留两位小数);- 如果不需要格式化,只是需要数值型的百分比,可以直接用
total / sum(total) * 100,再根据需求用round()保留小数。
内容的提问来源于stack exchange,提问作者Gui Albernaz
相关产品推荐
相关产品推荐

