表达式为" == True"和"是真的"给出不同的结果

时间:2016-04-24 16:35:41

标签: python pandas pep8

我有以下MCVE

#!/usr/bin/env python3                                           

import pandas as pd

df = pd.DataFrame([True, False, True])

print("Whole DataFrame:")
print(df)

print("\nFiltered DataFrame:")
print(df[df[0] == True])

输出如下,我期望:

Whole DataFrame:
     0
  0  True
  1  False
  2  True

Filtered DataFrame:
     0
  0  True
  2  True

好的,但PEP8样式似乎有误,它说: E712与True的比较应为if cond is Trueif cond 。所以我将其更改为is True而不是== True,但现在它失败了,输出为:

Whole DataFrame:
    0
0   True
1  False
2   True

Filtered DataFrame:
0     True
1    False
2     True
Name: 0, dtype: bool

发生了什么事?

5 个答案:

答案 0 :(得分:4)

在python中,is测试一个对象是否与另一个对象相同。 ==pandas.Series定义,以元素方式执行,is不是。

因此,df[0] is True会比较df[0]True是否是同一个对象。结果为False,后者又等于0,因此您在执行0

时会获得df[df[0] is True]

答案 1 :(得分:1)

我认为boolean Series比较仅适用于is,结果为Falseprint df[0] == True 0 True 1 False 2 True Name: 0, dtype: bool print df[df[0]] 0 0 True 2 True print df[df[0] == True] 0 0 True 2 True print df[0] is True False print df[df[0] is True] 0 True 1 False 2 True Name: 0, dtype: bool 输出为%F。有关is的更多信息。

2016-04-14T07:47:50.120043Z

答案 2 :(得分:1)

这里的问题是df[df[0] == True]你没有将对象与True 进行比较。

正如其他答案所说的那样,==中的pandas会超载Series,而不像通常那样产生bool而不是[]Series也被重载,以解释series = df[0].__eq__(True) df.__getitem__(series) 并提供过滤后的结果。代码基本上等同于:

==

因此,您 违反了PEP8,只留下pandas

基本上,item给出了熟悉的语法异常语义 - 这就是引起混淆的原因。

Accoring to Stroustroup(sec.3.3.3),运算符重载自从发明以来就一直引起麻烦(他必须仔细思考是否将它包含在C ++中)。 Seeing even more abuse of it in C++,Gosling在Java中遇到了另一个极端,完全禁止它,事实证明这是极端的。

作为结论,现代语言和代码往往会使运算符重载,但要密切注意不要过度使用它,并保持语义保持一致。

答案 3 :(得分:1)

这是对MaxNoe答案的详细说明,因为这包括很长的内容 在评论中。

正如他所指出的那样,df[0] is True评估为False,然后被强迫 到0,对应于列名。这有趣的是 如果你运行

>>>df = pd.DataFrame([True, False, True])
>>>df[False]
KeyError                                  Traceback (most recent call last)
<ipython-input-21-62b48754461f> in <module>()
----> 1 df[False]

>>>df[0]
0     True
1    False
2     True
Name: 0, dtype: bool
>>>df[False]
0     True
1    False
2     True
Name: 0, dtype: bool

起初看起来有点令人困惑(至少对我而言),但与如何有​​关 pandas使用缓存。如果你看一下df[False]是如何解决的,那就是它 看起来像

  /home/matthew/anaconda/lib/python2.7/site-packages/pandas/core/frame.py(1975)__getitem__()
-> return self._getitem_column(key)
  /home/matthew/anaconda/lib/python2.7/site-packages/pandas/core/frame.py(1999)_getitem_column()
-> return self._get_item_cache(key)
> /home/matthew/anaconda/lib/python2.7/site-packages/pandas/core/generic.py(1343)_get_item_cache()
-> res = cache.get(item)

由于cache只是常规python dict,因此在df[0] cache>>>cache {0: 0 True 1 False 2 True Name: 0, dtype: bool} 看起来像

False

这样当我们查找0时,python会将其强制转换为df[0]。如果我们没有 已经使用res启动了缓存,然后NoneKeyError,触发了一个 {。1}}在generic.py

的第1345行
def _get_item_cache(self, item):
1341            """Return the cached item, item represents a label indexer."""
1342            cache = self._item_cache
1343 ->         res = cache.get(item)
1344            if res is None:
1345                values = self._data.get(item)

答案 4 :(得分:0)

一种解决方案,可以避免棉短绒的投诉,但仍然可以合理设置子集的语法,

s = pd.Series([True] * 10 + [False])

s.loc[s == True]  # bad comparison in Python's eyes
s.loc[s.isin([True])]  # valid comparison, not as ugly as s.__eq__(True)

两者都需要相同的时间。

此外,对于数据帧,可以使用query

df = pd.DataFrame([
        [True] * 10 + [False],
        list(range(11))],
    index=['T', 'N']).T
df.query("T == True")  # also okay