Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant way of reducing list by averaging?

Tags:

python

list

Is there a more elegant way of writing this function?

def reduce(li):
    result=[0 for i in xrange((len(li)/2)+(len(li)%2))]
    for i,e in enumerate(li):
        result[int(i/2)] += e
    for i in range(len(result)):
        result[i] /= 2
    if (len(li)%2 == 1):
        result[len(result)-1] *= 2
    return result

Here, what it does:

a = [0,2,10,12]
b = [0,2,10,12,20]
reduce(a)
>>> [1,11]
reduce(b)
>>> [1,11,20]

It is taking average of even and odd indexes, and leaves last one as is if list has odd number of elements

like image 639
gok Avatar asked Mar 02 '11 00:03

gok


1 Answers

what you actually want to do is to apply a moving average of 2 samples trough your list, mathematically you convolve a window of [.5,.5], then take just the even samples. To avoid dividing by two the last element of odd arrays, you should duplicate it, this does not affect even arrays.

Using numpy it gets pretty elegant:

import numpy as np

np.convolve(a + [a[-1]], [.5,.5], mode='valid')[::2]
array([  1.,  11.])

np.convolve(b + [b[-1]], [.5,.5], mode='valid')[::2]
array([  1.,  11.,  20.])

you can convert back to list using list(outputarray).

using numpy is very useful if performance matters, optimized C math code is doing the work:

In [10]: %time a=reduce(list(np.arange(1000000))) #chosen answer
CPU times: user 6.38 s, sys: 0.08 s, total: 6.46 s
Wall time: 6.39 s

In [11]: %time c=np.convolve(list(np.arange(1000000)), [.5,.5], mode='valid')[::2]
CPU times: user 0.59 s, sys: 0.01 s, total: 0.60 s
Wall time: 0.61 s
like image 167
Andrea Zonca Avatar answered Oct 15 '22 03:10

Andrea Zonca