Reputation: 1375
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
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
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
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
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