sdbbs
sdbbs

Reputation: 5384

How to do the equivalent of setting an array element with a sequence in numpy?

I just ended up being confused about this for a while, so I thought I'd document in Q&A format - although more thorough explanations are more than welcome.

Let's say, I have a 2D numpy array, say xm below:

$ python3
Python 3.8.9 (default, Apr  3 2021, 09:30:04)  [GCC 10.2.0 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
import numpy as np
x = y = np.linspace(0,1.0, 4)
xm,ym = np.meshgrid(x,y)
xm
array([[0.        , 0.33333333, 0.66666667, 1.        ],
       [0.        , 0.33333333, 0.66666667, 1.        ],
       [0.        , 0.33333333, 0.66666667, 1.        ],
       [0.        , 0.33333333, 0.66666667, 1.        ]])
>>>

... and I want to replace each element, with an array of 3 elements - say, with: the basis [1.0, 1.0, 0.5], multiplied by the scalar value of each element of the 2D array.

Multiplication of a numpy array with a scalar is trivial:

xm*2
array([[0.        , 0.66666667, 1.33333333, 2.        ],
       [0.        , 0.66666667, 1.33333333, 2.        ],
       [0.        , 0.66666667, 1.33333333, 2.        ],
       [0.        , 0.66666667, 1.33333333, 2.        ]])

... but attempting to do "scalar (element od 2D array) times list" trivially does not work:

xm*np.array([1,1])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (4,4) (2,)

... and trying to cheat by iterating through all the elements of the 2D array, and replacing each with a list/array, also fails:

for ir, irow in enumerate(xm):
  for ic, icol in enumerate(irow):
    xm[ir][ic] = icol*np.array([1, 1, 0.5])
...
TypeError: only size-1 arrays can be converted to Python scalars

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
ValueError: setting an array element with a sequence.

Yeah - but I do want do set an array element with a sequence - or at least, obtain the equivalent kind of array. How do I do that?

Upvotes: 1

Views: 361

Answers (2)

Amit Vikram Singh
Amit Vikram Singh

Reputation: 2128

Use:

xm[:, :, np.newaxis]*np.array([[1.0, 1.0, 0.5]])

Output:

array([[[0.        , 0.        , 0.        ],
    [0.33333333, 0.33333333, 0.16666667],
    [0.66666667, 0.66666667, 0.33333333],
    [1.        , 1.        , 0.5       ]],

   [[0.        , 0.        , 0.        ],
    [0.33333333, 0.33333333, 0.16666667],
    [0.66666667, 0.66666667, 0.33333333],
    [1.        , 1.        , 0.5       ]],

   [[0.        , 0.        , 0.        ],
    [0.33333333, 0.33333333, 0.16666667],
    [0.66666667, 0.66666667, 0.33333333],
    [1.        , 1.        , 0.5       ]],

   [[0.        , 0.        , 0.        ],
    [0.33333333, 0.33333333, 0.16666667],
    [0.66666667, 0.66666667, 0.33333333],
    [1.        , 1.        , 0.5       ]]])

Upvotes: 1

sdbbs
sdbbs

Reputation: 5384

Turns out, I "simply" have to reshape the arrays - basically:

  • first reshape xm of shape (4, 4) to 1D numpy array, which then has shape (16, 1);
  • multuplying each (scalar) element of that with the 1d numpy array basis, which has shape (3,), is trivial -- and we obtain a result with is an array of 3-element arrays, with a shape of (16, 3);
  • reshape that result into a numpy array of shape (4, 4, 3) - basically, we got a 3D array/matrix now
np.reshape( np.reshape(xm, (-1,1))*np.array([1,1,0.5]), (xm.shape[0], xm.shape[1], 3) )
array([[[0.        , 0.        , 0.        ],
        [0.33333333, 0.33333333, 0.16666667],
        [0.66666667, 0.66666667, 0.33333333],
        [1.        , 1.        , 0.5       ]],

       [[0.        , 0.        , 0.        ],
        [0.33333333, 0.33333333, 0.16666667],
        [0.66666667, 0.66666667, 0.33333333],
        [1.        , 1.        , 0.5       ]],

       [[0.        , 0.        , 0.        ],
        [0.33333333, 0.33333333, 0.16666667],
        [0.66666667, 0.66666667, 0.33333333],
        [1.        , 1.        , 0.5       ]],

       [[0.        , 0.        , 0.        ],
        [0.33333333, 0.33333333, 0.16666667],
        [0.66666667, 0.66666667, 0.33333333],
        [1.        , 1.        , 0.5       ]]])

Upvotes: 1

Related Questions