如何从直方图计算标准差?(Python,Matplotlib)

7
假设我有一个数据集,并使用matplotlib绘制了该数据集的直方图。
n, bins, patches = plt.hist(data, normed=1)

如何使用hist()返回的nbins值计算标准差? 我目前正在使用以下方法计算平均值:
s = 0
for i in range(len(n)):
   s += n[i] * ((bins[i] + bins[i+1]) / 2) 
mean = s / numpy.sum(n)

这似乎很好用,因为我得到了相当准确的结果。然而,如果我尝试像这样计算标准偏差:
t = 0
for i in range(len(n)):
  t += (bins[i] - mean)**2
std = np.sqrt(t / numpy.sum(n))

我的结果与 numpy.std(data) 返回的结果相差甚远。将左边界替换为每个区间的中心点也无济于事。我感觉问题在于 nbins 值实际上并没有包含任何有关每个区间内个体数据分布的信息,但我正在完成的任务明确要求我使用它们来计算标准差。

我可以访问它,但是任务明确规定我不应使用原始数据。我认为整个措辞(“这些值非常有用,可用于计算分布的平均值、方差或其他属性。”)让我感到困惑,因为它没有提到结果仅为近似值。 :) - justaname
2个回答

19

你没有使用n[i]对每个箱子的贡献进行加权。将t的增量更改为

    t += n[i]*(bins[i] - mean)**2

顺便提一下,您可以使用numpy.averageweights参数来简化(并加快)计算。
以下是一个示例。首先,生成一些要处理的数据。在计算直方图之前,我们将计算输入的样本均值、方差和标准差。
In [54]: x = np.random.normal(loc=10, scale=2, size=1000)

In [55]: x.mean()
Out[55]: 9.9760798903061847

In [56]: x.var()
Out[56]: 3.7673459904902025

In [57]: x.std()
Out[57]: 1.9409652213499866

我将使用numpy.histogram来计算直方图:

In [58]: n, bins = np.histogram(x)

mids是箱子的中点;它与n具有相同的长度:

In [59]: mids = 0.5*(bins[1:] + bins[:-1])

平均值的估计是 mids 的加权平均值:

In [60]: mean = np.average(mids, weights=n)

In [61]: mean
Out[61]: 9.9763028267760312

在这种情况下,它与原始数据的平均值非常接近。
估计方差是从平均值计算的加权平均平方差:
In [62]: var = np.average((mids - mean)**2, weights=n)

In [63]: var
Out[63]: 3.8715035807387328

In [64]: np.sqrt(var)
Out[64]: 1.9676136767004677

这个估计值与实际样本标准差相差不超过2%。


谢谢,完全忘记了!然而,我的结果仍然有点不准确(例如使用numpy时是0.19而不是0.17)。我可以认为从直方图中只能得到标准差的近似值吗?还是我还缺少其他东西? - justaname
1
没错,你不能期望使用直方图计算出的值与使用完整数据集计算出的值匹配。 直方图会丢失信息。 - Warren Weckesser

6
以下答案与Warren Weckesser的答案相同,但可能更适合那些更喜欢将平均值称为期望值的人:
counts, bins = np.histogram(x)
mids = 0.5*(bins[1:] + bins[:-1])
probs = counts / np.sum(counts)

mean = np.sum(probs * mids)  
sd = np.sqrt(np.sum(probs * (mids - mean)**2))

请注意,在某些情况下,您可能需要无偏样本方差,其中权重未被N但被N-1归一化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接