Python如何==为float / double工作?

时间:2016-09-14 14:59:25

标签: python pandas floating-point

我知道使用==进行浮动通常是不安全的。但它是否适用于以下情况?

  1. 从csv文件A.csv中读取,将前半部分数据保存到csv文件B.csv而不做任何事情。
  2. 从A.csv和B.csv中读取。使用==检查数据是否与上半场的所有位置匹配。
  3. 这些都是用熊猫完成的。 A.csv中的列具有datetime,string和float类型。显然==适用于datetime和string,所以如果==适用于float,在这种情况下,它可以节省大量的工作。

    它似乎适用于我的所有测试,但我能否认为它会一直有效?

2 个答案:

答案 0 :(得分:3)

当通过相同的解析例程时,相同的字符串表示将成为相同的浮点表示。当对值执行数学运算或使用高精度表示时,会出现浮点不准确问题,但是低精度值的相等性无需担心。

答案 1 :(得分:3)

不,你不能认为这会一直有效。

要使其工作,您需要知道Pandas在写入CSV文件时写出的文本值在读回时(再次使用Pandas)恢复完全相同的值。但默认情况下,Pandas read_csv函数牺牲了速度的准确性,因此解析操作会自动恢复相同的浮动。

为了演示这一点,请尝试以下操作:我们将创建一些随机值,将它们写入CSV文件,然后使用Pandas将其读回。首先是必要的进口:

>>> import pandas as pd
>>> import numpy as np

现在创建一些随机值,并将它们放入Pandas Series对象中:

>>> test_values = np.random.rand(10000)
>>> s = pd.Series(test_values, name='test_values')

现在我们使用to_csv方法将这些值写入文件,然后将该文件的内容读回DataFrame

>>> s.to_csv('test.csv', header=True)
>>> df = pd.read_csv('test.csv')

最后,让我们从df的相关列中提取值并进行比较。我们将对==操作的结果求和,以找出确切恢复了多少10000个输入值。

>>> sum(test_values == df['test_values'])
7808

因此大约78%的值被正确恢复;其他人则没有。

此行为被认为是Pandas的一个功能,而不是一个bug。但是,有一种解决方法:Pandas 0.15为CSV阅读器添加了一个新的float_precision参数。通过向float_precision='round_trip'操作提供read_csv,Pandas使用更慢但更准确的解析器。试试上面的例子,我们得到了完美的恢复值:

>>> df = pd.read_csv('test.csv', float_precision='round_trip')
>>> sum(test_values == df['test_values'])
10000

这是第二个例子,朝另一个方向发展。前面的例子表明,写入然后读取不会返回相同的数据。此示例显示读取和写入也不保留数据。设置与您在问题中描述的设置非常匹配。首先,我们将创建A.csv,这次使用常规值而不是随机值:

>>> import pandas as pd, numpy as np
>>> s = pd.Series(np.arange(10**4) / 1e3, name='test_values')
>>> s.to_csv('A.csv', header=True)

现在我们阅读A.csv,并将数据的前半部分再次写回B.csv,与第1步一样。

>>> recovered_s = pd.read_csv('A.csv').test_values
>>> recovered_s[:5000].to_csv('B.csv', header=True)

然后我们同时阅读A.csvB.csv,并将A的前半部分与B进行比较,与第2步一样。

>>> a = pd.read_csv('A.csv').test_values
>>> b = pd.read_csv('B.csv').test_values
>>> (a[:5000] == b).all()
False
>>> (a[:5000] == b).sum()
4251

因此,有几个值无法正确比较。打开文件,A.csv看起来就像我期望的那样。以下是A.csv中的前15个条目:

,test_values
0,0.0
1,0.001
2,0.002
3,0.003
4,0.004
5,0.005
6,0.006
7,0.007
8,0.008
9,0.009
10,0.01
11,0.011
12,0.012
13,0.013
14,0.014
15,0.015

以下是B.csv中的相应条目:

,test_values
0,0.0
1,0.001
2,0.002
3,0.003
4,0.004
5,0.005
6,0.006
7,0.006999999999999999
8,0.008
9,0.009000000000000001
10,0.01
11,0.011000000000000001
12,0.012
13,0.013000000000000001
14,0.013999999999999999
15,0.015

有关将float_precision关键字引入read_csv的更多信息,请参阅此bug report