不太有用的答案是因为 scipy 是这样定义它的,所以你最好让开发人员得到一个明确的答案。
真的。文档中的示例是
from scipy.stats import circvar
circvar([0, 2*np.pi/3, 5*np.pi/3])
2.19722457734
所以你不能说这种行为是意外的。
但是为什么会这样呢?
您的第二个链接将一组 n 角 a_1, ... a_n 的圆形方差定义为
V = 1 - \hat{R_1}
在哪里
\hat{R_1} = R_1 / n
R_1 = \sqrt{C^2 + S^2}
和
C = \sum_{i=1}^n cos(a_i)
S = \sum_{i=1}^n sin(a_i)
scipy 库通过
找到循环方差
ang = (samples - low)*2.*pi / (high - low)
S = sin(ang).mean(axis=axis)
C = cos(ang).mean(axis=axis)
R = hypot(S, C)
return ((high - low)/2.0/pi)**2 * 2 * log(1/R)
这有点难以理解。
如果我们假设样本是零均值,范围是 [0, 2*pi],并且使用默认轴(在示例中均为 true),则可以将其简化为
S = mean(sin(samples))
C = mean(cos(samples))
R = hypot(S, C)
V = 2 * log(1/R)
所以 scipy 使用的定义将 R 转换为 2*log(1/R),而不是 1-R。
这似乎很奇怪。
回顾历史,https://github.com/scipy/scipy/blame/v1.1.0/scipy/stats/morestats.py#L2696-L2733,在某一时刻,统计数据是使用
ang = (samples - low)*2*pi / (high-low)
res = stats.mean(exp(1j*ang))
V = 1-abs(res)
return ((high-low)/2.0/pi)**2 * V
这似乎符合您提供的定义。
在添加测试的同时在错误修复中对此进行了更改,但没有提及新计算的来源。
https://github.com/scipy/scipy/pull/5747 上提供了有关 scipy 错误跟踪器的一些讨论。
它表明该行为是故意的,不会被修复。
astropy 中还有另一种实现,http://docs.astropy.org/en/stable/api/astropy.stats.circvar.html,它指出
此处使用的定义与 scipy.stats.circvar 中的定义不同。准确地说,Scipy circvar 使用了基于接近线性方差的小角度极限的近似值。
因此,总而言之,由于未知原因scipy 使用了近似值(在某些情况下似乎相当差)。但是,由于向后兼容,它不会被修复,因此您可能希望使用astropy 的实现。