pythonarraysnumpymultidimensional-arraytensordot

Generating an array of arrays in Python


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)

It currently produces an error:

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]]))

Solution

  • 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):

    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])