我正在使用Pandas系列来选择系列的行。但是,我遇到了以下问题:
>>> q=pandas.Series([0.5,0.5,0,1,0.5,0.5])
>>> q
0 0.5
1 0.5
2 0.0
3 1.0
4 0.5
5 0.5
dtype: float64
>>> (q-0.3).abs()
0 0.2
1 0.2
2 0.3
3 0.7
4 0.2
5 0.2
dtype: float64
>>> (q-0.7).abs()
0 0.2
1 0.2
2 0.7
3 0.3
4 0.2
5 0.2
dtype: float64
>>> (q-0.3).abs() > (q-0.7).abs() # This is I expected:
0 True # False
1 True # False
2 False # False
3 True # True
4 True # False
5 True # False
dtype: bool
>>> (q-0.3).abs() == (q-0.7).abs()
0 False
1 False
2 False
3 False
4 False
5 False
dtype: bool
显然,“0.2”不大于“0.2”......
为什么输出与我的期望不同?
答案 0 :(得分:1)
这是一个浮点问题。它在this问题中得到了很好的描述。
要直接回答您的问题,请查看两个测试的第一个元素。你的价值不相等。
>>> (q-0.7).abs()[1]
0.19999999999999996
>>> (q-0.3).abs()[1]
0.20000000000000001
我们可以通过一些操作和使用decimal
模块来获得您的结果。
>>> from decimal import Decimal, getcontext
>>> import pandas
>>> s = [0.5,0.5,0,1,0.5,0.5]
>>> dec_s = [Decimal(x) for x in s]
>>> q = pandas.Series(dec_s)
>>> q
0 0.5
1 0.5
2 0
3 1
4 0.5
5 0.5
dtype: object
>>> getcontext().prec
28
>>> getcontext().prec = 2
>>> (q-Decimal(0.3)).abs() > (q-Decimal(0.7)).abs()
0 False
1 False
2 False
3 True
4 False
5 False
dtype: bool
有几点需要注意:
float
之前,值列表已从decimal
转换为Series
数据类型。dtype
现在是object
而不是float64
。这是因为numpy没有直接处理Decimal类型。0.3
和0.7
值也必须为十进制,否则您将看到类似于unsupported operand type(s) for +: 'Decimal' and 'float'
的错误。 答案 1 :(得分:1)
Andy的回答是正确的(这是一个浮点问题,也是pandas在Series / DataFrame中打印时如何截断浮点的问题......)。
您可能想要使用numpy函数isclose
:
In [11]: a = (q-0.3).abs()
In [12]: b = (q-0.7).abs()
In [13]: np.isclose(a, b)
Out[13]: array([ True, True, False, False, True, True], dtype=bool)
我认为没有本地熊猫功能可以做到这一点,很高兴被召唤出来......
默认容差(atol
)为1e-8,因此在测试大于(以获得所需结果)时,我们可以使用它:
In [14]: a > b + 1e-8
Out[14]:
0 False
1 False
2 False
3 True
4 False
5 False
dtype: bool
更新:为了进一步评论性能方面,我们看到,对于具有6000个元素的系列,float64的速度要快1000倍(随着长度的增加,这会变得更糟):
In [21]: q = pd.Series([0.5, 0.5, 0, 1, 0.5, 0.5] * 1000)
In [22]: %timeit a = (q-0.3).abs(); b = (q-0.7).abs(); a > b + 1e-8
1000 loops, best of 3: 726 µs per loop
In [23]: dec_s = q.apply(Decimal)
In [24]: %timeit (dec_s-Decimal(0.3)).abs() > (dec_s-Decimal(0.7)).abs()
1 loops, best of 3: 915 ms per loop
与更多元素的差异更为明显:
In [31]: q = pd.Series([0.5, 0.5 ,0, 1, 0.5, 0.5] * 10000)
In [32]: %timeit a = (q-0.3).abs(); b = (q-0.7).abs(); a > b + 1e-8
1000 loops, best of 3: 1.5 ms per loop
In [33]: dec_s = q.apply(Decimal)
In [34]: %timeit (dec_s-Decimal(0.3)).abs() > (dec_s-Decimal(0.7)).abs()
1 loops, best of 3: 9.16 s per loop