检查浮点数是否接近于存储在数组中的任何浮点数

12

我需要检查给定的浮点数是否与浮点数数组中的任何一个浮点数接近(在给定的容差范围内),请帮忙翻译。

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)

有没有一种简单的方法来实现这个?类似于if a in arr_f:,但允许一定差异性?


添加

所谓的“允许差异性”是指以下意义:

for i in arr_f:
    if abs(a - i) <= t:
        print 'float a is in arr_f within tolerance t'
        break

你是在寻找一个简单易写易维护的解决方案,还是需要采用复杂的方法来实现更好的性能? - Aprillion
我认为numpy.isclose(a,arr_f, atol=t)是最好的答案,如下所示! - Mazdak
@Kasra,为什么这比(abs(arr_f - a) < t).any()更好? - Yoel
@Yoel,你的答案也很好,但其他人使用了numpy方法!它的优点在于此! - Mazdak
@Kasra,我认为这并不相关,特别是因为这种方法更快,但我猜每个人都有自己的做法,哈哈 :-) - Yoel
1
通常(但不一定是在您的情况下),您需要一个相对误差,类似于 abs(arr_f - a) / max(abs(arr_f), abs(a)),以及一个公差值,可能为 1E-51E-6。我预计numpy也提供了这样的机制;isclose()方法可能会提供它 - 实际上,您可以使用rtol=t来指定相对公差,而不是建议的atol=t - Jonathan Leffler
3个回答

22

那么使用 np.isclose 如何?

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

np.isclose函数会逐元素比较两个对象的值,判断它们是否在指定的公差范围内(由关键字参数atol指定,即两个元素之间的绝对差)。该函数返回一个布尔类型的数组。


这个答案的问题在于它在执行any操作之前进行了所有比较,而普通的any在遇到第一个False时就会停止。因此,使用any(np.isclose(ar, a, atol=0.01) for ar in arr_f)代替似乎更节省内存。 - Dr_Zaszuś
@Dr_Zaszuś 如果在内存非常有限的机器上工作,这可能是个问题。否则,即使使用非常大的数组,构建额外的布尔数组来减少也几乎从不会出现问题。在数组足够大以威胁到程序员可用内存限制的情况下,any(np.isclose(ar, a, atol=0.01) for ar in arr_f) 可能会变得无法接受的缓慢。当 arr_f 拥有 100 万个值且 a 不接近其中任何一个时,该代码需要多长时间?对我来说是 27 秒(而使用 isclose/any 仅需 4 毫秒)! - Alex Riley

8
如果你只对True/False的结果感兴趣,那么这应该可以实现:
In [1]: (abs(arr_f - a) < t).any()
Out[1]: True

说明:对于abs(arr_f - a) < t,返回一个布尔数组,然后调用any()以查找其中是否有任何一个值为True

编辑 - 比较这种方法和其他答案中建议的方法,发现这种方法略微更快:

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

另一种解决方案是返回相关索引,代码如下:
In [5]: np.where(abs(arr_f - a) < t)[0]
Out[5]: array([27, 28])

这意味着arr_f中索引27和28的值在所需范围内,确实如此:
In [9]: arr_f[27]
Out[9]: 0.26600000000000001

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

使用这种方法还可以生成一个True/False结果:
In [11]: np.where(abs(arr_f - a) < t)[0].any()
Out[11]: True

非常好的答案。我正在寻找一些更“出人意料”的东西,已经打包到Python或NumPy中,但我一定会记住用这种方式获得更好的性能。干杯。 - Gabriel

-1
[temp] = np.where(np.int32((sliceArray - aimFloat) > 0) == 1)

temp[0] 是答案。 sliceArray 已排序!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接