1

I have a multimensionnal array with a shape of (2, 2, 3) like this :

array([[[  0.64,   0.49,   2.56],
    [  7.84,  13.69,  21.16]],

   [[ 33.64,  44.89,  57.76],
    [ 77.44,  94.09, 112.36]]])

I would like to find the indices of the min for each row. So for this example there are 4 minimums which are : 0.49, 7.84, 33.64 and 77.44.

To get the indices of those minimum I thought this would work :

idx_arr = np.unravel_index(np.argmin(my_array,axis=2),my_array.shape)

This yields the following array of indices :

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

However, the minimums are not correctly computed, as one can see :

my_array[idx_arr]
array([[0.49, 0.64],
   [0.64, 0.64]])

What am I missing there ?

1 Answer 1

1

the argmin is actually calculating the values correctly. But you misunderstand what np.unravel_index is expecting.

From docs:

Converts a flat index or array of flat indices into a tuple of coordinate arrays.

To see what kind of input it would accept to give the desired output here, We need to focus on the main point: it will convert a flat array into the correct coordinate array for a particular location in non-flat terms. Essentially, what it expected is coordinates of your desired points as if your input array was flattened.

import numpy as np
inp = np.array([[[  0.64,   0.49,   2.56],
    [  7.84,  13.69,  21.16]],

   [[ 33.64,  44.89,  57.76],
    [ 77.44,  94.09, 112.36]]])

idx = inp.argmin(axis=-1)
#Output:
array([[1, 0],
       [0, 0]], dtype=int64)

Note that you cannot send this idx directly because it is not representing correct coordinates for a flattened version of inp array.

That would look more like the following:

flat_idx = np.arange(0, idx.size*inp.shape[-1], inp.shape[-1]) + idx.flatten()
#Output:
array([1, 3, 6, 9], dtype=int64)

And we can see unravel_index accepts it happily.

temp = np.unravel_index(flat_idx, inp.shape)
#Output:
(array([0, 0, 1, 1], dtype=int64),
 array([0, 1, 0, 1], dtype=int64),
 array([1, 0, 0, 0], dtype=int64))

inp[temp]

Output:

array([ 0.49,  7.84, 33.64, 77.44])

Also, taking a look at the output tuple, we can notice that it is not too difficult to recreate the same ourselves as well. Notice that the last array corresponds to a flattened form of idx, while the first two arrays essentially enable indexing through the first two axes of inp.


And to prepare that, we can actually use the unravel_index function in a rather nifty way, as follows:

real_idx = (*np.unravel_index(np.arange(idx.size), idx.shape), idx.flatten())
inp[real_idx]
#Output:
array([ 0.49,  7.84, 33.64, 77.44])
Sign up to request clarification or add additional context in comments.

Comments

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.