m Smallest values from upper triangular matrix with their indices as a list of tuples
For an Inf
filled array -
r,c = np.unravel_index(a.ravel().argsort()[:4], a.shape)out = zip(r,c,a[r,c])
For performance, consider using np.argpartition
. So, replace a.ravel().argsort()[:4]
with np.argpartition(a.ravel(), range(4))[:4]
.
Sample run -
In [285]: aOut[285]: array([[ inf, 1., 3., 2., 1.], [ inf, inf, 2., 3., 2.], [ inf, inf, inf, 5., 4.], [ inf, inf, inf, inf, 1.], [ inf, inf, inf, inf, inf]])In [286]: outOut[286]: [(0, 1, 1.0), (0, 4, 1.0), (3, 4, 1.0), (0, 3, 2.0)]
For a generic case -
R,C = np.triu_indices(a.shape[1],1)idx = a[R,C].argsort()[:4]r,c = R[idx], C[idx]out = zip(r,c,a[r,c])
Sample run -
In [351]: aOut[351]: array([[ 68., 67., 81., 23., 16.], [ 84., 83., 20., 66., 48.], [ 58., 72., 98., 63., 30.], [ 61., 40., 1., 86., 22.], [ 29., 95., 38., 22., 95.]])In [352]: outOut[352]: [(0, 4, 16.0), (1, 2, 20.0), (3, 4, 22.0), (0, 3, 23.0)]
For performance, consider using np.argpartition
. So, replace a[R,C].argsort()[:4]
with np.argpartition(a[R,C], range(4))[:4]
.
Something like this works:
import numpy as npa = np.random.rand(4,4)tuples = [(ix,iy, a[ix,iy]) for ix, row in enumerate(a) for iy, i in enumerate(row)]sorted(tuples,key=lambda x: x[2])[:10]
Where k=10 ([:10]
) from your question.
If you only want the upper triangular elements you can add a condition to the list comprehension:
a = np.random.rand(4,4)tuples = [(ix,iy, a[ix,iy]) for ix, row in enumerate(a) for iy, i in enumerate(row) if ix<=iy]sorted(tuples,key=lambda x: x[2])
If my np.array() is n I could get the n smallest values from it by flattening it (with *np.ndenumerate()), and using the heapq module's .heapify() and .smallest() methods like so:
#!pythonflattened = [(y,x) for x,y in np.ndenumerate(n)]# tuples reversed for natural sorting on values rather than co-ordsheapq.heapify(flattened)results = heapq.nsmallest(4, flattened)
But this will use plenty of extra memory and will extract the data and co-ordinates out of Numpy's efficient arrays into Python's native lists. So there's probably much better ways to do it more natively in Python.