Find the indices of the two largest and two smallest values in a matrix in python

Viewed 49

I am attempting to find the indices of the two smallest and the two largest values in python:

I have

import sklearn
euclidean_matrix=sklearn.metrics.pairwise_distances(H10.T,metric='euclidean')

max_index =np.where(euclidean_matrix==np.max(euclidean_matrix[np.nonzero(euclidean_matrix)]))

min_index=np.where(euclidean_matrix==np.min(euclidean_matrix[np.nonzero(euclidean_matrix)]))

min_index
max_index

I get the following output

(array([158, 272]), array([272, 158]))
(array([ 31, 150]), array([150,  31]))

the above code only returns the indices of the absolute smallest and the absolute largest values of the matrix, I would like to find the indices of the next smallest value and the indices of the next largest value. How can I do this? Ideally I would like to return the indices of the 2 largest values of the matrix and the indices of the two smallest values of the matrix. How can I do this?

1 Answers

I can think of a couple ways of doing this. Some of these depend on how much data you need to search through.

A couple of caveats: You will have to decide what to do when there are 1, 2, 3 elements only Or if all the same value, do you want min, max, etc to be identical? What if there are multiple items in max or min or min2, max2? which should be selected?

  1. run min then remove that element run min on the rest. run max then remove that element and run on the rest (note that this is on the original and not the one with min removed). This is the least efficient method since it requires searching 4 times and copying twice. (Actually 8 times because we find the min/max then find the index.) Something like the in the pseudo code.
PSEUDO CODE:

max_index = np.where(euclidean_matrix==np.max(euclidean_matrix[np.nonzero(euclidean_matrix)]))
tmp_euclidean_matrix = euclidean_matrix #make sure this is a deepcopy
tmp_euclidean_matrix.remove(max_index)  #syntax might not be right?
max_index2 = np.where(tmp_euclidean_matrix==np.max(tmp_euclidean_matrix[np.nonzero(tmp_euclidean_matrix)]))

min_index = np.where(euclidean_matrix==np.min(euclidean_matrix[np.nonzero(euclidean_matrix)]))
tmp_euclidean_matrix = euclidean_matrix #make sure this is a deepcopy
tmp_euclidean_matrix.remove(min_index)  #syntax might not be right?
min_index2 = np.where(tmp_euclidean_matrix==np.min(tmp_euclidean_matrix[np.nonzero(tmp_euclidean_matrix)]))
  1. Sort the data (if you need it sorted anyway this is a good option) then just grab two smallest and largest. This isn't great unless you needed it sorted anyway because of many copies and comparisons to sort.
PSEUDO CODE:

euclidean_matrix.sort()
min_index  = 0
min_index2 = 1
max_index  = len(euclidean_matrix) - 1
max_index2 = max_index - 1
  1. Best option would be to roll your own search function to run on the data, this would be most efficient because you would go through the data only once to collect them.

This is just a simple iterative approach, other algorithms may be more efficient. You will want to validate this works though.

PSEUDO CODE:
def minmax2(array):
    """ returns (minimum, second minimum, second maximum, maximum)
    """
    if len(array) == 0:
        raise Exception('Empty List')
    elif len(array) == 1:
        #special case only 1 element need at least 2 to have different 
        minimum  = 0
        minimum2 = 0
        maximum2 = 0
        maximum  = 0
    else:
        minimum  = 0
        minimum2 = 1
        maximum2 = 1
        maximum  = 0
        for i in range(1, len(array)):
           if array[i] <= array[minimum]:
               # a new minimum (or tie) will shift the other minimum
               minimum2 = minimum 
               minimum  = i
           elif array[i] < array[minimum2]:
               minimum2 = i
           elif array[i] >= array[maximum]:
               # a new maximum (or tie) will shift the second maximum
               maximum2 = maximum
               maximum = i
           elif array[i] > array[maximum2]:
               maximum2 = i
    return (minimum, minimum2, maximum2, maximum)

edit: Added pseudo code

Related