我对fix
中的floor
和numpy
函数提出了一个简单的问题。
当将大于-1的负数舍入为零时,numpy
将它们正确地舍入为零,但会留下负号。这个负号会干扰我的服装unique_rows函数,因为它使用ascontiguousarray
来比较数组的元素,这个符号会扰乱唯一性。圆形和修复在这方面表现相同。
>>> np.fix(-1e-6)
Out[1]: array(-0.0)
>>> np.round(-1e-6)
Out[2]: -0.0
有关如何摆脱标志的任何见解?我考虑使用np.sign
函数,但它带来额外的计算成本。
提前致谢。
答案 0 :(得分:8)
-0.
和+0.
之间的问题是浮点数应该如何表现的规范的一部分(IEEE754)。在某些情况下,人们需要这种区别。例如,请参阅the docs for around
中链接到的文档。
值得注意的是,两个零应该相等,所以
np.array(-0.)==np.array(+0.)
# True
也就是说,我认为问题更可能与您的唯一性比较。例如:
a = np.array([-1., -0., 0., 1.])
np.unique(a)
# array([-1., -0., 1.])
如果您想将数字保持为浮点但所有零都相同,则可以使用:
x = np.linspace(-2, 2, 6)
# array([-2. , -1.2, -0.4, 0.4, 1.2, 2. ])
y = x.round()
# array([-2., -1., -0., 0., 1., 2.])
y[y==0.] = 0.
# array([-2., -1., 0., 0., 1., 2.])
# or
y += 0.
# array([-2., -1., 0., 0., 1., 2.])
但是,请注意,由于您试图避免浮点规范,因此必须执行此项额外工作。
另请注意,这不是由于舍入错误造成的。例如,
np.fix(np.array(-.4)).tostring().encode('hex')
# '0000000000000080'
np.fix(np.array(-0.)).tostring().encode('hex')
# '0000000000000080'
也就是说,结果数字完全相同,但是
np.fix(np.array(0.)).tostring().encode('hex')
# '0000000000000000'
是不同的。这就是你的方法不起作用的原因,因为它正在比较数字的二进制表示,这对于两个零是不同的。因此,我认为问题更多的是比较方法,而不是比较浮点数的唯一性。
各种方法的快速测试:
data0 = np.fix(4*np.random.rand(1000000,)-2)
# [ 1. -0. 1. -0. -0. 1. 1. 0. -0. -0. .... ]
N = 100
data = np.array(data0)
print timeit.timeit("data += 0.", setup="from __main__ import np, data", number=N)
# 0.171831846237
data = np.array(data0)
print timeit.timeit("data[data==0.] = 0.", setup="from __main__ import np, data", number=N)
# 0.83500289917
data = np.array(data0)
print timeit.timeit("data.astype(np.int).astype(np.float)", setup="from __main__ import np, data", number=N)
# 0.843791007996
我同意@ senderle的观点,如果你想进行简单而精确的比较,并且可以通过整数来实现,那么整数通常会更容易。但是如果你想要独特的花车,你也应该能够做到这一点,尽管你需要更加小心。浮点数的主要问题是,您可以在计算中引入较小的差异而不会出现在正常的print
中,但这不是一个巨大的障碍,特别是在round, fix, rint
之后。对于合理范围的花车。
答案 1 :(得分:5)
我认为根本问题在于你在浮点数上使用类似集合的操作 - 除非你有一个很好的规则,否则这是一个值得避免的通用规则理由和对浮点数的深刻理解。
遵循此规则的显而易见的原因是,即使两个浮点数之间的非常小的差异也会记录为绝对差异,因此数值错误会导致类似集合的操作产生意外结果。现在,在您的使用案例中,最初似乎您可以通过先舍入来避免该问题,从而限制可能值的范围。但事实证明,正如这个角落案例所示,仍然可能出现意想不到的结果。浮点数很难推理。
我认为正确的解决方法是使用int
进行舍入,然后转换为astype
。
>>> a
array([-0.5, 2. , 0.2, -3. , -0.2])
>>> numpy.fix(a)
array([-0., 2., 0., -3., -0.])
>>> numpy.fix(a).astype(int) # could also use 'i8', etc...
array([ 0, 2, 0, -3, 0])
由于您已经四舍五入,因此不应丢弃任何信息,以后对于类似集合的操作它将更加稳定和可预测。这是使用正确抽象的最佳情况之一!
如果您需要花车,您可以随时转换回来。唯一的问题是它创建了另一个副本;但大部分时间并不是真正的问题。 numpy
足够快,复制的开销非常小!
我添加如果你的案例确实需要使用花车,那么tom10的回答是好的。但我觉得真正需要浮动和类似集合操作的案例数量非常少。