2

I would like to efficiently multiply every element in a 2D array with a 1D array using numpy, so that a 3D array is returned.

Basically, the code should do something like:

import numpy as np

#create dummy data
arr1=np.arange(0,9).reshape((3,3))
arr2=np.arange(0,9)

#create output container
out = []

#loop over every increment in arr1
for col in arr1:

    row = []

    for i in col:

        #perform calculation
        row.append(i*arr2)

    out.append(row)


#convert output to array
out = np.array(out)

With out having the shape (3, 3, 9) and thus amounting to

array([[[ 0,  0,  0,  0,  0,  0,  0,  0,  0],
        [ 0,  1,  2,  3,  4,  5,  6,  7,  8],
        [ 0,  2,  4,  6,  8, 10, 12, 14, 16]],

       [[ 0,  3,  6,  9, 12, 15, 18, 21, 24],
        [ 0,  4,  8, 12, 16, 20, 24, 28, 32],
        [ 0,  5, 10, 15, 20, 25, 30, 35, 40]],

       [[ 0,  6, 12, 18, 24, 30, 36, 42, 48],
        [ 0,  7, 14, 21, 28, 35, 42, 49, 56],
        [ 0,  8, 16, 24, 32, 40, 48, 56, 64]]])

Thank you very much in advance!

3 Answers3

2

Use numpy.outer:

np.outer(arr2,arr1).reshape(3,3,9)

to get:

array([[[ 0,  0,  0,  0,  0,  0,  0,  0,  0],
        [ 0,  1,  2,  3,  4,  5,  6,  7,  8],
        [ 0,  2,  4,  6,  8, 10, 12, 14, 16]],

       [[ 0,  3,  6,  9, 12, 15, 18, 21, 24],
        [ 0,  4,  8, 12, 16, 20, 24, 28, 32],
        [ 0,  5, 10, 15, 20, 25, 30, 35, 40]],

       [[ 0,  6, 12, 18, 24, 30, 36, 42, 48],
        [ 0,  7, 14, 21, 28, 35, 42, 49, 56],
        [ 0,  8, 16, 24, 32, 40, 48, 56, 64]]])
seralouk
  • 30,938
  • 9
  • 118
  • 133
  • Thank you for your answer. Unfortunately, this approach does not mimic the behaviour of the above stated nested loop. If you try to operate it on different arrays you will find that the reshaping does not keep the required hierachy. – Cpt Fishpan Jan 24 '20 at 07:57
1

Alternatively to np.outer product as in @makis' answer, you can directly use np.einsum like this:

out_einsum = np.einsum('i,jk->jki', arr2, arr1)

and then avoid reshaping. Thus, also giving:

>>> array([[[ 0,  0,  0,  0,  0,  0,  0,  0,  0],
            [ 0,  1,  2,  3,  4,  5,  6,  7,  8],
            [ 0,  2,  4,  6,  8, 10, 12, 14, 16]],

           [[ 0,  3,  6,  9, 12, 15, 18, 21, 24],
            [ 0,  4,  8, 12, 16, 20, 24, 28, 32],
            [ 0,  5, 10, 15, 20, 25, 30, 35, 40]],

           [[ 0,  6, 12, 18, 24, 30, 36, 42, 48],
            [ 0,  7, 14, 21, 28, 35, 42, 49, 56],
            [ 0,  8, 16, 24, 32, 40, 48, 56, 64]]])

This has the disadvantage of being a bit less intuitive if you are not used to that function subscripts inputs but it's worth the try.

Yacola
  • 2,873
  • 1
  • 10
  • 27
-1
(arr1.reshape(arr2.size, 1) * arr2.reshape(1, arr2.size)).reshape(3, 3, 9)