twfx
twfx

Reputation: 1694

Identify offset of a value in numpy

Given a flatten NxN array in numpy, I'd like to find the minimum value, and its offset in the array. I've managed to find the minimum value, but is it possible to identify the offset (which row and which column)?

In the example below, a = 0.5, how can I know if it is 0.5 from [1,0], or [2,1]?

from numpy import *

value = 0
NUM_NODE = 5
EDGE = array(zeros((NUM_NODE, NUM_NODE)))
EDGE = [[ 0.,          0.,          0.,          0.,          0.        ],
    [ 0.5,         0.,          0.,          0.,          0.        ],
    [ 1.,          0.5,         0.,          0.,          0.        ],
    [ 1.41421356,  1.11803399,  1.,          0.,          0.        ],
    [ 1.,          1.11803399,  1.41421356,  1.,          0.        ]]

a = reshape(EDGE, NUM_NODE*NUM_NODE)
print min(filter(lambda x : x > value, a))

Upvotes: 0

Views: 863

Answers (2)

DSM
DSM

Reputation: 353229

You could use np.where:

>>> edge = np.array(EDGE) 
>>> edge[edge > 0].min()
0.5
>>> np.where(edge == edge[edge > 0].min())
(array([1, 2]), array([0, 1]))

which gives the x coordinates and the y coordinates which hit the minimum value separately. If you want to combine them, there are lots of ways, e.g.

>>> np.array(np.where(edge == edge[edge > 0].min())).T
array([[1, 0],
       [2, 1]])

A few asides: from numpy import * is a bad habit because that replaces some built-in functions with numpy's versions which work differently, and in some cases have the opposite results; ALLCAPS variable names are usually only given to constants; and your

 EDGE = array(zeros((NUM_NODE, NUM_NODE)))

line doesn't do anything, because your EDGE = [[ 0., ... etc line immediately makes a new list and binds EDGE to it instead. You made an array and threw it away. There's also no need to call array here; zeros already returns an array.

Upvotes: 3

utdemir
utdemir

Reputation: 27226

numpy.ndenumerate will enumerate over the array(by the way, you shouldn't lose position information with reshaping).

In [43]: a = array(EDGE)

In [44]: a
Out[44]: 
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.5       ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 1.        ,  0.5       ,  0.        ,  0.        ,  0.        ],
       [ 1.41421356,  1.11803399,  1.        ,  0.        ,  0.        ],
       [ 1.        ,  1.11803399,  1.41421356,  1.        ,  0.        ]])

In [45]: min((i for i in ndenumerate(a) if i[1] > 0), key=lambda i: i[1])
Out[45]: ((1, 0), 0.5)

Or you can do it with the old way if you want every occurence:

In [11]: m, ms = float("inf"), []

In [12]: for pos, i in ndenumerate(a):
   ....:     if not i: continue
   ....:     if i < m: 
   ....:         m, ms = i, [pos]
   ....:     elif i == m:
   ....:         ms.append(pos)
   ....:         

In [13]: ms
Out[13]: [(1, 0), (2, 1)]

Upvotes: 2

Related Questions