20

Is there a function in numpy or scipy (or some other library) that generalizes the idea of cumsum and cumprod to arbitrary function. For example, consider the (theoretical) function

cumf( func, array) 

func is a function that accepts two floats, and returns a float. Particular cases

lambda x,y: x+y 

and

lambda x,y: x*y 

are cumsum and cumprod respectively. For example, if

func = lambda x,prev_x: x^2*prev_x 

and I apply it to:

cumf(func, np.array( 1, 2, 3) )

I would like

np.array( 1, 4, 9*4 )
Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
Cam.Davidson.Pilon
  • 1,606
  • 1
  • 17
  • 31
  • I think this is a great idea, but I think it is more canonical to define `func = lambda x, y: x+y` (two non-related arguments) and let the cumulative concept to "figure out" that x and y are actually consecutive elements of a sequence. – heltonbiker Dec 11 '12 at 21:53
  • that was more for human readers ;) – Cam.Davidson.Pilon Dec 11 '12 at 22:06

2 Answers2

14

The ValueError above is still a bug using Numpy 1.20.1 (with Python 3.9.1).

Luckily a workaround was discovered that uses casting: https://groups.google.com/forum/#!topic/numpy/JgUltPe2hqw

import numpy as np
uadd = np.frompyfunc(lambda x, y: x + y, 2, 1)
uadd.accumulate([1,2,3], dtype=object).astype(int)
# array([1, 3, 6])

Note that since the custom operation works on an object type, it won't benefit from the efficient memory management of numpy. So the operation may be slower than one that didn't need casting to object for extremely large arrays.

user2561747
  • 1,333
  • 2
  • 16
  • 39
12

NumPy's ufuncs have accumulate():

In [22]: np.multiply.accumulate([[1, 2, 3], [4, 5, 6]], axis=1)
Out[22]: 
array([[  1,   2,   6],
       [  4,  20, 120]])

Unfortunately, calling accumulate() on a frompyfunc()'ed Python function fails with a strange error:

In [32]: uadd = np.frompyfunc(lambda x, y: x + y, 2, 1)

In [33]: uadd.accumulate([1, 2, 3])
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)

ValueError: could not find a matching type for <lambda> (vectorized).accumulate, 
            requested type has type code 'l'

This is using NumPy 1.6.1 with Python 2.7.3.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Ah, but I would like an numpy array as output – Cam.Davidson.Pilon Dec 11 '12 at 21:15
  • @Cam.Davidson.Pilon -- What do you mean you'd like a numpy array as output? A concrete example would be helpful. – mgilson Dec 11 '12 at 21:18
  • No need for `np.array` here. Numpy will happily operate on your lists, but good answer (+1) – mgilson Dec 11 '12 at 21:19
  • While it fails with lambda functoins, I can recreate my desired function with ufuncs. This is what I needed. Thanks for introducing me to ufuncs and accumulate! – Cam.Davidson.Pilon Dec 11 '12 at 21:33
  • @Cam.Davidson.Pilon Now that you figured out how to do it with ufuncs and accumulate, please post a piece of working code as your own answer, or editing the question, so that others will benefit also. Thanks! – heltonbiker Dec 11 '12 at 21:55
  • On further analysis, I actually cannot use this method. There is apparently a bug in Numpy 1.6, hence the ValueEror above (same as I get) http://mail.scipy.org/pipermail/numpy-discussion/2011-September/058501.html Either way, my question was answered with the knowledge of frompyfunc() and accumulate() – Cam.Davidson.Pilon Dec 11 '12 at 22:09
  • @Cam.Davidson.Pilon: Yes, that's exactly the bug I've run into. – NPE Dec 11 '12 at 22:09
  • with `numpy 1.24.2` the error is fixed – cards Feb 16 '23 at 14:46