对于 (-pi, pi) 范围内的一系列角度值,我制作了一个直方图。有没有一种有效的方法来计算平均值和模态(后可能)值?考虑以下示例:
import numpy as N, cmath
deg = N.pi/180.
d = N.array([-175., 170, 175, 179, -179])*deg
i = N.sum(N.exp(1j*d))
ave = cmath.phase(i)
i /= float(d.size)
stdev = -2. * N.log(N.sqrt(i.real**2 + i.imag**2))
print ave/deg, stdev/deg
现在,让我们有一个直方图:
counts, bins = N.histogram(data, N.linspace(-N.pi, N.pi, 360))
是否可以计算具有计数和 bin 的平均值、模式?对于非周期性数据,平均值的计算很简单:
ave = sum(counts*bins[:-1])
模态值的计算需要更多的努力。实际上,我不确定下面的代码是否正确:首先,我确定最常出现的 bin,然后计算算术平均值:
cmax = bins[N.argmax(counts)]
mode = N.mean(N.take(bins, N.nonzero(counts == cmax)[0]))
不过,我不知道如何根据这些数据计算标准偏差。解决我所有问题(至少是上述问题)的一个明显解决方案是将直方图数据转换为数据系列,然后在计算中使用它。然而,这并不优雅,而且效率低下。
任何提示将不胜感激。
这是我写的部分解决方案。
import numpy as N, cmath
import scipy.stats as ST
d = [-175, 170.2, 175.57, 179, -179, 170.2, 175.57, 170.2]
deg = N.pi/180.
data = N.array(d)*deg
i = N.sum(N.exp(1j*data))
ave = cmath.phase(i) # correct and exact mean for periodic data
wrong_ave = N.mean(d)
i /= float(data.size)
stdev = -2. * N.log(N.sqrt(i.real**2 + i.imag**2))
wrong_stdev = N.std(d)
bins = N.linspace(-N.pi, N.pi, 360)
counts, bins = N.histogram(data, bins, normed=False)
# consider it weighted vector addition
nz = N.nonzero(counts)[0]
weight = counts[nz]
i = N.sum(weight * N.exp(1j*bins[nz])/len(nz))
pave = cmath.phase(i) # correct and approximated mean for periodic data
i /= sum(weight)/float(len(nz))
pstdev = -2. * N.log(N.sqrt(i.real**2 + i.imag**2))
print
print 'scipy: %12.3f (mean) %12.3f (stdev)' % (ST.circmean(data)/deg, \
ST.circstd(data)/deg)
运行时,它会给出以下结果:
mean: 175.840 85.843 175.360
stdev: 0.472 151.785 0.430
scipy: 175.840 (mean) 3.673 (stdev)
现在有一些评论:第一列给出了计算的平均值/标准差。可以看出,平均值与 scipy.stats.circmean 非常吻合(感谢 JoeKington 指出)。不幸的是 stdev 不同。我稍后会看的。第二列给出了完全错误的结果(来自 numpy 的非周期性平均值/标准显然在这里不起作用)。第三列给出了我想从直方图数据中获得的东西(@JoeKington:我的原始数据不适合我的计算机内存......,@dmytro:感谢您的输入:当然,bin 大小会影响结果,但在我的应用程序我没有太多选择,即我必须以某种方式减少数据)。可以看出,均值(第 3 列)计算正确,stdev 需要进一步注意 :)