Matplotlib:如何用等面积的箱子制作直方图?

Matplotlib: How to make a histogram with bins of equal area?

给定一些遵循某种任意分布的数字列表,我如何为 matplotlib.pyplot.hist() 定义 bin 位置,以便每个 bin 中的面积等于(或接近)某个常数面积 A?面积的计算方法是将垃圾箱中的物品数量乘以垃圾箱的宽度,其值不应大于A。

这是一个 MWE,用于显示具有正态分布样本数据的直方图:

import matplotlib.pyplot as plt
import numpy as np

x = np.random.randn(100)
plt.hist(x, bin_pos)
plt.show()

这里 bin_pos 是表示 bin 边界位置的列表(参见相关问题 here

我发现这个问题很有趣。解决方案取决于您是要绘制 密度函数 还是 真实直方图 。后一种情况变得更具挑战性。 Here 是关于直方​​图和密度函数之间差异的更多信息。

密度函数


这将执行您想要的密度函数:

def histedges_equalN(x, nbin):
    npt = len(x)
    return np.interp(np.linspace(0, npt, nbin + 1),
                     np.arange(npt),
                     np.sort(x))

x = np.random.randn(1000)
n, bins, patches = plt.hist(x, histedges_equalN(x, 10), normed=True)

请注意 normed=True 的使用,它指定我们正在计算和绘制密度函数。在这种情况下,面积完全相等(您可以通过查看 n * np.diff(bins) 来检查)。另请注意,此解决方案涉及查找具有相同点数的箱子。

直方图


这是一个为直方图给出近似等面积框的解决方案:

def histedges_equalA(x, nbin):
    pow = 0.5
    dx = np.diff(np.sort(x))
    tmp = np.cumsum(dx ** pow)
    tmp = np.pad(tmp, (1, 0), 'constant')
    return np.interp(np.linspace(0, tmp.max(), nbin + 1),
                     tmp,
                     np.sort(x))

n, bins, patches = plt.hist(x, histedges_equalA(x, nbin), normed=False)

然而,这些盒子的面积并不都是相等的。特别是第一个和最后一个,往往比其他的大 30%。这是正态分布尾部数据稀疏分布的产物,我相信它会在数据集中人口稀少的任何时候持续存在。

旁注:我稍微玩了一下 pow 值,发现大约 0.56 的值在正态分布中具有较低的 RMS error。我坚持使用 square-root,因为它在数据为 tightly-spaced(相对于 bin-width)时表现最佳,而且我很确定它有一个我没有的理论基础'懒得深入研究(任何人?)。

equal-area 直方图的问题

据我所知,不可能得到这个问题的精确解。这是因为它对数据的离散化很敏感。例如,假设数据集中的第一个点是 -13 的离群值,下一个值是 -3,如图中的红点所示:

现在假设直方图的总数 "area" 是 150,而您需要 10 个分箱。在那种情况下,每个直方图条的面积应该约为 15,但您无法到达那里,因为一旦您的条包含第二个点,它的面积就会从 10 跳到 20。也就是说,数据不允许此条面积在 10 到 20 之间。对此的一种解决方案可能是调整框的 lower-bound 以增加其面积,但这开始变得随意,如果 'gap' 在数据集的中间。