Home > Software engineering >  Generating an array of arrays in Python
Generating an array of arrays in Python

Time:06-09

I want to multiply each element of B to the whole array A to obtain P. The current and desired outputs are attached. The desired output is basically an array consisting of 2 arrays since there are two elements in B.

import numpy as np
A=np.array([[1, 2, 3],
       [4, 5, 6],
       [7 , 8, 9]])
t = np.linspace(0,1,2)
B = 0.02109*np.exp(-t)
P=B*A
print(P)

The current output is

ValueError: operands could not be broadcast together with shapes (2,) (3,3) 

The desired output is

array(([[0.02109, 0.04218, 0.06327],
       [0.08436, 0.10545, 0.12654],
       [0.14763, 0.16872, 0.18981]]),
([[0.00775858, 0.01551716, 0.02327574],
       [0.03103432, 0.0387929 , 0.04655148],
       [0.05431006, 0.06206864, 0.06982722]]))

CodePudding user response:

You can do this by:

B.reshape(-1, 1, 1) * A

or

B[:, None, None] * A

where -1 or : refer to B.shape[0] which was 2 and 1, 1 or None, None add two additional dimensions to B to get the desired result shape which was (2, 3, 3).

CodePudding user response:

The easiest way i can think of is using list comprehension and then casting back to numpy.ndarray

np.asarray([A*i for i in B])

Answer :

array([[[0.02109   , 0.04218   , 0.06327   ],
        [0.08436   , 0.10545   , 0.12654   ],
        [0.14763   , 0.16872   , 0.18981   ]],

       [[0.00775858, 0.01551715, 0.02327573],
        [0.03103431, 0.03879289, 0.04655146],
        [0.05431004, 0.06206862, 0.0698272 ]]])

CodePudding user response:

There are many possible ways for this:

Here is an overview on their runtime for the given array (bare in mind these will change for bigger arrays):

  • reshape: 0.000174 sec
  • tensordot: 0.000550 sec
  • einsum: 0.000196 sec
  • manual loop: 0.000326 sec

See the implementation for each of these:

numpy reshape

Find documentation here: Link

Gives a new shape to an array without changing its data.

Here we reshape the array B so we can later multiply it:

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

t = np.linspace(0,1,2)
B = 0.02109*np.exp(-t)
P = B.reshape(-1, 1, 1) * A
print(P)


numpy tensordot

Find documentation here: Link

Given two tensors, a and b, and an array_like object containing two array_like objects, (a_axes, b_axes), sum the products of a’s and b’s elements (components) over the axes specified by a_axes and b_axes. The third argument can be a single non-negative integer_like scalar, N; if it is such, then the last N dimensions of a and the first N dimensions of b are summed over.

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

t = np.linspace(0,1,2)
B = 0.02109*np.exp(-t)

P = np.tensordot(B, A, 0)
print(P)

numpy einsum (Einstein summation)

Find documentation here: Link

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

t = np.linspace(0,1,2)
B = 0.02109*np.exp(-t)
   
P = np.einsum('ij,k', A, B)
print(P)

Note: A has two dimensions, we assign ij for their indexes. B has one dimension, we assign k to its index


manual loop

Another simple approach would be a loop (is faster than tensordot for the given input). This approach could be made "numpy free" if you dont want to use numpy for some reason. Here is the version with numpy:

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

t = np.linspace(0,1,2)
B = 0.02109*np.exp(-t)

products = []
for b in B:
    products.append(b*A)
P = np.array(products)
print(P)

#or the same as one-liner: np.asarray([A * elem for elem in B])
  • Related