【问题标题】:Computing Standard Deviation in a stream计算流中的标准偏差
【发布时间】:2011-04-04 20:00:06
【问题描述】:

使用 Python,假设我正在运行已知数量的项目I,并且能够计算处理每个项目所需的时间t,以及处理所花费的总时间@ 987654325@ 和到目前为止处理的项目数c。我目前正在即时计算平均值A = T / c,但这可能会因为单个项目需要非常长的时间来处理(几秒钟而不是几毫秒)而产生偏差。

我想展示一个正在运行的标准偏差。在不记录每个t 的情况下如何做到这一点?

【问题讨论】:

标签: python math


【解决方案1】:

正如Wikipedia article on the standard deviation 中所述,跟踪以下三个总和就足够了:

s0 = sum(1 for x in samples)
s1 = sum(x for x in samples)
s2 = sum(x*x for x in samples)

随着新值的到来,这些总和很容易更新。标准差可以计算为

std_dev = math.sqrt((s0 * s2 - s1 * s1)/(s0 * (s0 - 1)))

请注意,如果您的样本是浮点数并且标准偏差与样本的平均值相比较小,那么这种计算标准偏差的方法可能会在数值上出现病态。如果您期望这种类型的样本,您应该求助于 Welford 的方法(请参阅接受的答案)。

【讨论】:

  • 不能将s0 更简单地计算为length(samples),将s1 计算为sum(samples)
  • @Benjamin:当然。但是 OP 不想跟踪 samples。我选择这种语法是为了清楚每次迭代中将添加什么(以及为了它漂亮的对称外观)。
  • @Benjamin:Sven 以编程方式显示标准差定义为数据的第零、第一和第二时刻的函数。
  • 对于一个样本,(s0 * (s0 - 1)) == 0,所以除以零。
【解决方案2】:

基于Welford's algorithm

import numpy as np

class OnlineVariance(object):
    """
    Welford's algorithm computes the sample variance incrementally.
    """

    def __init__(self, iterable=None, ddof=1):
        self.ddof, self.n, self.mean, self.M2 = ddof, 0, 0.0, 0.0
        if iterable is not None:
            for datum in iterable:
                self.include(datum)

    def include(self, datum):
        self.n += 1
        self.delta = datum - self.mean
        self.mean += self.delta / self.n
        self.M2 += self.delta * (datum - self.mean)

    @property
    def variance(self):
        return self.M2 / (self.n - self.ddof)

    @property
    def std(self):
        return np.sqrt(self.variance)

用每条新数据更新方差:

N = 100
data = np.random.random(N)
ov = OnlineVariance(ddof=0)
for d in data:
    ov.include(d)
std = ov.std
print(std)

对照 numpy 计算的标准差检查我们的结果:

assert np.allclose(std, data.std())

【讨论】:

  • 默认 ddof 会在第一轮崩溃,因为 n=1 并且除以零会发生方差。一种解决方法是使方差成为一个属性,这样它就不会在线计算。
【解决方案3】:

我使用Welford's Method,它可以提供更准确的结果。此链接指向John D. Cook's overview。这里有一段总结了为什么它是首选方法:

这种计算方差的更好方法可以追溯到 1962 年 B. P. Welford 的一篇论文,并在 Donald Knuth 的计算机编程艺术,第 2 卷,第 232 页,第 3 版中进行了介绍。尽管这种解决方案已经为人所知数十年,但了解它的人还不够多。大多数人可能不知道,在他们第一次计算标准差并获得负数平方根的例外情况之前,计算样本方差可能很困难。

【讨论】:

  • 阅读约翰库克的概述,我没有看到提到如何合并加权值。对于@SvenMarnach 帖子中的方法,维基百科 (en.wikipedia.org/wiki/…) 提到使用 s0、s1 和 s2 的加权值将产生正确的结果。看起来很可能,但你知道这是否与 Welford 方法相同吗?
  • 我也对加权很好奇。给定的解决方案似乎给出了数据流整个历史的方差。对于某些流媒体领域,我可以看到将值加权以表示最近数据点的方差并让较旧的样本消失是多么有用。
猜你喜欢
  • 1970-01-01
  • 2017-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-04
  • 1970-01-01
相关资源
最近更新 更多