Finding the nearest value and return the index of array in Python
Question:
I found this post: Python: finding an element in an array
and it’s about returning the index of an array through matching the values.
On the other hand, what I am thinking of doing is similar but different. I would like to find the nearest value for the target value. For example I am looking for 4.2 but I know in the array there is no 4.2 but I want to return the index of the value 4.1 instead of 4.4.
What would be the fastest way of doing it?
I am thinking of doing it the old way like how I used to do it with Matlab, which is using the array A where I want to get the index from to minus the target value and take the absolute of it, then select the min. Something like this:-
[~,idx] = min(abs(A - target))
That is Matlab code but I am newbie in Python so I am thinking, is there a fast way of doing it in Python?
Thank you so much for your help!
Answers:
The corresponding Numpy code is almost the same, except you use numpy.argmin
to find the minimum index.
idx = numpy.argmin(numpy.abs(A - target))
def finder(myList, target)
diff = ''
index = None
for i,num in enumerate(myList):
if abs(target - num) < diff:
diff = abs(target - num)
index = i
return index
Hope this helps
EDIT:
If you’d like a one-liner, then you might like this better:
min(L, key=lambda x: abs(target-x))
Possible solution:
>>> a = [1.0, 3.2, -2.5, -3.1]
>>> i = -1.5
>>> diff = [(abs(i - x),idx) for (idx,x) in enumerate(a)]
>>> diff
[(2.5, 0), (4.7, 1), (1.0, 2), (1.6, 3)]
>>> diff.sort()
>>> diff
[(1.0, 2), (1.6, 3), (2.5, 0), (4.7, 1)]
You’ll have the index of nearest value in diff[0][1]
This is similar to using bisect_left, but it’ll allow you to pass in an array of targets
def find_closest(A, target):
#A must be sorted
idx = A.searchsorted(target)
idx = np.clip(idx, 1, len(A)-1)
left = A[idx-1]
right = A[idx]
idx -= target - left < right - target
return idx
Some explanation:
First the general case: idx = A.searchsorted(target)
returns an index for each target
such that target
is between A[index - 1]
and A[index]
. I call these left
and right
so we know that left < target <= right
. target - left < right - target
is True
(or 1) when target is closer to left
and False
(or 0) when target is closer to right
.
Now the special case: when target
is less than all the elements of A
, idx = 0
. idx = np.clip(idx, 1, len(A)-1)
replaces all values of idx
< 1 with 1, so idx=1
. In this case left = A[0]
, right = A[1]
and we know that target <= left <= right
. Therefor we know that target - left <= 0
and right - target >= 0
so target - left < right - target
is True
unless target == left == right
and idx - True = 0
.
There is another special case if target
is greater than all the elements of A
, In that case idx = A.searchsorted(target)
and np.clip(idx, 1, len(A)-1)
replaces len(A)
with len(A) - 1
so idx=len(A) -1
and target - left < right - target
ends up False
so idx returns len(A) -1
. I’ll let you work though the logic on your own.
For example:
In [163]: A = np.arange(0, 20.)
In [164]: target = np.array([-2, 100., 2., 2.4, 2.5, 2.6])
In [165]: find_closest(A, target)
Out[165]: array([ 0, 19, 2, 2, 3, 3])
Tested and timed two solutions:
idx = np.searchsorted(sw, sCut)
and
idx = np.argmin(np.abs(sw - sCut))
for computation in a time expensive method. timing was 113s for computation with the second solution, and 132s for computation with the first one.
Well, more than 2 years have gone by and I have found a very simple implementation from this URL in fact: Find nearest value in numpy array
The implementation is:
def getnearpos(array,value):
idx = (np.abs(array-value)).argmin()
return idx
Cheers!!
I found this post: Python: finding an element in an array
and it’s about returning the index of an array through matching the values.
On the other hand, what I am thinking of doing is similar but different. I would like to find the nearest value for the target value. For example I am looking for 4.2 but I know in the array there is no 4.2 but I want to return the index of the value 4.1 instead of 4.4.
What would be the fastest way of doing it?
I am thinking of doing it the old way like how I used to do it with Matlab, which is using the array A where I want to get the index from to minus the target value and take the absolute of it, then select the min. Something like this:-
[~,idx] = min(abs(A - target))
That is Matlab code but I am newbie in Python so I am thinking, is there a fast way of doing it in Python?
Thank you so much for your help!
The corresponding Numpy code is almost the same, except you use numpy.argmin
to find the minimum index.
idx = numpy.argmin(numpy.abs(A - target))
def finder(myList, target)
diff = ''
index = None
for i,num in enumerate(myList):
if abs(target - num) < diff:
diff = abs(target - num)
index = i
return index
Hope this helps
EDIT:
If you’d like a one-liner, then you might like this better:
min(L, key=lambda x: abs(target-x))
Possible solution:
>>> a = [1.0, 3.2, -2.5, -3.1]
>>> i = -1.5
>>> diff = [(abs(i - x),idx) for (idx,x) in enumerate(a)]
>>> diff
[(2.5, 0), (4.7, 1), (1.0, 2), (1.6, 3)]
>>> diff.sort()
>>> diff
[(1.0, 2), (1.6, 3), (2.5, 0), (4.7, 1)]
You’ll have the index of nearest value in diff[0][1]
This is similar to using bisect_left, but it’ll allow you to pass in an array of targets
def find_closest(A, target):
#A must be sorted
idx = A.searchsorted(target)
idx = np.clip(idx, 1, len(A)-1)
left = A[idx-1]
right = A[idx]
idx -= target - left < right - target
return idx
Some explanation:
First the general case: idx = A.searchsorted(target)
returns an index for each target
such that target
is between A[index - 1]
and A[index]
. I call these left
and right
so we know that left < target <= right
. target - left < right - target
is True
(or 1) when target is closer to left
and False
(or 0) when target is closer to right
.
Now the special case: when target
is less than all the elements of A
, idx = 0
. idx = np.clip(idx, 1, len(A)-1)
replaces all values of idx
< 1 with 1, so idx=1
. In this case left = A[0]
, right = A[1]
and we know that target <= left <= right
. Therefor we know that target - left <= 0
and right - target >= 0
so target - left < right - target
is True
unless target == left == right
and idx - True = 0
.
There is another special case if target
is greater than all the elements of A
, In that case idx = A.searchsorted(target)
and np.clip(idx, 1, len(A)-1)
replaces
len(A)
with len(A) - 1
so idx=len(A) -1
and target - left < right - target
ends up False
so idx returns len(A) -1
. I’ll let you work though the logic on your own.
For example:
In [163]: A = np.arange(0, 20.)
In [164]: target = np.array([-2, 100., 2., 2.4, 2.5, 2.6])
In [165]: find_closest(A, target)
Out[165]: array([ 0, 19, 2, 2, 3, 3])
Tested and timed two solutions:
idx = np.searchsorted(sw, sCut)
and
idx = np.argmin(np.abs(sw - sCut))
for computation in a time expensive method. timing was 113s for computation with the second solution, and 132s for computation with the first one.
Well, more than 2 years have gone by and I have found a very simple implementation from this URL in fact: Find nearest value in numpy array
The implementation is:
def getnearpos(array,value):
idx = (np.abs(array-value)).argmin()
return idx
Cheers!!