Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if float is close to any float stored in array

I need to check if a given float is close, within a given tolerance, to any float in an array of floats.

import numpy as np

# My float
a = 0.27
# The tolerance
t = 0.01
# Array of floats
arr_f = np.arange(0.05, 0.75, 0.008)

Is there a simple way to do this? Something like if a in arr_f: but allowing for some tolerance in the difference?


Add

By "allow tolerance" I mean it in the following sense:

for i in arr_f:
    if abs(a - i) <= t:
        print 'float a is in arr_f within tolerance t'
        break
like image 940
Gabriel Avatar asked Sep 21 '14 19:09

Gabriel


2 Answers

How about using np.isclose?

>>> np.isclose(arr_f, a, atol=0.01).any()
True

np.isclose compares two objects element-wise to see if the values are within a given tolerance (here specified by the keyword argument atol which is the absolute difference between two elements). The function returns a boolean array.

like image 145
Alex Riley Avatar answered Nov 12 '22 18:11

Alex Riley


If you're only interested in a True/False result, then this should work:

In [1]: (abs(arr_f - a) < t).any()
Out[1]: True

Explanation: abs(arr_f - a) < t returns a boolean array on which any() is invoked in order to find out whether any of its values is True.

EDIT - Comparing this approach and the one suggested in the other answer reveals that this one is slightly faster:

In [37]: arr_f = np.arange(0.05, 0.75, 0.008)

In [38]: timeit (abs(arr_f - a) < t).any()
100000 loops, best of 3: 11.5 µs per loop

In [39]: timeit np.isclose(arr_f, a, atol=t).any()
10000 loops, best of 3: 44.7 µs per loop

In [40]: arr_f = np.arange(0.05, 1000000, 0.008)

In [41]: timeit (abs(arr_f - a) < t).any()
1 loops, best of 3: 646 ms per loop

In [42]: timeit np.isclose(arr_f, a, atol=t).any()
1 loops, best of 3: 802 ms per loop

An alternative solution that also returns the relevant indices is as follows:

In [5]: np.where(abs(arr_f - a) < t)[0]
Out[5]: array([27, 28])

This means that the values residing in indices 27 and 28 of arr_f are within the desired range, and indeed:

In [9]: arr_f[27]
Out[9]: 0.26600000000000001

In [10]: arr_f[28]
Out[10]: 0.27400000000000002

Using this approach can also generate a True/False result:

In [11]: np.where(abs(arr_f - a) < t)[0].any()
Out[11]: True
like image 8
Yoel Avatar answered Nov 12 '22 18:11

Yoel