在Python Pandas中选择一个系列

时间:2014-08-23 02:48:24

标签: python pandas

我正在使用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”......

为什么输出与我的期望不同?

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类型。
  • 小数点后28位的小数类型的默认精度。我把它砍成了2.通常十进制模块可以自动处理这个,但是通过numpy交互(我假设),它会混淆,我们最终得到大数字浮点数。较小的精度与您的数据集匹配。
  • 比较中使用的0.30.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