熊猫的逻辑与运算符在有括号和无括号的情况下会产生不同的结果。

11
我刚刚注意到这个:
df[df.condition1 & df.condition2]
df[(df.condition1) & (df.condition2)]

为什么这两行代码的输出结果不同?
我不能分享具体的数据,但我会尽量提供尽可能多的细节:
df[df.col1 == False & df.col2.isnull()] # returns 33 rows and the rule `df.col2.isnull()` is not in effect
df[(df.col1 == False) & (df.col2.isnull())] # returns 29 rows and both conditions are applied correctly 

解决方案

感谢 @jezrael 和 @ayhan,以下是发生的情况,并让我使用 @jezael 提供的示例:

df = pd.DataFrame({'col1':[True, False, False, False],
                   'col2':[4, np.nan, np.nan, 1]})

print (df)
    col1  col2
0   True   4.0
1  False   NaN
2  False   NaN
3  False   1.0

如果我们看一下第三行:
    col1  col2
3  False   1.0

而且我写条件的方式:
df.col1 == False & df.col2.isnull() # is equivalent to False == False & False

因为符号&的优先级高于==,所以没有括号的False == False & False等同于:
False == (False & False)
print(False == (False & False)) # prints True

带括号的:
print((False == False) & False) # prints False

我觉得用数字来说明这个问题会更容易一些:
print(5 == 5 & 1) # prints False, because 5 & 1 returns 1 and 5==1 returns False
print(5 == (5 & 1)) # prints False, same reason as above
print((5 == 5) & 1) # prints 1, because 5 == 5 returns True, and True & 1 returns 1

所以教训是:永远加上括号!

2个回答

17

df[condition1 & condition2]df[(condition1) & (condition2)]之间没有区别。不同之处在于当您编写表达式并且运算符&优先级较高时会出现差异:

df = pd.DataFrame(np.random.randint(0, 10, size=(5, 3)), columns=list('abc'))    
df
Out: 
   a  b  c
0  5  0  3
1  3  7  9
2  3  5  2
3  4  7  6
4  8  8  1

condition1 = df['a'] > 3
condition2 = df['b'] < 5

df[condition1 & condition2]
Out: 
   a  b  c
0  5  0  3

df[(condition1) & (condition2)]
Out: 
   a  b  c
0  5  0  3

然而,如果您这样输入,将会看到一个错误:

df[df['a'] > 3 & df['b'] < 5]
Traceback (most recent call last):

  File "<ipython-input-7-9d4fd21246ca>", line 1, in <module>
    df[df['a'] > 3 & df['b'] < 5]

  File "/home/ayhan/anaconda3/lib/python3.5/site-packages/pandas/core/generic.py", line 892, in __nonzero__
    .format(self.__class__.__name__))

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

这是因为首先会对3 & df['b']进行求值(在你的示例中对应于False & df.col2.isnull())。因此你需要将条件用括号分组:

df[(df['a'] > 3) & (df['b'] < 5)]
Out[8]: 
   a  b  c
0  5  0  3

1
你是正确的,这是不同的,我认为运算符优先级存在问题-请查看文档
df = pd.DataFrame({'col1':[True, False, False, False],
                   'col2':[4, np.nan, np.nan, 1]})

print (df)
    col1  col2
0   True   4.0
1  False   NaN
2  False   NaN
3  False   1.0

# operator & precedence
print (df[df.col1 == False & df.col2.isnull()])
    col1  col2
1  False   NaN
2  False   NaN
3  False   1.0

# operator == precedence bacause in brackets
print (df[(df.col1 == False) & (df.col2.isnull())])
    col1  col2
1  False   NaN
2  False   NaN

我在docs中找到了它 - 6.16 运算符优先级,其中看到&的优先级比==高:
Operator                                Description

lambda                                  Lambda expression
if – else                               Conditional expression
or                                      Boolean OR
and                                     Boolean AND
not x                                   Boolean NOT
in, not in, is, is not,                 Comparisons, including membership tests    
<, <=, >, >=, !=, ==                    and identity tests
|                                       Bitwise OR
^                                       Bitwise XOR
&                                       Bitwise AND

(expressions...), [expressions...],     Binding or tuple display, list display,       
{key: value...}, {expressions...}       dictionary display, set display

那么哪个运算符优先级更高呢?我还是很困惑。 - Cheng
下表总结了Python中的运算符优先级,从最低优先级(最不紧密)到最高优先级(最紧密)。因此,我认为&==具有更高的优先级。请参见更新的OP。 - Cheng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接