R语言hist()函数不基于区间宽度计算概率/密度的实现方法
实现基于总元素数的相对频率直方图(忽略区间宽度)
你说得对,R的hist()函数在freq=FALSE时计算的是密度(相对频率除以区间宽度),这和你想要的「每个区间元素数占总元素数的比例」(即相对频率,不考虑区间宽度)不是一回事。因为你的区间长度不一致,默认参数确实满足不了需求,不过我们有两种简便的实现方式,不用完全从零开始写代码:
方法1:利用hist()的统计结果手动计算并绘图
先让hist()帮我们统计每个区间的元素个数,再自己计算相对频率,最后用绘图函数实现你要的效果:
步骤示例
# 你的示例数据和区间 v <- seq(1, 10, 1) breaks <- c(1, 8, 10) # 先获取直方图的统计结果,不绘图 h <- hist(v, breaks = breaks, plot = FALSE) # 计算每个区间的相对频率:区间元素数 / 总元素数 rel_freq <- h$counts / length(v) # 方式A:用条形图展示(每个条宽度一致,适合强调比例对比) barplot(rel_freq, names.arg = paste0(h$breaks[-length(h$breaks)], "-", h$breaks[-1]), ylab = "Relative Frequency", xlab = "Intervals", main = "Relative Frequency by Interval") # 方式B:用矩形绘制「保持区间宽度」的直方图样式 plot(NULL, xlim = range(breaks), ylim = c(0, max(rel_freq) * 1.1), # 留一点顶部空间 xlab = "Intervals", ylab = "Relative Frequency", main = "Relative Frequency Histogram (Original Interval Widths)") # 绘制每个区间的矩形 rect(h$breaks[-length(h$breaks)], 0, h$breaks[-1], rel_freq, col = "lightblue")
方法2:自定义一个简单函数封装逻辑
如果需要反复使用,可以把上面的逻辑封装成函数,方便调用:
rel_freq_hist <- function(x, breaks, ...) { h <- hist(x, breaks = breaks, plot = FALSE) rel_freq <- h$counts / length(x) plot(NULL, xlim = range(breaks), ylim = c(0, max(rel_freq)*1.1), ...) rect(h$breaks[-length(h$breaks)], 0, h$breaks[-1], rel_freq, ...) } # 调用示例 rel_freq_hist(v, breaks = c(1,8,10), xlab = "Intervals", ylab = "Relative Frequency", col = "coral", main = "Custom Relative Frequency Histogram")
补充说明
- 如果你更关注比例的对比,用
barplot会更直观,因为它统一了每个类别(区间)的宽度; - 如果需要保留原始区间宽度的可视化,用
rect绘制的方式更符合直方图的形态,但要注意此时y轴是相对频率,不是密度,所以矩形的面积总和不等于1(这和freq=FALSE的默认行为不同)。
内容的提问来源于stack exchange,提问作者Herman Toothrot
相关产品推荐
相关产品推荐

