maschu
maschu

Reputation: 1375

How to find nearest value that is greater in numpy array?

I would like to obtain the index of the nearest value in a numpy array which is greater than my search value. Example: findNearestAbove(np.array([0.,1.,1.4,2.]), 1.5) should return 3 (the index of 2.).

I know that I can get the nearest index with np.abs(a-value).argmin(), and I found out that min(a[np.where(a-value >= 0.)[0]]) returns the desired array value. Hence, np.where(a == min(a[np.where(a-value >= 0.)[0]]))[0] would probably give me the desired index. However, this looks rather convoluted, and I fear that it might break in the case of multi-dimensional arrays. Any suggestions how to improve this?

Upvotes: 7

Views: 11074

Answers (4)

user6565699
user6565699

Reputation:

Here's a solution which worked for me pretty nicely when finding the value and index of the nearest but greater than number in an array (no promises in terms of speed, etc.):

def findNearestGreaterThan(searchVal, inputData):
    diff = inputData - searchVal
    diff[diff<0] = np.inf
    idx = diff.argmin()
    return idx, inputData[idx]

It's easily adapted for nearest but less than, too:

def findNearestLessThan(searchVal, inputData):
    diff = inputData - searchVal
    diff[diff>0] = -np.inf
    idx = diff.argmax()
    return idx, inputData[idx]

Upvotes: 0

JoshAdel
JoshAdel

Reputation: 68732

I believe you can use np.searchsorted for this:

In [15]: np.searchsorted(a,[1.5,],side='right')[0]
Out[15]: 3

assuming a is in ascending order.

This method also won't work for multi-dimensional arrays, but I'm not sure exactly how that use case would work in terms of the expected output. If you could give an example of what you imagine, I might be able to adapt this to that purpose.

Note: you could also use np.digitize for this purpose, although it executes a linear rather than a binary search, so for certain input sizes, it can be a lot slower than searchsorted and requires that a be monotonic:

In [25]: np.digitize([1.5,], a, right=True)[0]
Out[25]: 3

Upvotes: 10

Akavall
Akavall

Reputation: 86326

Here is one way (I am assuming that by nearest you mean in terms of value not location)

import numpy as np

def find_nearest_above(my_array, target):
    diff = my_array - target
    mask = np.ma.less_equal(diff, 0)
    # We need to mask the negative differences and zero
    # since we are looking for values above
    if np.all(mask):
        return None # returns None if target is greater than any value
    masked_diff = np.ma.masked_array(diff, mask)
    return masked_diff.argmin()

Result:

>>> find_nearest_above(np.array([0.,1.,1.4,2.]), 1.5)
3
>>> find_nearest_above(np.array([0.,1.,1.4,-2.]), -1.5)
0
>>> find_nearest_above(np.array([0., 1, 1.4, 2]), 3)
>>> 

Upvotes: 7

kirelagin
kirelagin

Reputation: 13626

Here is the right way to do this:

>>> def argfind(array, predicate):
...     for i in xrange(array.shape[0]):
...         if predicate(array[i]):
...             return i
...     return False
...
>>> def find_nearest_above(array, value):
...     return argfind(array, lambda x: x > value)
...
>>> find_nearest_above(np.array([0.,1.,1.4,2.]), 1.5)
  > 3

The point here is that if a matching value exists, you'll get the answer when this value is met. Other methods (includeing your own, proposed in the question) will inspect the whole array, which is a waste of time.

Upvotes: -3

Related Questions