2013-08-21 74 views
3

我有很多数据,通常在一个文件中。我想计算一些量,所以我有这样的功能:单迭代共享迭代器

def mean(iterator): 
    n = 0 
    sum = 0. 
    for i in iterator: 
     sum += i 
     n += 1 
    return sum/float(n) 

我也有很多其他类似的功能(varsize,...)

现在我有一个迭代器迭代throught数据:iter_data。我可以计算我想要的所有数量:m = mean(iter_data); v = var(iter_data)等,但问题是我迭代了很多次,这对我来说很贵。其实I/O是最昂贵的部分。

所以,问题是:我可以计算我的数量m, v, ...迭代只有一次超过iter_data保持独立功能meanvar,...所以,它很容易增加新的?

我需要的是类似于boost::accumulators

+1

http://www.johndcook.com/standard_deviation.html – YXD

+1

你可以捆绑所有功能于一体的功能与一个循环,返回的字典所有的计算值,如'{'mean':2.7,'var':0.2,'size':27}'等等。 – Brionius

+0

@MrE:不,在你的解决方案中,你并没有保持独立的功能,但你计算相同函数中的均值和方差 –

回答

2

东西,你可以使用itertools.tee和发电机魔术(我说的魔力,因为它不是完全好的,可读):

import itertools 

def mean(iterator): 
    n = 0 
    sum = 0. 
    for i in iterator: 
     sum += i 
     n += 1 
     yield 
    yield sum/float(n) 

def multi_iterate(funcs, iter_data): 
    iterators = itertools.tee(iter_data, len(funcs)) 
    result_iterators = [func(values) for func, values in zip(funcs, iterators)] 
    for results in itertools.izip(*result_iterators): 
     pass 
    return results 

mean_result, var_result = multi_iterate([mean, var], iter([10, 20, 30])) 

print(mean_result) # 20.0 

顺便说一句,你可以写mean在一个简单的方法:

def mean(iterator): 
    total = 0. 
    for n, item in enumerate(iterator, 1): 
     total += i 
     yield 
    yield total/n 

你不应该命名变量sum因为SH使用相同名称的内置函数。

0

你想要的是有一个主要Calc类,通过数据迭代采用不同的计算meanvar然后可以通过接口返回的值。通过让计算在主计算之前向这个类注册自己,然后通过界面中的新访问者获得他们的结果,可以使它更通用化。

5

例如使用对象和回调等:

class Counter(): 
    def __init__(self): 
     self.n = 0 
    def __call__(self, i): 
     self.n += 1 

class Summer(): 
    def __init__(self): 
     self.sum = 0 
    def __call__(self, i): 
     self.sum += i 


def process(iterator, callbacks): 
    for i in iterator: 
     for f in callbacks: f(i) 

counter = Counter() 
summer = Summer() 
callbacks = [counter, summer] 
iterator = xrange(10) # testdata 
process(iterator, callbacks) 

# process results from callbacks 
n = counter.n 
sum = summer.sum 

这是很容易伸缩并迭代数据仅一次。

1

没有班,你能适应以下几点:

def my_mean(): 
    total = 0. 
    length = 0 
    while True: 
     val = (yield) 
     if val is not None: 
      total += val 
      length += 1 
     else: 
      yield total/length 

def my_len(): 
    length = 0 
    while True: 
     val = (yield) 
     if val is not None: 
      length += 1 
     else: 
      yield length 

def my_sum(): 
    total = 0. 
    while True: 
     val = (yield) 
     if val is not None: 
      total += val 
     else: 
      yield total 


def process(iterable, **funcs): 
    fns = {name:func() for name, func in funcs.iteritems()} 
    for fn in fns.itervalues(): 
     fn.send(None) 
    for item in iterable: 
     for fn in fns.itervalues(): 
      fn.send(item) 
    return {name:next(func) for name, func in fns.iteritems()} 


data = [1, 2, 3] 
print process(data, items=my_len, some_other_value=my_mean, Total=my_sum) 
# {'items': 3, 'some_other_value': 2.0, 'Total': 6.0}