如何用group_by() |> tally()对整数列分箱并显示所有分箱(含空分箱)
解决分箱统计保留空分箱的问题
针对mtcars数据集的hp列按40间隔分箱并保留空分箱的需求,有两种简便方法可以实现:
方法一:用因子强制保留所有分箱水平
先手动生成所有需要的分箱区间,将分箱结果转为因子并指定所有区间为水平,这样统计时空分箱会被保留,最后把NA替换为0即可:
library(dplyr) # 生成按40间隔的断点,覆盖hp的最小到最大值范围 breaks <- seq(floor(min(mtcars$hp)/40)*40, ceiling(max(mtcars$hp)/40)*40, by = 40) # 生成分箱标签,格式如"40-80" labels <- paste0(breaks[-length(breaks)], "-", breaks[-1]) mtcars %>% # 按断点分箱,include.lowest确保最小值被包含在第一个分箱 mutate(hp_bin = cut(hp, breaks = breaks, labels = labels, include.lowest = TRUE)) %>% # 强制将分箱转为因子,保留所有预设的分箱水平 mutate(hp_bin = factor(hp_bin, levels = labels)) %>% # 统计每个分箱的数量 count(hp_bin, name = "count") %>% # 把空分箱的NA计数替换为0 mutate(count = replace(count, is.na(count), 0))
方法二:生成完整分箱表后左连接
先生成包含所有分箱的数据集,再和原数据的统计结果做左连接,空分箱的计数会显示为NA,最后替换为0:
library(dplyr) breaks <- seq(floor(min(mtcars$hp)/40)*40, ceiling(max(mtcars$hp)/40)*40, by = 40) labels <- paste0(breaks[-length(breaks)], "-", breaks[-1]) # 生成包含所有分箱的基础表 full_bins <- tibble(hp_bin = labels) # 统计原数据中各分箱的数量 hp_counts <- mtcars %>% mutate(hp_bin = cut(hp, breaks = breaks, labels = labels, include.lowest = TRUE)) %>% count(hp_bin, name = "count") # 左连接后替换空分箱的NA为0 full_bins %>% left_join(hp_counts, by = "hp_bin") %>% mutate(count = ifelse(is.na(count), 0, count))
原理说明
原来用ggplot2::cut_interval()的方式会丢失空分箱,是因为该函数只会生成数据实际覆盖到的分箱,且group_by() + tally()只会统计存在数据的分组。通过手动生成全部分箱区间并强制保留(因子水平或左连接),就能让空分箱的计数显示为0。
内容的提问来源于stack exchange,提问作者Emman
相关产品推荐
相关产品推荐

