Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find index of first element in array close to float within tolerance, with numpy

I need to find the index of the first element in an array, that is close to a float within a given tolerance.

I can do this with a for block:

import numpy as np

# Define array of floats
a = np.random.uniform(0., 10., 10.)

# Float to search, and tolerance.
val, tol = 6.87, 0.1

for i, _ in enumerate(a):
    if np.isclose(_, val, tol):
        print('Index is: {}'.format(i))
        break

but I was wondering if there might be a one-liner solution using some numpy function.

Notice that I'm interested in the index of the first element that is close to val, no matter that there might be closer elements further down the a array. The solutions I've found are interested in the index of the nearest value, no matter where it is located within the array.

like image 218
Gabriel Avatar asked Dec 03 '22 23:12

Gabriel


2 Answers

Here's a one-liner:

Index = next(i for i, _ in enumerate(a) if np.isclose(_, val, tol))

What is this?

The code in parentheses is a generator expression and next returns (you guessed it!) the next (in this case, the first) value the generator will produce. If there'll be no next value, a StopIteration exception will be raised.

Advantages

  1. It isn't memory-consuming as it doesn't need to compute all the possible values and store them.
  2. It's fast as it doesn't continue looping through the array if the needed value is already found.
  3. It will raise an exception if no value could be found.
  4. It could be easily turned into a one-liner function:

    FirstIndex = lambda a, val, tol: next(i for i, _ in enumerate(a) if np.isclose(_, val, tol))
    
    i = FirstIndex(a, val, tol) # call it
    
like image 75
ForceBru Avatar answered Mar 16 '23 00:03

ForceBru


Here's a vectorized one-liner -

(np.abs(a - val) <= tol).argmax()

Sample step-by-step run -

In [57]: a
Out[57]: array([5, 3, 9, 6, 8, 3, 5, 1])

In [58]: val = 2

In [59]: tol = 2

In [60]: (np.abs(a - val) < tol) # Many might satisfy
Out[60]: array([False,True,False,False,False,True,False,True], dtype=bool)

In [61]: (np.abs(a - val) <= tol).argmax() # Choose the first one with argmax
Out[61]: 1
like image 40
Divakar Avatar answered Mar 16 '23 00:03

Divakar