Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find all indexes of a numpy array closest to a value

In a numpy array the indexes of all values closest to a given constant are needed. The background is digital signal processing. The array holds the magnitude function of a filter (np.abs(np.fft.rfft(h))) and certain frequencies (=indexes) are searched where the magnitude is e.g. 0.5 or in another case 0. Most the time the value in question is not included exactly in the sequence. The index of the closed value should be found in this.

So far I came up with the following method where I look at the change in sign of the difference between the sequence and the constant. However, this only works for sequences which are monotonically increasing or decresasing at the points in question. It also is off by 1 sometimes.

def findvalue(seq, value):
    diffseq = seq - value
    signseq = np.sign(diffseq)
    signseq[signseq == 0] = 1
    return np.where(np.diff(signseq))[0]

I'm wondering if there is a better solution for this. It is only for 1D real float arrays and the requirement of the computation efficiency is not so high in my case.

As a numerical example the following code should return [8, 41]. I replaced the filter magnitude response with a half-wave for simplicity here.

f=np.sin(np.linspace(0, np.pi))
findvalue(f, 0.5)

Similar questions I found are as following but they do only return the first or second index:
Find the second closest index to value
Find nearest value in numpy array

like image 959
Martin Scharrer Avatar asked Oct 22 '25 15:10

Martin Scharrer


1 Answers

I think you have two choices here. One is to make some assumptions on the shape and look for the zero-crossings of the difference between the seq and your val (as @ColonelFazackerley did in their answer). The other one is to state up to which relative tolerance you want to consider the value close enough.

In the latter case you can use numpy.isclose:

import numpy as np

def findvalue(seq, val, rtol=0.05):    # value that works for your example
    return np.where(np.isclose(seq, val, rtol=rtol))[0]

Example:

x = np.sin(np.linspace(0, np.pi))
print(findvalue(x, 0.5))
# array([ 8, 41])

This has the disadvantage that it depends on the value of rtol. Set it too large (0.1 for this example) and you get multiple values close to the crossing, set it too low and you don't get any.

like image 112
Graipher Avatar answered Oct 25 '25 04:10

Graipher



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!