2012-07-03 2 views
2

При работе с генераторами вы можете вытаскивать предметы только за один проход. Альтернативой является загрузка генератора в список и выполнение нескольких проходов, но это связано с ударом по производительности и распределению памяти.Вычисление статистики по генераторам за один проход. Python

Может ли кто-нибудь подумать о лучшем способе вычисления следующих показателей из генератора за один проход. В идеале код вычисляет счет, сумму, средний, sd, max, min и любую другую статистику, о которой вы можете думать.

UPDATE

Первоначальный противный код в этом суть. См. Раздел: https://gist.github.com/3038746

Использование замечательных предложений от @larsmans здесь является окончательным решением, с которым я пошел. Использование названного кортежа действительно помогло.

import random 
from math import sqrt 
from collections import namedtuple 

def stat(gen): 
    """Returns the namedtuple Stat as below.""" 
    Stat = namedtuple('Stat', 'total, sum, avg, sd, max, min') 
    it = iter(gen) 

    x0 = next(it) 
    mx = mn = s = x0 
    s2 = x0*x0 
    n = 1 

    for x in it: 
     mx = max(mx, x) 
     mn = min(mn, x) 
     s += x 
     s2 += x*x 
     n += 1 

    return Stat(n, s, s/n, sqrt(s2/n - s*s/n/n), mx, mn) 

def random_int_list(size=100, start=0, end=1000): 
    return (random.randrange(start,end,1) for x in xrange(size)) 

if __name__ == '__main__': 
    r = stat(random_int_list()) 
    print r #Stat(total=100, sum=56295, avg=562, sd=294.82537204250247, max=994, min=10) 
+1

'stat.n + = 1.0' Тысячи мертвых математиков качению в могилах .. . –

+0

Используйте numpy. Он обладает всеми встроенными функциями, которые вам нужны, и он быстрее, чем петли python. – eumiro

+0

Lol @ IgnacioVazquez-Abrams любым другим способом вы могли бы сделать это с помощью генератора? –

ответ

7
def statistics(it): 
    """Returns number of elements, sum, max, min""" 

    it = iter(it) 

    x0 = next(it) 
    maximum = minimum = total = x0 
    n = 1 

    for x in it: 
     maximum = max(maximum, x) 
     minimum = min(minimum, x) 
     total += x 
     n += 1 

    return n, total, maximum, minimum 

Добавить другие статистические данные, как вам угодно. Рассмотрите возможность использования namedtuple, когда количество статистических вычислений увеличивается.

Если вы хотите получить действительно фантазии, вы можете построить иерархию ОО из статистики коллекторов (непроверенных):

class Summer(object): 
    def __init__(self, x0=0): 
     self.value = x0 

    def add(self, x): 
     self.value += x 

class SquareSummer(Summer): 
    def add(self, x): 
     super(SquareSummer, self).add(x ** 2) 

class Maxer(object): 
    def __init__(self, x0): 
     self.value = x0 

    def add(self, x): 
     self.value = max(self.value, x) 

# example usage: collect([Maxer, Summer], iterable) 
def collect(collectors, it): 
    it = iter(it) 

    x0 = next(it) 
    collectors = [c(x0) for c in collectors] 

    for x in it: 
     for c in collectors: 
      c.add(x) 

    return [c.value for c in collectors] 
+0

Это замечательный @larsmans, но зачем нужна его = iter (it) эта защитная проверка типа? –

+1

@MattAlcock: необходимо, чтобы функция работала как с итераторами, так и с итераторами. Например, 'next ([1])' вызывает 'TypeError'. –

Смежные вопросы