代码之家  ›  专栏  ›  技术社区  ›  Nate Kohl

python中的运行平均值

  •  13
  • Nate Kohl  · 技术社区  · 15 年前

    有没有蟒蛇的方法 建立包含运行平均值的列表 有什么作用吗?

    在读了一篇关于 Martians, black boxes, and the Cauchy distribution 我认为自己计算柯西分布的平均值会很有趣:

    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 列出而不是使用循环和计数器(例如 list comprehensions )

    有一些相关的问题,但它们解决了更复杂的问题(小窗口大小、指数加权),或者不特定于Python:

    3 回复  |  直到 8 年前
        1
  •  15
  •   orip    15 年前

    你可以写一个生成器:

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

    或者,给定一个用于Cauchy数的生成器和一个用于运行和生成器的实用函数,您可以有一个简洁的生成器表达式:

    # 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
    
        2
  •  6
  •   Markus Jarderot    12 年前

    你可以使用协同训练。它们类似于生成器,但允许您发送值。在python 2.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一起工作。这个 下() 函数也已返回到python 2.6+。
      在python 2.5中,您可以将调用替换为 N.(下) 或定义 next 发挥你自己的作用。
      (谢谢亚当·帕金)
        3
  •  4
  •   Bryan McLemore    15 年前

    我有两个可能的解决办法。这两个函数都是通用的运行平均值函数,适用于任何数字列表。(可以与任何无法识别的人一起工作)

    基于发电机:

    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和以下(1000000次迭代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 
    

    结果以秒为单位,并显示 液晶 新的生成器兼容的生成器方法要始终更快,您的结果可能会有所不同。我预计我的原始发电机和新发电机之间的巨大区别在于,总和不是即时计算的。