Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

numpy.argmin for elements greater than a threshold

I'm interested in getting the location of the minimum value in an 1-d NumPy array that meets a certain condition (in my case, a medium threshold). For example:

import numpy as np

limit = 3
a = np.array([1, 2, 4, 5, 2, 5, 3, 6, 7, 9, 10])

I'd like to effectively mask all numbers in a that are under the limit, such that the result of np.argmin would be 6. Is there a computationally cheap way to mask values that don't meet a condition and then apply np.argmin?

like image 367
triphook Avatar asked Jun 22 '16 16:06

triphook


People also ask

What does argmin do in numpy?

The numpy. argmin() method returns indices of the min element of the array in a particular axis. Return : Array of indices into the array with same shape as array.

What does Argmax in numpy do?

The numpy. argmax() function returns indices of the max element of the array in a particular axis.

How do you find min and max in numpy?

numpy. amax() will find the max value in an array, and numpy. amin() does the same for the min value.

How do I get indices of N minimum values in a numpy array?

To get the indices of N miniumum values in NumPy in an optimal way, use the argpartition(~) method.


2 Answers

This can simply be accomplished using numpy's MaskedArray

import numpy as np

limit = 3
a = np.array([1, 2, 4, 5, 2, 5, 3, 6, 7, 9, 10])
b = np.ma.MaskedArray(a, a<limit)
np.ma.argmin(b)    # == 6
like image 186
MaxPowers Avatar answered Sep 26 '22 19:09

MaxPowers


You could store the valid indices and use those for both selecting the valid elements from a and also indexing into with the argmin() among the selected elements to get the final index output. Thus, the implementation would look something like this -

valid_idx = np.where(a >= limit)[0]
out = valid_idx[a[valid_idx].argmin()]

Sample run -

In [32]: limit = 3
    ...: a = np.array([1, 2, 4, 5, 2, 5, 3, 6, 7, 9, 10])
    ...: 

In [33]: valid_idx = np.where(a >= limit)[0]

In [34]: valid_idx[a[valid_idx].argmin()]
Out[34]: 6

Runtime test -

For performance benchmarking, in this section I am comparing the other solution based on masked array against a regular array based solution as proposed earlier in this post for various datasizes.

def masked_argmin(a,limit): # Defining func for regular array based soln
    valid_idx = np.where(a >= limit)[0]
    return valid_idx[a[valid_idx].argmin()]

In [52]: # Inputs
    ...: a = np.random.randint(0,1000,(10000))
    ...: limit = 500
    ...: 

In [53]: %timeit np.argmin(np.ma.MaskedArray(a, a<limit))
1000 loops, best of 3: 233 µs per loop

In [54]: %timeit masked_argmin(a,limit)
10000 loops, best of 3: 101 µs per loop

In [55]: # Inputs
    ...: a = np.random.randint(0,1000,(100000))
    ...: limit = 500
    ...: 

In [56]: %timeit np.argmin(np.ma.MaskedArray(a, a<limit))
1000 loops, best of 3: 1.73 ms per loop

In [57]: %timeit masked_argmin(a,limit)
1000 loops, best of 3: 1.03 ms per loop
like image 24
Divakar Avatar answered Sep 24 '22 19:09

Divakar