我需要计算存储在循环缓冲区中的值的标准差。最终算法将在资源受限设备上运行,因此我希望它尽可能轻量级。天真的方法是每次推入新值时重新评估整个缓冲区的标准差,但这样会非常慢。理想情况下,我希望有一种算法,可以在推入新值时动态更新当前标准差的值。
维基百科报告了一些快速计算技术,但它们只能用于流:在我的情况下,当推入新值时,应该计算标准差,就好像已弹出的最后一个值从未存在过。
tl;dr:如何以最小的计算量计算循环缓冲区的标准差?
tl;dr:如何以最小的计算量计算循环缓冲区的标准差?
标准差可以表示为:
stddev = sqrt(1/N * SUM(x[i]^2) - 1/N^2 * SUM(x[i])^2)
对于未修正的样本标准差,可以写成:
对于修正后的样本标准差,可以写成:
stddev = sqrt(1/(N-1) * SUM(x[i]^2) - 1/(N^2-N) * SUM(x[i])^2)
SUM(x[i]^2)
,另一个用于SUM(x[i])
,那么每次更新这些累加器都是很简单的(减去最老的值的影响,加上最新值的影响)。N
当然是你缓冲区的长度。(x + y) - x != y
)。我认为没有任何简单的解决方法。struct Statistic {
int k;
Element M;
Element S;
Statistic(Element x)
: k(1)
, M(x)
, S(0)
{}
Statistic(Statistic a, Statistic b)
: k(a.k + b.k)
, M(a.M*a.k + b.M*b.k)/float(k)
, S(a.S + b.S + (a.M-b.M)*(a.M-b.M)*(a.k*b.k/float(k)))
{}
};
为了实现一个稳定的O(log N)在线算法,需要维护一个平衡的二叉树来存储上述统计信息,其中叶子节点代表单个元素;根节点将提供所需的在线统计信息。当您以旋转缓冲区的方式更新元素时,每次从叶子节点到根节点的更新传播将需要O(log N)次操作。
n
空间。在我看来,Kahan是一个很好的折衷方案,我在这里全力推荐它。 - Alexandre C.