2014-11-06 22 views
10

我对在numpyfixfloor功能一个简单的问题。 将大于-1的负数舍入到零时,numpy将它们正确舍入为零但留下负号。这个负面信号会干扰我的服饰unique_rows功能,因为它使用ascontiguousarray来比较数组中的元素,并且此标志会干扰唯一性。在这方面,轮次和修复的行为都是相同的。如何消除多余的负号在四舍五入将负数舍入到零时?

>>> np.fix(-1e-6) 
Out[1]: array(-0.0) 
>>> np.round(-1e-6) 
Out[2]: -0.0 

关于如何摆脱标志的任何见解?我想过使用np.sign函数,但它带有额外的计算成本。

在此先感谢。

+1

尝试将0.0加到结果中。 – 2014-11-06 14:37:03

+1

这是以前的问题吗? http://stackoverflow.com/questions/3387655/safest-way-to-convert-float-to-integer-in-python – 2014-11-06 14:54:16

回答

6

您在-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' 

是不同的。这就是为什么你的方法不起作用,因为它比较了数字的二进制表示,这对于两个零来说是不同的。因此,我认为这个问题更多的是比较浮点数的唯一性的一般思路。

的各种方法快速timeit测试:

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之后。

+0

我同意这是一个很好的方法,如果有必要坚持浮动。 (我想知道它与Mark Ransom添加'0.0'的想法相比如何。)另外,我认为正面和负面的零不一样,因为连接到问题的唯一性测试将数据转换为'np.void'。 – senderle 2014-11-06 18:16:03

+0

感谢@Mark Ransom和@ tom10。将0.0添加到“修复”或“循环”命令的答案中,可以消除由于上述原因所造成的额外负面信号。 解决了这个问题之后,我能够编写一个python函数来在numpy数组中找到唯一的行,并且可以选择接受精度(小数位数)。这个函数可以在[这里]找到(http://stackoverflow.com/questions/16970982/find-unique-rows-in-numpy-array/26867764#26867764)。 – 2014-11-11 14:59:48

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的回答是一个好的答案。但我认为,浮动和类固定操作真正需要的案例数量非常少。

+0

我同意你的解决方案(所以+1),但我认为原因是IEEE754标准指定'0.'和'-0.'是不同的(尽管它们应该相等)。 – tom10 2014-11-06 16:11:56

+0

@ tom10,OP似乎意识到这一点,你不觉得吗?但它比你建议的更复杂,因为我们特别讨论_rounding_。我不知道标准中关于它所定义的四个舍入规则中的任何一个签名的零是什么。大概'numpy'可以忽略这些规则,并且如果它想要的话只能回到正值零!我认为无论使用哪种特定标准,这些问题都会很困难。 – senderle 2014-11-06 17:08:35

+0

我会删除我的评论,并写我自己的答案。你在这里明确表示问题是“数字错误”,我试图说这不是问题。但是我会在几分钟内删除这两条评论,以免混淆水域。 – tom10 2014-11-06 17:29:00