3

I have 0s and 1s store in a 3-dimensional numpy array:

g = np.array([[[0, 1], [0, 1], [1, 0]], [[0, 0], [1, 0], [1, 1]]])
# array([
#     [[0, 1], [0, 1], [1, 0]],
#     [[0, 0], [1, 0], [1, 1]]])

and I'd like to replace these values by those in another array using a row-wise replacement strategy. For example, replacing the vales of g by x:

x = np.array([[2, 3], [4, 5]])
array([[2, 3],
       [4, 5]])

to obtain:

array([
     [[2, 3], [2, 3], [3, 2]],
     [[4, 4], [5, 4], [5, 5]]])

The idea here would be to have the first row of g replaced by the first elements of x (0 becomes 2 and 1 becomes 3) and the same for the other row (the first dimension - number of "rows" - will always be the same for g and x)

I can't seem to be able to use np.where because there's a ValueError: operands could not be broadcast together with shapes (2,3,2) (2,2) (2,2).

4 Answers 4

3

IIUC,

np.stack([x[i, g[i]] for i in range(x.shape[0])])

Output:

array([[[2, 3],
        [2, 3],
        [3, 2]],

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

Comments

3

Vectorized approach with np.take_along_axis to index into the last axis of x with g using axis=-1 -

In [20]: np.take_along_axis(x[:,None],g,axis=-1)
Out[20]: 
array([[[2, 3],
        [2, 3],
        [3, 2]],

       [[4, 4],
        [5, 4],
        [5, 5]]])

Or with manual integer-based indexing -

In [27]: x[np.arange(len(g))[:,None,None],g]
Out[27]: 
array([[[2, 3],
        [2, 3],
        [3, 2]],

       [[4, 4],
        [5, 4],
        [5, 5]]])

4 Comments

A vectorized approach is interesting. I'm surprised it takes more or less the same time as the other answers based on list comprehension.
You can have a look at this comparaison.
@PedroA Think for a vectorized approach to shine, you need to feed in something bigger than those sample ones.
@Divakar In this particular case it is faster, but not drastically faster. For example with a 100^3 matrix it takes around 4ms while np.stack([x[i, g[i]] ... takes about 6ms and the comprehension about 14.5ms.
1

One solution, is to simply use comprehension directly here:

>>> np.array([[x[i][c] for c in r] for i, r in enumerate(g)])
array([[[2, 3],
        [2, 3],
        [3, 2]],

       [[4, 4],
        [5, 4],
        [5, 5]]])

Comments

1

From what I understand, g is an array of indexes (indexes being 0 or 1) and x is the array to who's values you use.

Something like this should work (tested quickly)

import numpy as np

def swap_indexes(index_array, array):
   out_array = []
   for i, row in enumerate(index_array):
         out_array.append([array[i,indexes] for indexes in row])
   return np.array(out_array)


index_array = np.array([[[0, 1], [0, 1], [1, 0]], [[0, 0], [1, 0], [1, 1]]])
x = np.array([[2, 3], [4, 5]])
print(swap_indexes(index_array, x))

[EDIT: fixed typo that created duplicates]

2 Comments

>g is an array of indexes This is an interesting approach. I have not looked at it this way but makes sense in the situation I'm using. The function seems to be returning duplicates though. Any way to fix this?
@PedroA you're right I had a typo in the function, should no longer return duplicates

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.