ここでは、2 つの解決策をご紹介します。どちらも、任意の数値リストで機能する単なる一般的な移動平均関数です。(任意の iterable で動作するようにすることができます)
ジェネレーターベース:
nums = [cauchy(3,1) for x in xrange(10)]
def running_avg(numbers):
for count in xrange(1, len(nums)+1):
yield sum(numbers[:count])/count
print list(running_avg(nums))
リスト内包表記ベース (実際には以前と同じコード):
nums = [cauchy(3,1) for x in xrange(10)]
print [sum(nums[:count])/count for count in xrange(1, len(nums)+1)]
発電機互換発電機ベース:
編集:これは、ソリューションをジェネレーターと簡単に互換性を持たせることができるかどうか、およびそのパフォーマンスがどうなるかを確認するためにテストしたばかりです。これが私が思いついたものです。
def running_avg(numbers):
sum = 0
for count, number in enumerate(numbers):
sum += number
yield sum/(count+1)
以下のパフォーマンス統計を参照してください。それだけの価値があります。
性能特性:
編集: また、複数のジェネレーターを使用した Orip の興味深い使用法をテストして、パフォーマンスへの影響を確認することにしました。
timeit と以下を使用します (1,000,000 回の反復を 3 回):
print "Generator based:", ', '.join(str(x) for x in Timer('list(running_avg(nums))', 'from __main__ import nums, running_avg').repeat())
print "LC based:", ', '.join(str(x) for x in Timer('[sum(nums[:count])/count for count in xrange(1, len(nums)+1)]', 'from __main__ import nums').repeat())
print "Orip's:", ', '.join(str(x) for x in Timer('list(itertools.islice(running_avgs, 10))', 'from __main__ import itertools, running_avgs').repeat())
print "Generator-compatabile Generator based:", ', '.join(str(x) for x in Timer('list(running_avg(nums))', 'from __main__ import nums, running_avg').repeat())
次の結果が得られます。
Generator based: 17.653908968, 17.8027219772, 18.0342400074
LC based: 14.3925321102, 14.4613749981, 14.4277560711
Orip's: 30.8035550117, 30.3142540455, 30.5146529675
Generator-compatabile Generator based: 3.55352187157, 3.54164409637, 3.59098005295
コードのコメントを参照してください:
Orip's genEx based: 4.31488609314, 4.29926609993, 4.30518198013
結果は数秒で表示され、LCジェネレーターと互換性のある新しいジェネレーター メソッドが一貫して高速であることを示していますが、結果は異なる場合があります。元のジェネレーターと新しいジェネレーターの大きな違いは、合計がその場で計算されないという事実だと思います。