我通过两列的值过滤数据帧中的行。

出于某种原因,OR操作符的行为和我期望的AND操作符的行为一样,反之亦然。

我的测试代码:

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。


当前回答

你可以尝试以下方法:

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

其他回答

这里有一点数学逻辑理论:

“NOT a AND NOT b”和“NOT (a OR b)”是一样的,所以:

“a NOT -1 AND b NOT -1”等价于“NOT (a is -1 OR b is -1)”,这与“(a is -1 OR b is -1)”相反。

所以如果你想要完全相反的结果,df1和df2应该如下所示:

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

你可以尝试以下方法:

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

延迟回答,但你也可以使用query(),即:

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

根据摩根定律,(i)一个联合的否定是两个否定的交集,(ii)一个交集的否定是两个否定的交集的并,即,

A AND B <=> not A OR not B
A OR B  <=> not A AND not B

如果目标是

删除至少有一个值等于-1的每一行

您可以使用AND操作符来标识要保留的行,也可以使用or操作符来标识要删除的行。

# select rows where both a and b values are not equal to -1
df2_0 = df[df['a'].ne(-1) & df['b'].ne(-1)]

# index of rows where at least one of a or b equals -1
idx = df.index[df.eval('a == -1 or b == -1')]
# drop `idx` rows
df2_1 = df.drop(idx)

df2_0.equals(df2_1) # True

另一方面,如果目标是

删除两个值都等于-1的每一行

你做的正好相反;要么使用OR运算符来标识要保留的行,要么使用AND运算符来标识要删除的行。

如您所见,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。A或df。B不是-1",这和删除两个值都是-1的行是一样的。

PS:像df['a'][1] = -1这样的链式访问可能会给你带来麻烦。最好养成使用.loc和.iloc的习惯。