如何有效地计算动态平均值(移动平均值)?

Posted

技术标签:

【中文标题】如何有效地计算动态平均值(移动平均值)?【英文标题】:How to efficiently compute average on the fly (moving average)? 【发布时间】:2015-05-03 11:03:38 【问题描述】:

我想出了这个

n=1;
curAvg = 0;
loop
  curAvg = curAvg + (newNum - curAvg)/n;
  n++;

我认为这种方式的亮点是: - 它避免了大数字(如果你先求和然后除,可能会溢出) - 你保存一个寄存器(不需要存储总和)

问题可能在于求和错误 - 但我认为通常向上和向下舍入的数字应该是平衡的,因此错误不会显着地求和。

您是否发现此解决方案存在任何缺陷? 你有更好的建议吗?

【问题讨论】:

我不明白你的公式。对于1 23 接下来,你会做curAvg = 1.5 + (3 - 1.5)/2 = 1.5 + 0.75 = 2.25,这会错吗? 类似问题:***.com/questions/12636613/… 那里提到了您的解决方案:new average = old average + (next data - old average) / next count @IVlad 您忘记增加 n 的值。它应该是 3 而不是 2。所以表达式应该是 curAvg = 1.5+(3-1.5)/3=1.5+0.5 = 2,这是正确的。 需要注意的是,OP的算法不是标准移动平均线,而是指数加权移动平均线。虽然 EMA 可能只是许多应用程序的票证,但在某些情况下(大阶跃响应)两者的行为完全不同,实施者应该意识到这种差异。见***.com/questions/12636613/… 【参考方案1】:

您的解决方案本质上是“标准”最佳在线解决方案,用于在不存储大笔金额的情况下保持平均运行轨迹,并且在“在线”运行时,即您可以一次只处理一个数字而无需返回其他数字,并且您只使用恒定数量的额外内存。如果您想要在数值准确性方面略微优化的解决方案,以“在线”为代价,然后假设您的数字都是非负数,然后首先从最小到最大对您的数字进行排序,然后按该顺序处理它们,和你现在一样。这样,如果你得到一堆非常小的数字,然后你得到一个大数字,你将能够准确地计算平均值而不会出现下溢,而不是先处理大数字。

【讨论】:

【参考方案2】:

我已经使用这个算法很多年了。 循环是任何类型的循环。可能是单独的网络会话,也可能是真正的循环。关键是您需要跟踪的是当前计数 (N) 和当前平均值 (avg)。每次收到新值时,应用此算法更新平均值。这将计算精确的算术平均值。它还有一个额外的好处是它可以防止溢出。如果您有数以万计的大数要平均,那么在除以 N 之前将它们全部加起来可能会溢出。该算法避免了这个陷阱。

Variables that are stored during the computation of the average:
N = 0
avg = 0

For each new value: V
    N=N+1
    a = 1/N
    b = 1 - a
    avg = a * V + b * avg

【讨论】:

以上是关于如何有效地计算动态平均值(移动平均值)?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 python + NumPy / SciPy 计算滚动/移动平均值?

使用 strides 实现有效的移动平均滤波器

如何有效地计算 numpy 二维数组的块均值(不规则块)?

在 C++ 中计算移动平均线

如何有效地计算运行标准偏差?

如果数据集中存在间隙,则使用mysql计算移动平均值会导致问题