我有以下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 True
或if 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
到底是怎么回事?
这里的问题是在df[df[0] == True]
,你没有比较对象与True
。
正如其他答案所说,==
在pandas
超负荷生产一个Series
而不是像往常那样的bool
。 []
也被重载,以解释Series
并给出过滤结果。代码基本上等同于:
series = df[0].__eq__(True)
df.__getitem__(series)
所以,你不要在这里留下==
来违反PEP8。
从本质上讲,pandas
给出了熟悉的语法异常语义 - 这就是引起混淆的原因。
Accoring to Stroustroup(sec.3.3.3),运算符重载自从它的发明以来一直引起麻烦(他必须仔细思考是否将它包含在C ++中)。加斯克斯沃斯,高斯林在Java中跑向另一个极端,完全禁止它,事实证明这是一个极端。
总而言之,现代语言和代码往往会使运算符重载,但要密切注意不要过度使用它,并保持语义保持一致。
在python中,Seeing even more abuse of it in C++测试一个对象是否与另一个对象相同。 is
由==
定义为元素方式,pandas.Series
不是。
因此,is
比较df[0] is True
和df[0]
是否是同一个对象。结果是True
,反过来等于False
,所以你在做0
时得到0
列
这是对MaxNoe答案的详细说明,因为这篇文章很长,可以包含在评论中。
正如他所指出的那样,df[df[0] is True]
评估为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)
只是一个普通的python cache
,在运行dict
后,df[0]
看起来像
cache
因此,当我们查找>>>cache
{0: 0 True
1 False
2 True
Name: 0, dtype: bool}
时,python将此强制转换为False
。如果我们还没有使用0
启动缓存,那么df[0]
是res
,它在generic.py的第1345行触发None
KeyError
我认为在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)
比较只适用于pandas
,结果是==
。随着boolean Series
输出是is
。有关更多信息False
。
is
一个解决方法是没有来自linters的投诉,但仍然有合理的子设置语法可能是:
print 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
两者也需要同一时间。
此外,对于数据帧,可以使用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