是否有一个功能已大大增强的方式来 建立一个列表,其中包含一个正在运行的平均 一些功能?

在阅读一个有趣的小块约 火星,黑盒,而柯西的分布, 我认为这将是有趣的计算正在运行的平均分配柯西我自己:

import math 
import random

def cauchy(location, scale):
    p = 0.0
    while p == 0.0:
        p = random.random()
    return location + scale*math.tan(math.pi*(p - 0.5))

# is this next block of code a good way to populate running_avg?
sum = 0
count = 0
max = 10
running_avg = []
while count < max:
    num = cauchy(3,1)
    sum += num
    count += 1
    running_avg.append(sum/count)

print running_avg     # or do something else with it, besides printing

我认为,这种方法的工作,但我很好奇如果有可能是一个更优雅的方式建立起来, running_avg 列于使用循环和计(例如 列表解析).

有一些相关的问题,但他们解决更为复杂的问题(很小的窗口大小、指数的加权)或者不具体到蟒蛇:

有帮助吗?

解决方案

你可以写一个发生器:

def running_average():
  sum = 0
  count = 0
  while True:
    sum += cauchy(3,1)
    count += 1
    yield sum/count

或者,给予发电机,用于柯西数字和实用功能,用于正在运行的总和生,你可以有一个整洁的发电机的表达:

# Cauchy numbers generator
def cauchy_numbers():
  while True:
    yield cauchy(3,1)

# running sum utility function
def running_sum(iterable):
  sum = 0
  for x in iterable:
    sum += x
    yield sum

# Running averages generator expression (** the neat part **)
running_avgs = (sum/(i+1) for (i,sum) in enumerate(running_sum(cauchy_numbers())))

# goes on forever
for avg in running_avgs:
  print avg

# alternatively, take just the first 10
import itertools
for avg in itertools.islice(running_avgs, 10):
  print avg

其他提示

你可以用协同程序.它们类似于发电机发电,但可以让你送值。协程中加入Python2.5,因此这不会的工作,在之前的版本。

def running_average():
    sum = 0.0
    count = 0
    value = yield(float('nan'))
    while True:
        sum += value
        count += 1
        value = yield(sum/count)

ravg = running_average()
next(ravg)   # advance the corutine to the first yield

for i in xrange(10):
    avg = ravg.send(cauchy(3,1))
    print 'Running average: %.6f' % (avg,)

作为一个列理解:

ravg = running_average()
next(ravg)
ravg_list = [ravg.send(cauchy(3,1)) for i in xrange(10)]

编辑:

  • 使用 next() 功能来代替 it.next() 法。这是如此,它还将与Python3.的 next() 功能也已经回来了-移植到蟒蛇2.6+.
    在Python2.5,你可以替换的电话 it.next(), 或定义 next 功能的你自己。
    (谢谢你亚当*帕金)

我有两个可能的解决方案。两者都是通用的运行平均功能工作的任何数字列表。(可以工作,与任何可迭代)

发生基于:

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)]

发电机-compatabile发生基于:

编辑:这一次我只是测试,看看如果我能让我的解决方案兼容的发电机很容易地以及它的业绩。这是什么,我来了。

def running_avg(numbers):
    sum = 0
    for count, number in enumerate(numbers):
        sum += number
        yield sum/(count+1)

看到的绩效统计数据以下,值得的。

性能特征:

编辑:我还决定试验Orip趣的是使用多个发电机以看到影响的性能。

使用斑马旅行记和下面(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 新的发电机兼容的发电机的方法是一致的速度更快,结果可能有所不同。我期待着巨大的差异之间我原来的发电机和一个新的事实是,总和不计算的飞行。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top