Matplotlib:如何制作具有相等面积区间的直方图?

wrk*_*yle 6 python matplotlib histogram binning

给定一些任意分布后的数字列表,如何定义bin位置,matplotlib.pyplot.hist()使每个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()
Run Code Online (Sandbox Code Playgroud)

bin_pos是一个表示箱子边界位置的列表(参见此处的相关问题).

far*_*rth 10

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

密度函数


这将为密度函数做你想做的事:

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)
Run Code Online (Sandbox Code Playgroud)

注意使用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)
Run Code Online (Sandbox Code Playgroud)

然而,这些盒子并非都是平等的.特别是,第一个和最后一个比其他的大约30%.这是正态分布尾部数据稀疏分布的人为因素,我相信只要它们是数据集中人口稀少的区域,它就会持续存在.

旁注:我pow稍微使用了该值,发现约值对于正态分布0.56具有较低的RMS误差.我坚持使用平方根,因为当数据紧密间隔时(相对于bin宽度)它表现最好,而且我很确定它有一个理论基础,我没有费心去挖掘(任何人?).

几乎相等的面积直方图

等面积直方图的问题

据我所知,不可能获得这个问题的确切解决方案.这是因为它对数据的离散化很敏感.例如,假设数据集中的第一个点是-13的异常值,下一个值是-3,如此图像中的红点所示:

图表显示直方图箱区域

现在假设你的直方图的总"面积"是150,你想要10个箱子.在这种情况下,每个直方图条的面积应该是大约15,但是你无法到达那里,因为只要你的条包含第二个点,它的区域就会从10跳到20.也就是说,数据不允许这个条形一个解决方案可能是调整框的下限以增加其面积,但这开始变得任意,如果这个'间隙'在数据集.

  • 我只是希望 SO 充满了如此有趣的问题。不过,如果真是这样的话,我就什么也做不了了…… (3认同)
  • 你是Stack Overflow中所有正确的人格化.感谢您提供详细,记录完备且优雅的解决方案. (2认同)