熊猫:索引数据框时出现多种情况-意外行为


134

我正在按两列中的值过滤数据框中的行。

出于某种原因,OR运算符的行为类似于我期望AND运算符的行为,反之亦然。

我的测试代码:

import pandas as pd

df = pd.DataFrame({'a': range(5), 'b': range(5) })

# let's insert some -1 values
df['a'][1] = -1
df['b'][1] = -1
df['a'][3] = -1
df['b'][4] = -1

df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a != -1) | (df.b != -1)]

print pd.concat([df, df1, df2], axis=1,
                keys = [ 'original df', 'using AND (&)', 'using OR (|)',])

结果:

      original df      using AND (&)      using OR (|)    
             a  b              a   b             a   b
0            0  0              0   0             0   0
1           -1 -1            NaN NaN           NaN NaN
2            2  2              2   2             2   2
3           -1  3            NaN NaN            -1   3
4            4 -1            NaN NaN             4  -1

[5 rows x 6 columns]

如您所见,AND运算符将删除其中至少一个等于的每一行-1。另一方面,OR运算符要求两个值相等-1才能删除它们。我期望结果恰好相反。任何人都可以解释这种行为吗?

我正在使用熊猫0.13.1。


1
df.query并且pd.eval看起来很好拟合这个用例。有关pd.eval()功能系列,其功能和使用案例的信息,请访问使用pd.eval()在熊猫中进行动态表达评估
cs95

Answers:


210

如您所见,AND运算符会删除每一行中至少有一个等于-1的值。另一方面,OR运算符要求两个值都等于-1才能删除它们。

那就对了。请记住,您是根据要保留的内容而不是要丢弃的内容来写条件。对于df1

df1 = df[(df.a != -1) & (df.b != -1)]

您说的是“保留其中df.a不是-1且df.b不是-1的行”,这与删除其中至少一个值为-1的每一行相同。

对于df2

df2 = df[(df.a != -1) | (df.b != -1)]

您说的是“保留其中任一行df.adf.b都不为-1的行”,这与删除两个值均为-1的行相同。

PS:连锁访问会给df['a'][1] = -1您带来麻烦。最好养成使用.loc和的习惯.iloc


24
DataFrame.query()在这里也很好用。df.query('a != -1 or b != -1')
菲利普·

4
碰巧知道为什么熊猫希望&|andor
炉灶

2
@stoves:在常规Python代码中,and并且or具有无法修改的基本Python语义。 &并且|,在另一方面,有其相应的控制其行为的特殊方法。(当然,在查询字符串中,我们可以自由地应用我们喜欢的任何解析。)
DSM

有趣的是,它似乎df[True & False]失败了但df[(True) & (False)]成功了(在此示例中未测试)
3pitt

可以跨多行打破这种语法吗?什么是大多数PEP8?
tommy.carstensen

41

您可以使用query(),即:

df_filtered = df.query('a == 4 & b != 2')

我有一种情况,我认为此语法更有意义,例如:df.query(''(a == 4&b!= 2)| c == 3“)
Aus_10

9

这里有一些数学逻辑理论

“ NOT a AND NOT b”“ NOT(a OR b)”相同,因此:

“ a NOT -1 AND b NOT -1” 等同于 “ NOT(a为-1 OR b为-1)”,与“(a is -1 OR b为-1)”的(补数)相反。

因此,如果您想要完全相反的结果,则df1和df2应如下所示:

df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a == -1) | (df.b == -1)]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.