1

In Python, say you have a 2D array of zeros of shape (N,4,4):

z = array([[[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]],

   [[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]]])

and you have a 2D array of indices:

i = array([[1, 1, 1, 1],
       [1, 0, 0, 0],
       [0, 0, 1, 1],
       [1, 1, 1, 0]])

and some valued 2D array:

v = array([[ 2.,  4., 10.,  7.],
   [10.,  9.,  9.,  2.],
   [ 3.,  8.,  8.,  8.],
   [ 8.,  6., 10.,  1.]])

Is there a way to fill the elements of z with the values of v but in the slices denoted by i, without using loops?

Note: Is there a way to do this in a scalable fashion such that if you had an N channel array z, where N>>1, you would not need to directly index z[i] when filling it with values from v?

For clarity, the resulting z array would look like the following:

z = array([[[0., 0., 0., 0.],
    [0., 9., 9., 2.],
    [3., 8., 0., 0.],
    [0., 0., 0., 1.]],

   [[2., 4., 10., 7.],
    [10., 0., 0., 0.],
    [0., 0., 8., 8.],
    [8, 6., 10., 0.]]])

Obviously, using something like:

z = v[i,:,:]

would never work but maybe there's a way to use rows, cols to do this?

Many thanks in advance!


Edit:

For clarity here is a similar example but for a 3D z as requested in the comments:

z = array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])


i = array([[2, 1, 2, 1],
       [1, 1, 2, 1],
       [1, 1, 1, 1],
       [1, 0, 0, 1]])


v = array([[5., 5., 0., 4.],
       [4., 6., 8., 3.],
       [4., 0., 4., 8.],
       [7., 6., 5., 7.]])

z would become:

z = array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 6., 5., 0.]],

       [[0., 5., 0., 4.],
        [4., 6., 0., 3.],
        [4., 0., 4., 8.],
        [7., 0., 0., 7.]],

       [[5., 0., 0., 0.],
        [0., 0., 8., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])

3 Answers 3

2

You can always use masks and multiply:

from numpy import array
z = array([[[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]],

   [[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]]])
i = array([[1, 1, 1, 1],
       [1, 0, 0, 0],
       [0, 0, 1, 1],
       [1, 1, 1, 0]])
v = array([[ 2.,  4., 10.,  7.],
   [10.,  9.,  9.,  2.],
   [ 3.,  8.,  8.,  8.],
   [ 8.,  6., 10.,  1.]])
z[0] = ~i.astype(bool)*v
z[1] = i.astype(bool)*v

Output:

z = 
array([[[ 0.,  0.,  0.,  0.],
        [ 0.,  9.,  9.,  2.],
        [ 3.,  8.,  0.,  0.],
        [ 0.,  0.,  0.,  1.]],

       [[ 2.,  4., 10.,  7.],
        [10.,  0.,  0.,  0.],
        [ 0.,  0.,  8.,  8.],
        [ 8.,  6., 10.,  0.]]])

For more general case:

for ax in np.unique(i):
    mask = i == ax
    z[ax] = mask*v
print(z)

Output:

[[[0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]
  [0. 6. 5. 0.]]

 [[0. 5. 0. 4.]
  [4. 6. 0. 3.]
  [4. 0. 4. 8.]
  [7. 0. 0. 7.]]

 [[5. 0. 0. 0.]
  [0. 0. 8. 0.]
  [0. 0. 0. 0.]
  [0. 0. 0. 0.]]]

Note: Here I assumed the values in i are same as there are channels in z. If different, instead of np.unique, you can try:

for i_val,ax in zip(np.unique(i),range(z.shape[0]))::
    mask = i == i_val
    z[ax] = mask*v

EDIT

A one-liner would be:

>>> z = np.array([*map(i.__eq__,np.unique(i))])*np.array([v]*z.shape[0])
>>> z
array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 6., 5., 0.]],

       [[0., 5., 0., 4.],
        [4., 6., 0., 3.],
        [4., 0., 4., 8.],
        [7., 0., 0., 7.]],

       [[5., 0., 0., 0.],
        [0., 0., 8., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the reply, unfortunately this wouldn't be scalable for high dimensional versions of z with many many channels. That's my fault for not being clear enough in he question though so I've updated the text accordingly.
Could you provide an example for what you want for z with 3 channels?
Thanks! I tried working that through and it all looks good :D
Glad to help :)
If the 4D array is X then, for k in range(X.shape[0]):X[k] = np.array([*map(i.__eq__,np.unique(i))])*np.array([v]*X[k].shape[0])
|
1

Something more complicated without numpy:

r = list(zip(i,v))
z[0] = [[l2[i] if l1[i]==0 else 0 for i in range(4)] for l1, l2 in r ]
z[1] = [[l2[i] if l1[i]==1 else 0 for i in range(4)] for l1, l2 in r ]

2 Comments

Thanks, this works but with loops unfortunately.. so not the ideal case but if it can't be done without loops then it's currently the best option.
@user8188120 it has a nested-loop for each of the z[0], z[1]... etc. It is defenitally not better than numpy solutions who don't have a single loop for each of the z[0], z[1]... etc.
1

Possible using numpy.where:

z[0] = np.where(i, z[0], v)
z[1] = np.where(1 - i, z[1], v)

Output:

array([[[ 0.,  0.,  0.,  0.],
        [ 0.,  9.,  9.,  2.],
        [ 3.,  8.,  0.,  0.],
        [ 0.,  0.,  0.,  1.]],

       [[ 2.,  4., 10.,  7.],
        [10.,  0.,  0.,  0.],
        [ 0.,  0.,  8.,  8.],
        [ 8.,  6., 10.,  0.]]])

And after your update, if i hold the indices of z to be changed (and opposite from the 0's and 1's in your example), it can be scaled easily to:

for N in range(z.shape[0]):    
    z[N] = np.where(i == N, v, z[N])

Or if you really want to avoid loops alltogheter:

z = np.where(i == (np.where(np.ones(len(z.reshape(-1))) == 1)[0] // (z.shape[1] * z.shape[2])).reshape(z.shape), v, z)

Ouput:

array([[[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 6., 5., 0.]],

   [[0., 5., 0., 4.],
    [4., 6., 0., 3.],
    [4., 0., 4., 8.],
    [7., 0., 0., 7.]],

   [[5., 0., 0., 0.],
    [0., 0., 8., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]]])

1 Comment

Thanks for the reply, unfortunately this wouldn't be scalable for high dimensional versions of z with many many channels as in the true problem I won't be able to index z[i] if there were say hundreds of channels. That's my fault for not being clear enough in he question though so I've updated the text accordingly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.