numpy multiply rows with subsequent rows of an array using product values of the previous row as input

Viewed 626

Assume to have the below numpy array:

import numpy as np
array_a = np.arange(1,10).reshape(3,3)
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

How can I iteratively multiply the previous row with the subsequent row without using any loop (the value of the previous row, except row=0, being the product of the multiplication).

The desired output for the above array_a would be

[[1,   2,  3
 [4,  10, 18]
 [28, 80, 162]]

I am aware of numpy matrix multiplication function like np.dot and np.einsum but I am not able to frame my problem in a way to use those functions. A solution in pandas, if any, is also welcome. Thank you for any guidance.

1 Answers

np.cumprod is a great option if you only need to multiply.

import numpy as np
array_a = np.arange(1,10).reshape(3,3)
array_b = np.cumprod(array_a, axis=0)

Another option which is pretty efficent, is to use a generator. This is a just a little bit slower, but also more versatile

def generator(arr):
    cnt_up = len(arr)
    cnt_down = 0

    if cnt_down == 0:
        yield arr[0]

    while cnt_up > 1:
       cnt_up -= 1
       cnt_down += 1
       yield arr[cnt_down-1] * arr[cnt_down]

gen = generator(array_a)
array_b = np.stack([g for g in gen])

Last option is to use recursion for other operations (which will be much much slower slower, so np.cumpcrod/generator is preferred)

import numpy as np

array_a = np.arange(1,10).reshape(3,3)


def recursive(arr):
    if len(arr) <= 1:
        return arr
    else:
        return arr[-1] * recursive(arr[:-1])


array_b = np.stack([recursive(array_a[:i])[0] for i in range(1, len(array_a)+1)])

The second way is if you want to use a different custom formula.

Using %timeit I obtained the following results:

  • 3 nano sec for cumpcrod,
  • 9 nano sec for the generator option,
  • 25 nano secs for the recursion
Related