[Numpy-discussion] custom accumlators

Tim Hochberg tim.hochberg at ieee.org
Fri Jan 5 21:23:57 CST 2007


Matt Knox wrote:
>>>>     
>>>>         
>>> You might want to look at frompyfunc:
>>>
>>>         def expmave2(x, k):
>>>             def expmave_sub(a, b):
>>>                 return a + k * (b - a)
>>>             return np.frompyfunc(expmave_sub, 2, 1).accumulate(x)
>>>
>>>
>>> It's amazing what you find when you dig around.
>>>       
>
> Thanks a lot everyone. This has been informative. For what it's worth, I did 
> some performance comparisons...
>
> import numpy as np
> import profile
>
> def expmave1(x, k):
>     def expmave_sub(a, b):
>         return b + k * (a - b)
>     return np.frompyfunc(expmave_sub, 2, 1).accumulate(x).astype(x.dtype)
>
>
> def expmave2(x, k):
>     result = np.array(x, copy=True)
>     for i in range(1, result.size):
>        result[i] = result[i-1] + k * (result[i] - result[i-1])
>     return result
>
> testArray = np.cumprod(1 + np.random.normal(size=10000)/100)
>
>
> profile.run('expmave1(testArray, 0.2)')
> profile.run('expmave2(testArray, 0.2)')
>
> and the second function is faster, which I guess makes sense if frompyfunc is 
> pure python, although the first one does have a nice elegance to it I think.
>   
Are you sure about this? I ran this case using timeit, and the first one 
was 5 times or so *faster* than the second case. I just dug around and 
frompyfunc is acutally implemented in C, although it has to call back 
into python to execute the function being vectorized. Can you try using 
timeit instead of profile and see what you get? For example:

    a = np.cumprod(1 + np.random.normal(size=10000)/10)
 
    if __name__ == '__main__':
        from timeit import Timer
        print Timer('expmave1(a, .5)', 'from scratch import np, 
expmave1, a').timeit(10)
        print Timer('expmave2(a, .5)', 'from scratch import np, 
expmave2, a').timeit(10)

Anyway, I'm glad that all was helpful.

-tim

-tim






More information about the Numpy-discussion mailing list