计算生成器的python中的平均值

时间:2011-02-10 23:11:05

标签: python generator mean

我正在做一些统计工作,我有一个(大)随机数集合来计算平均值,我想使用生成器,因为我只需要计算均值,所以我不需要存储数字。

问题是numpy.mean如果你把它传给一个生成器就会中断。我可以写一个简单的函数来做我想要的,但我想知道是否有一个正确的,内置的方法来做到这一点?

如果我可以说“sum(values)/ len(values)”,那就好了,但len不适用于genetators,并且总和已消耗的值。

这是一个例子:

import numpy 

def my_mean(values):
    n = 0
    Sum = 0.0
    try:
        while True:
            Sum += next(values)
            n += 1
    except StopIteration: pass
    return float(Sum)/n

X = [k for k in range(1,7)]
Y = (k for k in range(1,7))

print numpy.mean(X)
print my_mean(Y)

这两个都给出相同的,正确的答案,买my_mean不适用于列表,而numpy.mean不适用于生成器。

我非常喜欢使用发电机的想法,但这样的细节似乎破坏了事情。

10 个答案:

答案 0 :(得分:19)

一般情况下,如果你正在进行浮点数的流均值计算,你可能最好使用一个数值更稳定的算法而不是简单地求和发生器并除以长度。

这些中最简单的(我知道)通常是credited to Knuth,并且还计算方差。该链接包含一个python实现,但为了完整性,只复制了平均部分。

def mean(data):
    n = 0
    mean = 0.0

    for x in data:
        n += 1
        mean += (x - mean)/n

    if n < 1:
        return float('nan');
    else:
        return mean

我知道这个问题已经超级老了,但它仍然是谷歌的第一个热门,所以发帖似乎很合适。我仍然很遗憾python标准库不包含这段简单的代码。

答案 1 :(得分:7)

只需对代码进行一次简单的更改即可使用这两种代码。生成器可以互换地用于for循环中的列表。

def my_mean(values):
    n = 0
    Sum = 0.0
    for v in values:
        Sum += v
        n += 1
    return Sum / n

答案 2 :(得分:5)

def my_mean(values):
    total = 0
    for n, v in enumerate(values, 1):
        total += v
    return total / n

print my_mean(X)
print my_mean(Y)

statistics.mean() in Python 3.4it calls list() on the input

def mean(data):
    if iter(data) is data:
        data = list(data)
    n = len(data)
    if n < 1:
        raise StatisticsError('mean requires at least one data point')
    return _sum(data)/n

其中_sum()返回一个准确的总和(math.fsum() - 除了float之外还支持FractionDecimal)的功能。

答案 3 :(得分:3)

老式的做法:

def my_mean(values):
   sum, n = 0, 0
   for x in values:
      sum += x
      n += 1
   return float(sum)/n

答案 4 :(得分:1)

一种方法是

numpy.fromiter(Y, int).mean()

但这实际上暂时存储了数字。

答案 5 :(得分:1)

您的方法很好,但您应该使用for x in y惯用语而不是重复调用next,直到获得StopIteration。这适用于列表和生成器:

def my_mean(values):
    n = 0
    Sum = 0.0

    for value in values:
        Sum += value
        n += 1
    return float(Sum)/n

答案 6 :(得分:0)

def my_mean(values):
    n = 0
    sum = 0
    for v in values:
        sum += v
        n += 1
    return sum/n

以上内容与您的代码非常相似,除非使用for迭代values,无论您是获得列表还是迭代器,都是好的。 然而,python sum方法已经非常优化,因此除非列表确实很长,否则您可能会更乐意临时存储数据。

(另请注意,由于您使用的是python3,因此不需要float(sum)/n

答案 7 :(得分:0)

如果您事先知道发生器的长度并且想要避免将完整列表存储在内存中,则可以使用:

reduce(np.add, generator)/length

答案 8 :(得分:0)

您可以在不知道数组大小的情况下使用reduce:

from itertools import izip, count
reduce(lambda c,i: (c*(i[1]-1) + float(i[0]))/i[1], izip(values,count(1)),0)

答案 9 :(得分:-1)

尝试:

import itertools

def mean(i):
    (i1, i2) = itertools.tee(i, 2)
    return sum(i1) / sum(1 for _ in i2)

print mean([1,2,3,4,5])

tee将复制任何可迭代i的迭代器(例如生成器,列表等),允许您使用一个副本进行求和,另一个用于计数。

(注意'tee'仍将使用中间存储。)