计算直方图交集百分比结果超1的原因及解决方法
问题原因与修正方案
为什么结果会大于1?
你混淆了直方图的频率和密度计算逻辑,导致分子分母的维度不匹配:
- 用
weights=(np.ones_like(d)/len(d))时,plt.hist返回的n是每个bin的频率(所有bin的频率总和为1)。 - 你计算直方图总面积时用了
sum(np.diff(bins)*n),这是每个bin的「频率×宽度」之和,结果等于数据范围的总长度(比如数据范围是0到0.5,这个值就是0.5)。 - 但你计算重叠面积时直接对
np.minimum(n1,n2)求和,得到的是频率的总和(两个数据集相同时为1)。 - 当数据范围总长度小于0.5时,分母
n1_area+n2_area就会小于1,分子是1,最终结果自然大于1。
修正代码
核心是让分子分母的计算逻辑统一:都基于直方图矩形的面积(高度×宽度)。有两种常用方案:
方案1:使用密度直方图(推荐)
直接用density=True参数获取密度值,此时每个直方图的总面积固定为1,计算更直观:
import numpy as np import matplotlib.pyplot as plt rng = (min(dataset1.min(), dataset2.min()), max(dataset1.max(), dataset2.max())) # 绘制密度直方图,返回的n是每个bin的密度值 n1, bins1, _ = plt.hist(dataset1, color=color1, alpha=0.75, bins=7, density=True, range=rng) n2, bins2, _ = plt.hist(dataset2, color=color2, alpha=0.75, bins=7, density=True, range=rng) bin_widths = np.diff(bins1) # 交集面积:每个bin取最小密度 × bin宽度,求和 overlap_area = np.sum(np.minimum(n1, n2) * bin_widths) # 两个直方图总面积各为1,总和是2 total_area = 1 + 1 # 转成百分比 overlap_percentage = overlap_area / total_area * 100
方案2:基于原权重逻辑修正
如果你坚持用权重方式,只需给重叠面积的计算加上bin宽度的乘积:
import numpy as np import matplotlib.pyplot as plt rng = (min(dataset1.min(), dataset2.min()), max(dataset1.max(), dataset2.max())) n1, bins1, _ = plt.hist(dataset1, color=color1, alpha=0.75, bins=7, weights=(np.ones_like(dataset1)/len(dataset1)), range=rng) n2, bins2, _ = plt.hist(dataset2, color=color2, alpha=0.75, bins=7, weights=(np.ones_like(dataset2)/len(dataset2)), range=rng) bin_widths = np.diff(bins1) # 计算每个直方图的总面积(频率×宽度之和) n1_area = np.sum(n1 * bin_widths) n2_area = np.sum(n2 * bin_widths) # 计算交集面积(最小频率×宽度之和) overlap_area = np.sum(np.minimum(n1, n2) * bin_widths) # 计算百分比 overlap_percentage = overlap_area / (n1_area + n2_area) * 100
当两个数据集完全相同时,两种方案都会得到50%的结果,符合预期。
内容的提问来源于stack exchange,提问作者Tessa
相关产品推荐
相关产品推荐

