如何计算Python中两个直方图的相交区域面积
直方图重叠面积计算方案
你之前用同索引bin取最小值累加的思路本身没有问题,计算错误的核心原因是两个直方图没有使用完全一致的分箱规则。
当你分别对两个数据集调用plt.hist(..., bins=20)时,matplotlib会针对每个输入数据集单独计算分箱范围:取当前数据集的最小值作为分箱左边界、最大值作为分箱右边界,自动生成20个等宽bin。如果两个数据集的值域存在差异(尤其是包含负值、值域偏移较大时),两个直方图同索引的bin对应的数值区间完全不重合,这种情况下直接对同索引bin取最小值计算,结果必然错误。
实现逻辑
只要保证两个直方图使用完全相同的分箱边界,对应bin取最小值乘bin宽累加的逻辑对包含负值的数据集完全生效,具体步骤如下:
- 先提取两个数据集的全局最小值、最大值,基于整体值域生成固定的20个等宽bin的边界数组
- 用和matplotlib底层完全一致的numpy直方图计算接口,分别得到两个数据集在统一分箱下的密度值
- 逐bin取两个密度的最小值,乘以bin宽度后累加,结果就是重叠区域的面积
- 绘图时同样传入这套固定的bin边界,保证可视化结果和计算结果完全对应
可直接运行的代码示例
import numpy as np import matplotlib.pyplot as plt # 测试用例:特意构造包含负值的两个数据集 data1 = np.random.normal(loc=-2, scale=1.5, size=10000) data2 = np.random.normal(loc=1, scale=2, size=10000) # 生成统一分箱边界:20个bin对应21个边界点,覆盖两个数据集的全部值域 global_min = min(data1.min(), data2.min()) global_max = max(data1.max(), data2.max()) shared_bins = np.linspace(global_min, global_max, 21) # 计算统一分箱下的密度直方图,density=True保证直方图总面积为1 hist_dens1, _ = np.histogram(data1, bins=shared_bins, density=True) hist_dens2, _ = np.histogram(data2, bins=shared_bins, density=True) # 计算重叠面积 bin_width = shared_bins[1] - shared_bins[0] overlap_area = np.sum(np.minimum(hist_dens1, hist_dens2) * bin_width) print(f"直方图重叠区域面积为: {overlap_area:.4f}") # 绘图时复用同一套分箱,和计算逻辑保持一致 plt.hist(data1, bins=shared_bins, alpha=0.4, density=True, label='dataset1') plt.hist(data2, bins=shared_bins, alpha=0.4, density=True, label='dataset2') plt.legend() plt.show()
注意事项
- 无论计算还是绘图,都不要直接传
bins=20让接口自动生成分箱,必须传入提前定义好的同一套bin边界数组- 计算时需要使用密度值(设置
density=True),如果直接用原始计数,需要先将计数除以对应数据集的总样本量转换为频率,否则计算结果是重叠的样本数量而非面积- 该方案基于数值轴的绝对区间分箱,对全负值、全正值、正负值混合的数据集都能得到正确结果
内容的提问来源于stack exchange,提问作者Curious
相关产品推荐
相关产品推荐

