【问题标题】:Histogram with equal number of points in each bin每个 bin 中点数相等的直方图
【发布时间】:2017-01-18 00:09:06
【问题描述】:

我有一个排序的向量points 有 100 个点。我现在想创建两个直方图:第一个直方图应该有 10 个宽度相等的 bin。第二个也应该有 10 个直方图,但不一定等宽。第二,我只希望直方图在每个 bin 中具有相同数量的点。因此,例如,第一个条形图可能非常短且宽,而直方图中的第二个条形图可能又高又窄。我有使用matplotlib 创建第一个直方图的代码,但现在我不确定如何创建第二个。

import matplotlib.pyplot as plt
points = [1,2,3,4,5,6, ..., 99]
n, bins, patches = plt.hist(points, 10)

编辑:

尝试下面的解决方案,我有点困惑为什么我的直方图中所有条形的高度都相同。

【问题讨论】:

  • 当然,如果每个 bin 包含相同数量的点,所有条的高度都是相同的,因为条的高度是属于该 bin 的点数(根据定义直方图)。请参阅接受的答案编辑,其中包含相同的内容。

标签: python matplotlib histogram


【解决方案1】:

为直方图提供 bin:

bins=points[0::len(points)/10]

然后

n, bins, patches = plt.hist(points, bins=bins)

(提供点已排序)

【讨论】:

  • 这几乎可行,但如果步幅不准确;最后一个 bin 将丢失。在这种情况下,您也不能只附加它,因为元素的数量不一定接近步幅。例如,如果您有 100 个元素并想要 12 个 bin,则步幅为 8,最终只占 100 个元素中的 97 个。如果将最后一个点添加到“bins”,则该 bin 将仅包含 3 个元素。
【解决方案2】:

这个问题是similar to one,我不久前写了一个答案,但完全不同,足以证明它是自己的问题。事实证明,该解决方案使用了与我的其他答案基本相同的代码。

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(100)
n, bins, patches = plt.hist(x, histedges_equalN(x, 10))

这个解决方案给出了一个具有相同高度的 bin 的直方图,因为——根据定义——直方图是每个 bin 中点数的计数。

要获取 pdf(即密度函数),请使用 normed=True kwarg 到 plt.hist。如我的other answer 所述。

【讨论】:

  • 我尝试过使用您的解决方案,但由于某种原因,我所有垃圾箱的高度都相同。你知道这是为什么吗?我希望它们肯定会有所不同,不是吗?我已经编辑了我的问题以包含一张图片。
  • @Apollo,该方法有效地改变了 bin 域覆盖范围以实现这一目标。因此,在“垃圾箱”中,您的计数相同。否则,使用前缀 bin 大小,一些 bin 中的点或多或少,但这样每个 bin 的总数相同;如果您尝试在该域上进行集成,则可能会出现违反直觉的情况。
  • @farenorth,很好的答案!矢量化和优雅。 np.historgram(x, histedges_equalN(x, 10)) 的快速 REPL 清楚地向我展示了实现 OP(和我)正在寻找的结果。
  • 感觉这真是一个quantile 的问题,解决方案是重现np.quantile 功能:np.quantile(x, np.linspace(0,1,nbin+1)) 可以解决问题
【解决方案3】:

在这里,我写了一个关于如何获得结果的示例。我的方法使用数据点来获取将传递给 np.histogram 的 bin 以构建直方图。因此需要使用np.argsort(x) 对数据进行排序。每个 bin 的点数可以用npoints 控制。例如,我使用这种方法构建了两个直方图。所有点的权重都相同,因此直方图的高度始终是恒定的(并且等于npoints)。另一个是每个点的“权重”是从均匀随机分布中提取的(参见mass 数组)。正如预期的那样,直方图的框不再相等。但是,每个 bin 的泊松误差是相同的。

x = np.random.rand(1000)
mass = np.random.rand(1000)
npoints = 200
ksort = np.argsort(x)

#Here I get the bins from the data set.
#Note that data need to be sorted
bins=x[ksort[0::npoints]]
bins=np.append(bins,x[ksort[-1]])


fig = plt.figure(1,figsize=(10,5))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

#Histogram where each data 
yhist, xhist = np.histogram(x, bins, weights=None)
ax1.plot(0.5*(xhist[1:]+xhist[:-1]), yhist, linestyle='steps-mid', lw=2, color='k')

yhist, xhist = np.histogram(x, bins, weights=mass)
ax2.plot(0.5*(xhist[1:]+xhist[:-1]), yhist, linestyle='steps-mid', lw=2, color='k')

ax1.set_xlabel('x', size=15)
ax1.set_ylabel('Number of points per bin', size=15)

ax2.set_xlabel('x', size=15)
ax2.set_ylabel('Mass per bin', size=15)

【讨论】:

    【解决方案4】:

    这个解决方案并不优雅,但它对我有用。希望对你有帮助

    def pyAC(x, npoints = 10, RetType='abs'):
        x = np.sort(x)
        ksort = np.argsort(x)
        binCount = int(len(x)/npoints) #number of data points in each bin
        bins = np.zeros(npoints) #initialize the bins values
        binsX = np.zeros(npoints)
        for i in range(0, npoints, 1):
            bins[i] = x[(i+1) * binCount]
            for j in range(((binCount * i) + 1), (binCount * (i+1)), 1):
                binsX[i] = x[j] + binsX[i]
        binsX = binsX/binCount  
        return pd.DataFrame({'bins':bins, 'binsX':binsX})
    

    【讨论】:

      猜你喜欢
      • 2015-10-11
      • 2016-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多