17

私はいくつかの統計作業を行っています。平均を計算する乱数の(大きな)コレクションがあります。平均を計算する必要があるだけなので、ジェネレーターを使用したいので、保存する必要はありません数字。

問題は、ジェネレーターに渡すと numpy.mean が壊れることです。やりたいことをする簡単な関数を書くことができますが、これを行うための適切な組み込みの方法があるかどうか疑問に思っていますか?

「sum(values)/len(values)」と言えればいいのですが、len はジェネレータには機能せず、sum はすでに消費された値です。

例を次に示します。

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 はジェネレーターでは機能しません。

ジェネレーターを使用するというアイデアは本当に気に入っていますが、このような詳細は物事を台無しにしているようです.

4

10 に答える 10

25

一般に、浮動小数点数のストリーミング平均計算を行う場合は、単純にジェネレーターを合計して長さで割るよりも、数値的に安定したアルゴリズムを使用する方がよいでしょう。

これらの中で最も単純なもの (私が知っている) は、通常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 標準ライブラリにこの単純なコードが含まれていないことは、今でも残念です。

于 2015-06-26T00:25:33.860 に答える
7

コードを 1 つ変更するだけで、両方を使用できるようになります。ジェネレーターは、for ループ内のリストと同じ意味で使用されることを意図していました。

def my_mean(values):
    n = 0
    Sum = 0.0
    for v in values:
        Sum += v
        n += 1
    return Sum / n
于 2011-02-10T23:20:18.537 に答える
7
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()Python 3.4にはありますが、入力で呼び出しlist()ます:

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

where_sum()は正確な合計を返します (に加えて,もサポートするmath.fsum()ような関数)。floatFractionDecimal

于 2011-02-11T20:29:10.517 に答える
3

それを行う昔ながらの方法:

def my_mean(values):
   sum, n = 0, 0
   for x in values:
      sum += x
      n += 1
   return float(sum)/n
于 2011-02-10T23:21:03.417 に答える
1

1つの方法は

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

しかし、これは実際には数値を一時的に保存します。

于 2011-02-10T23:17:25.897 に答える
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
于 2011-02-10T23:20:11.420 に答える
0
def my_mean(values):
    n = 0
    sum = 0
    for v in values:
        sum += v
        n += 1
    return sum/n

上記はあなたのコードと非常に似ていますが、リストまたはイテレータを取得するかどうかに関係なくfor、反復するために使用することを除いて. valuesただし、pythonsumメソッドは非常に最適化されているため、リストが非常に長くない限り、データを一時的に保存する方が満足できる場合があります。

(また、python3 を使用しているため、必要ないことに注意してくださいfloat(sum)/n)

于 2011-02-10T23:18:23.727 に答える
0

ジェネレーターの長さが事前にわかっていて、完全なリストをメモリに保存したくない場合は、次を使用できます。

reduce(np.add, generator)/length
于 2015-06-25T12:38:17.990 に答える
-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(ジェネレータ、リストなど) のイテレータを複製し、1 つの複製を合計に使用し、もう 1 つの複製をカウントに使用できるようにします。

(「tee」は引き続き中間ストレージを使用することに注意してください)。

于 2011-02-10T23:16:57.020 に答える