我有以下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
发生了什么事?
答案 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
,结果为False
。 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
输出为%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
启动了缓存,然后None
为KeyError
,触发了一个
{。1}}在generic.py
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