Python 在numpy中查找浮点数组的唯一元素(使用增量值进行比较)

Python 在numpy中查找浮点数组的唯一元素(使用增量值进行比较),python,numpy,floating-point,Python,Numpy,Floating Point,我在numpy中有一个浮点值的ndarray,我想找到这个数组的唯一值。当然,这有问题,因为浮点精度…所以我希望能够设置一个增量值,以便在计算出哪些元素是唯一的时用于比较 有办法做到这一点吗?目前,我只是在做: unique(array) 这让我觉得: array([ -Inf, 0.62962963, 0.62962963, 0.62962963, 0.62962963, 0.62962963]) 其中,看起来相同的值(显示的小数位数)明显略有不同。类似的情况如

我在numpy中有一个浮点值的
ndarray
,我想找到这个数组的唯一值。当然,这有问题,因为浮点精度…所以我希望能够设置一个增量值,以便在计算出哪些元素是唯一的时用于比较

有办法做到这一点吗?目前,我只是在做:

unique(array)
这让我觉得:

array([       -Inf,  0.62962963,  0.62962963,  0.62962963,  0.62962963,
    0.62962963])

其中,看起来相同的值(显示的小数位数)明显略有不同。

类似的情况如何

np.unique1d(np.floor(1e7*x)/1e7)

其中,
x
是您的原始数组。

另一种可能是四舍五入到最接近的理想公差:

np.unique(a.round(decimals=4))
其中
a
是原始数组

编辑:请注意,根据我的计时,我的解决方案和@unutbu的速度几乎相同(我的可能快5%),因此两者都是一个好的解决方案

编辑#2:这是为了解决保罗的担忧。这肯定是较慢的,可能有一些优化可以做,但我张贴它是为了证明战略:

def eclose(a,b,rtol=1.0000000000000001e-05, atol=1e-08):
    return np.abs(a - b) <= (atol + rtol * np.abs(b))

x = np.array([6.4,6.500000001, 6.5,6.51])
y = x.flat.copy()
y.sort()
ci = 0

U = np.empty((0,),dtype=y.dtype)

while ci < y.size:
    ii = eclose(y[ci],y)
    mi = np.max(ii.nonzero())
    U = np.concatenate((U,[y[mi]])) 
    ci = mi + 1

print U
def eclose(a,b,rtol=1.0000000000000001e-05,atol=1e-08):
返回np。在某些情况下,abs(a-b)是否
floor
round
都不符合OP的要求

np.floor([5.99999999, 6.0]) # array([ 5.,  6.])
np.round([6.50000001, 6.5], 0) #array([ 7.,  6.])
我会这样做(这可能不是最优的(而且肯定比其他答案慢)),比如:

import numpy as np
TOL = 1.0e-3
a = np.random.random((10,10))
i = np.argsort(a.flat)
d = np.append(True, np.diff(a.flat[i]))
result = a.flat[i[d>TOL]]
当然,此方法将排除在任何其他值公差范围内的一系列值中的所有值(最大值除外),这意味着您可能无法在数组中找到任何唯一值,如果所有值都非常接近,即使最大最小值大于公差

这里的算法基本相同,但更容易理解,而且应该更快,因为它避免了索引步骤:

a = np.random.random((10,))
b = a.copy()
b.sort()
d = np.append(True, np.diff(b))
result = b[d>TOL]

OP可能还想研究
scipy.cluster
(对于此方法的奇特版本)或
numpy.digitalize
(对于其他两种方法的奇特版本)

我刚刚注意到,接受的答案不起作用。例如,本案例:

a = 1-np.random.random(20)*0.05
<20 uniformly chosen values between 0.95 and 1.0>
np.sort(a)
>>>> array([ 0.9514548 ,  0.95172218,  0.95454535,  0.95482343,  0.95599525,
             0.95997008,  0.96385762,  0.96679186,  0.96873524,  0.97016127,
             0.97377579,  0.98407259,  0.98490461,  0.98964753,  0.9896733 ,
             0.99199411,  0.99261766,  0.99317258,  0.99420183,  0.99730928])
TOL = 0.01
这仅仅是因为排序后的输入数组的值没有足够的间距至少为“TOL”appart,而正确的结果应该是:

>>>> array([ 0.9514548,  0.96385762,  0.97016127,  0.98407259,
             0.99199411])
(尽管这取决于您如何决定在“TOL”中采用哪个值)

您应该使用整数不会受到这种机器精度影响的事实:

np.unique(np.floor(a/TOL).astype(int))*TOL
>>>> array([ 0.95,  0.96,  0.97,  0.98,  0.99])
其执行速度比建议的解决方案快5倍(根据%timeit)

请注意,“.astype(int)”是可选的,尽管删除它会使性能降低1.5倍,因为从int数组中提取unique要快得多

您可能希望在uniques的结果中添加一半的“TOL”,以补偿地板效果:

(np.unique(np.floor(a/TOL).astype(int))+0.5)*TOL
>>>> array([ 0.955,  0.965,  0.975,  0.985,  0.995])

请注意,
np.unique1d
在1.4版中已被弃用,并将在1.5版中删除。@JoshAdel:谢谢提醒。实际上,我可能对这些版本有点错误,但它肯定不在最新的文档中。
np.unique
建议替换它。+1:舍入将正确地统一fl所在的一些转角情况ooring可能会失败,而且速度更快。原则上我喜欢这个想法,但最后一个警告似乎与OP的要求有更大的分歧。@JoshAdel:我必须假设OP的数据是自然聚集的(通过示例,它们似乎紧紧围绕着某些值聚集)或者这个请求没有多大意义。假设在任意阈值下数字化OP的数据(这可能会分裂集群)似乎弊大于利。有用的是能够进行定点精度截断。我想有一种方法可以正确解决这个问题(尽管速度较慢),但我要晚些时候才能发布。
(np.unique(np.floor(a/TOL).astype(int))+0.5)*TOL
>>>> array([ 0.955,  0.965,  0.975,  0.985,  0.995])