find indices of maximum value in matrix (python) - python

I want to find the indices[i,j] of the maximum value in a 2d numpy array:
a = numpy.array([[1,2,3],[4,3,1]])
I tried to do it using numpy.argsort() but it returns an array because it can be done along an axis only.
One solution can be by comparing elements at all indices (along both axes) returned by argsort using for loops, but it seems kind of complicated for this. Maybe there is a simple solution?

You want np.unravel_index. The np.argmax will return an index as if the flattened version of array is traversed. The unravel_index will give you the N-D indices.
a = np.random.randint(0, 10, (4,4))
ind = np.unravel_index(np.argmax(a, axis=None), a.shape) # returns a tuple

Maybe this can return what you are looking for? It returns the index of the max (
max_xy = np.where(a == a.max() )
Zip the result to get the index as list of tuples:
zip(max_xy[0], max_xy[1]) #=> [(1, 0)]
In case of more than one max: a = np.array([[4,2,3],[4,3,4]]), it returns #=> [(0, 0), (1, 0), (1, 2)]
To return as a tuple the first maximum found, just fetch the first element of the array:
zip(max_xy[0], max_xy[1])[0] #=> (0, 0)

Related

How to get the index of np.maximum?

I know np.maximum computes the element-wise maximum, e.g.
>>> b = np.array([3, 6, 1])
>>> c = np.array([4, 2, 9])
>>> np.maximum(b, c)
array([4, 6, 9])
But is there any way to get the index as well? like in the above example, I also want something like this where each tuple denote (which array, index), it could be tuple or dictionary or something else. And also it would be great if it could work on 3d array, like the input two arrays are 3d arrays.
array([(1, 0), (0, 1), (1, 2)])
You could stack the two 1d-arrays to get a 2d-array and use argmax:
arr = np.vstack((b, c))
indices = np.argmax(arr, axis=0)
This will give you a list of integers, not tuples, but as you know that you compare per column, the last elements of each tuple are unnecessary anyway. They are just ascending integers starting at 0. If you really need them, though, you could just add
indices = list(zip(indices, range(len(b)))

find two closest values in numpy ndarray

i have a numpy ndarray which looks like this
np.array(
[[40.26164428, 63.50590524, 58.30951895],
[50.99019514, 69.0651866 , 60.44005295],
[20.24845673, 14.31782106, 58.52349955],
[54.58937626, 53.03772242, 21.09502311],
[56.75385449, 57.5847202 , 1.41421356]])
(NOTE: the arrays i generate are always in different shapes ( the shape of this array is (5, 3) but it can be (2, 2) (4, 1)... ),
so this isn't a 3D coordinates array, it just generated like that)
What i need is to find the two closest values of the generated array and return their indices, in this case the values are 58.30951895 and 58.52349955, which should return the coordinates [0, 2] and [2, 2]
I've tried to use cKDtree but this isn't a coordinate array so that doesn't work in this case, how should i do this?
I'm going to be embarrassed when someone points out a one-liner, but here's a way to do it.
I flatten the array, then sort it, then find the deltas between each element. Find the minimum delta. Now, from the sorted array, I know the values of the two closest elements. argwhere then gives me the coordinates.
import numpy as np
data = np.array(
[[40.26164428, 63.50590524, 58.30951895],
[50.99019514, 69.0651866 , 60.44005295],
[20.24845673, 14.31782106, 58.52349955],
[54.58937626, 53.03772242, 21.09502311],
[56.75385449, 57.5847202 , 1.41421356]])
order = np.sort(data.reshape(-1))
delta = np.diff(order)
am = np.argmin(delta)
print( np.argwhere(data == order[am]))
print( np.argwhere(data == order[am+1]))
Output:
C:\tmp>python x.py
[[0 2]]
[[2 2]]
If I understand it correctly their position in the array is irrelevant, so in that case is simple, put the numbers in a list in a way that it remember their original position, then sorted it and find the lowest difference between two consecutive elements
>>> import itertools
>>> def pairwise(iterable):
a,b = itertools.tee(iterable)
next(b,None)
return zip(a,b)
>>> data=[[40.26164428, 63.50590524, 58.30951895],
[50.99019514, 69.0651866, 60.44005295],
[20.24845673, 14.31782106, 58.52349955],
[54.58937626, 53.03772242, 21.09502311],
[56.75385449, 57.5847202, 1.41421356]]
>>> linear=[ (value,x,y) for x,row in enumerate(data) for y,value in enumerate(row)]
>>> linear.sort(key=lambda x:x[0])
>>> min(pairwise(linear),key=lambda pair: abs(pair[0][0]-pair[1][0]))
((58.30951895, 0, 2), (58.52349955, 2, 2))
>>>

Numpy max over only the first element of an array of pairs

I have a multidimensional numpy array consisting of tuples like below:
[[(0.56, 1),(0.25, 4), ...],[(0.11, 9), ...], ...]
The second element of each tuple is an index reference. I want to extract the tuple with the highest first value per row. Is there a way to achieve this with numpy max?
One thing I tried is playing around with the axis parameter like below:
np.max(my_array, axis=0)
But this shuffles around the pairs with the index reference not preserved. E.g. the first row in the above example would show something like [(0.56,4), ...] whereas I want it to show [(0.56,1), ...]
In plain python, you could use :
[max(row, key=lambda row: row[0]) for row in array]
Don't use tuples in numpy arrays. Convert it all to a numpy array with the last dimension being 2:
>>> a = np.array([[(0.56, 1), (0.25, 4)],[(0.11, 9), (0.19, 5)]])
>>> a.shape
(2, 2, 2)
Then:
>>> highest_val_per_row = np.argmax(a[:,:,0], axis=1)
>>> a[np.arange(a.shape[0]), highest_val_per_row]
array([[0.56, 1. ],
[0.19, 5. ]])
You can try something linke this:
lst = [[(0.56, 1),(0.25, 4)],[(0.11, 9), (0.25, 4)]]
for e in lst:
print(max(e))
However, i think there are more efficient ways of doing it.

Python slice without dimension

Why slicing one row or column produces "dimensionless array"? For example:
import numpy as np
arr = np.zeros((10,10))
print arr.shape
# (10, 10)
But when I want only one column or row, I get
print arr[:,0].shape
# (10,)
print arr[0,:].shape
# (10,)
instead of
print arr[:,0].shape
# (10, 1)
print arr[0,:].shape
# (1, 10)
For you example you getting np.arrays from 0 column and from 0 row which are numpy.array with 1 dimension. You could do a little trick with slicing like that:
In [103]: arr[:1,:].shape
Out[103]: (1, 10)
In [104]: arr[:,:1].shape
Out[104]: (10, 1)
EDIT
From docs:
An integer, i, returns the same values as i:i+1 except the dimensionality of the returned object is reduced by 1. In particular, a selection tuple with the p-th element an integer (and all other entries :) returns the corresponding sub-array with dimension N - 1. If N = 1 then the returned object is an array scalar. These objects are explained in Scalars.

Sort a list then give the indexes of the elements in their original order

I have an array of n numbers, say [1,4,6,2,3]. The sorted array is [1,2,3,4,6], and the indexes of these numbers in the old array are 0, 3, 4, 1, and 2. What is the best way, given an array of n numbers, to find this array of indexes?
My idea is to run order statistics for each element. However, since I have to rewrite this function many times (in contest), I'm wondering if there's a short way to do this.
>>> a = [1,4,6,2,3]
>>> [b[0] for b in sorted(enumerate(a),key=lambda i:i[1])]
[0, 3, 4, 1, 2]
Explanation:
enumerate(a) returns an enumeration over tuples consisting of the indexes and values in the original list: [(0, 1), (1, 4), (2, 6), (3, 2), (4, 3)]
Then sorted with a key of lambda i:i[1] sorts based on the original values (item 1 of each tuple).
Finally, the list comprehension [b[0] for b in ...] returns the original indexes (item 0 of each tuple).
Using numpy arrays instead of lists may be beneficial if you are doing a lot of statistics on the data. If you choose to do so, this would work:
import numpy as np
a = np.array( [1,4,6,2,3] )
b = np.argsort( a )
argsort() can operate on lists as well, but I believe that in this case it simply copies the data into an array first.
Here is another way:
>>> sorted(xrange(len(a)), key=lambda ix: a[ix])
[0, 3, 4, 1, 2]
This approach sorts not the original list, but its indices (created with xrange), using the original list as the sort keys.
This should do the trick:
from operator import itemgetter
indices = zip(*sorted(enumerate(my_list), key=itemgetter(1)))[0]
The long way instead of using list comprehension for beginner like me
a = [1,4,6,2,3]
b = enumerate(a)
c = sorted(b, key = lambda i:i[1])
d = []
for e in c:
d.append(e[0])
print(d)

Categories

Resources