如何在ggplot2中绘制带权重的geom_histogram(避免数据复制)
绘制加权直方图(避免重复大权重数据)
示例数据集
set.seed(100) my_data <- data.frame(type = letters, value = rnorm(26, 10, 3) |> sort(), weight = 1:26)
原普通直方图实现
bin_width <- 5 x_seq <- seq(0, 20, bin_width) ggplot2::ggplot(my_data, ggplot2::aes(x = value)) + ggplot2::geom_histogram(binwidth = bin_width) + ggplot2::scale_x_continuous(limits = c(min(x_seq), max(x_seq)), n.breaks = length(x_seq))
需求说明
需要绘制与原直方图x轴一致的加权直方图:
- 外观保持直方图样式
- y轴显示每个bin范围内观测值的
weight求和值,而非观测数量 - 禁止使用
rep(my_data$value, my_data$weight)复制数据(真实数据集权重极大,会导致性能问题)
可行解决方案
方法1:提前分箱计算权重和(手动处理)
先通过数据分组计算每个bin的权重总和,再用geom_col绘制,完全避免重复数据:
library(dplyr) library(ggplot2) bin_width <- 5 x_seq <- seq(0, 20, bin_width) # 分箱并计算每个bin的权重总和 weighted_bins <- my_data |> # 为每个value分配对应的bin区间 mutate(bin = cut(value, breaks = x_seq, include.lowest = TRUE)) |> group_by(bin) |> summarise(total_weight = sum(weight)) |> # 计算bin的中点,保证和原直方图x轴对齐 mutate(x_mid = (as.numeric(sub("\\((.*),.*\\]", "\\1", bin)) + as.numeric(sub(".*,(.*)\\]", "\\1", bin))) / 2) # 绘制加权直方图 ggplot(weighted_bins, aes(x = x_mid, y = total_weight)) + geom_col(width = bin_width, fill = "gray50", color = "black") + scale_x_continuous(limits = c(min(x_seq), max(x_seq)), breaks = x_seq) + labs(x = "value", y = "Total Weight")
方法2:使用stat_summary_bin(更简洁)
直接利用ggplot2的stat_summary_bin统计层,指定求和函数,无需提前处理数据:
library(ggplot2) bin_width <- 5 x_seq <- seq(0, 20, bin_width) ggplot(my_data, aes(x = value, y = weight)) + stat_summary_bin(fun = sum, geom = "col", binwidth = bin_width, fill = "gray50", color = "black") + scale_x_continuous(limits = c(min(x_seq), max(x_seq)), breaks = x_seq) + labs(y = "Total Weight")
两种方法都能生成与预期一致的加权直方图,且不会因大权重数据导致性能问题。
内容的提问来源于stack exchange,提问作者nateroe
相关产品推荐
相关产品推荐

