为了账号安全,请及时绑定邮箱和手机立即绑定

用于Pandas中布尔索引的逻辑运算符

用于Pandas中布尔索引的逻辑运算符

慕田峪9158850 2019-06-23 17:09:34
用于Pandas中布尔索引的逻辑运算符我正在处理Pandas中的布尔索引。问题是为什么声明:a[(a['some_column']==some_number) & (a['some_other_column']==some_other_number)]工作得很好a[(a['some_column']==some_number) and (a['some_other_column']==some_other_number)]错误退出?例子:a=pd.DataFrame({'x':[1,1],'y':[10,20]})In: a[(a['x']==1)&(a['y']==10)]Out:    x   y      0  1  10In: a[(a['x']==1) and (a['y']==10)]Out: ValueError: The truth value of an array with more than one element is ambiguous.         Use a.any() or a.all()
查看完整描述

3 回答

?
qq_笑_17

TA贡献1818条经验 获得超7个赞

当你说

(a['x']==1) and (a['y']==10)

您正在隐式地要求Python进行转换。(a['x']==1)(a['y']==10)布尔值。

NumPy数组(长度大于1)和Pandas对象(如Series)没有布尔值-换句话说,它们引发

ValueError: The truth value of an array is ambiguous. Use a.empty, a.any() or a.all().

当用作布尔值时。那是因为不清楚什么时候应该是对的还是错的..一些用户可能会假设他们是真实的,如果他们有非零的长度,如Python列表。其他人可能希望它是真实的,只有在它的元素是真实的。其他人可能希望它是真实的,如果任何其中的元素是真实的。

因为有这么多相互冲突的期望,NumPy和Pandas的设计者拒绝猜测,而是提出了一个价值错误。

相反,您必须显式地调用empty()all()any()方法来指示您想要的行为。

但是,在这种情况下,看起来不需要布尔值,而是需要元素级合乎逻辑-还有。这就是&二进制运算符执行:

(a['x']==1) & (a['y']==10)

返回布尔数组。


顺便说一下,列支钞票,括号是强制性的,因为&有更高的运算符优先==..如果没有括号,a['x']==1 & a['y']==10将被评估为a['x'] == (1 & a['y']) == 10而这又相当于链式比较(a['x'] == (1 & a['y'])) and ((1 & a['y']) == 10)..这是表单的表达式。Series and Series..使用and用两个系列赛会再次触发相同的ValueError如上段所述。这就是为什么括号是强制性的。


查看完整回答
反对 回复 2019-06-23
?
慕沐林林

TA贡献2016条经验 获得超9个赞

Pandas中的逻辑运算符是&|~,和括号(...)很重要!

Python的andornot逻辑运算符设计用于处理标量。因此,Pandas必须做得更好,并重写按位运算符来实现。矢量化(就元素而言)此功能的版本。

下面是python中的内容(exp1exp2是计算为布尔结果的表达式).。

exp1 and exp2              # Logical ANDexp1 or exp2               # Logical ORnot exp1                   # Logical NOT

.会翻译成.

exp1 & exp2                # Element-wise logical ANDexp1 | exp2                # Element-wise logical OR~exp1         
             # Element-wise logical NOT

为了熊猫。

如果在执行逻辑操作的过程中,您将得到一个ValueError,则需要使用括号进行分组:

(exp1) op (exp2)

例如,

(df['col1'] == x) & (df['col2'] == y)

诸若此类。


布尔索引一个常见的操作是通过逻辑条件计算布尔掩码来过滤数据。熊猫提供操作员:&合乎逻辑,|用于逻辑或,以及~逻辑上没有。

考虑以下设置:

np.random.seed(0)df = pd.DataFrame(np.random.choice(10, (5, 3)), columns=list('ABC'))df

   A  B  C0  5  0  31  3  7  92  3  5  23  4  7  64  8  8  1

逻辑与

df上面,假设您想返回A<5和B>5的所有行。这是通过分别计算每个条件的掩码来完成的,并对它们进行处理。

重载位&操作者
在继续之前,请注意以下特定的文档摘录:

另一个常见操作是使用布尔向量过滤数据。营办商包括:|or&and,和~not必须使用括号对它们进行分组。,因为默认情况下Python将计算一个表达式,如df.A > 2 & df.B < 3df.A > (2 &  df.B) < 3,而所需的评估顺序是(df.A > 2) & (df.B <  3).

因此,考虑到这一点,元素分逻辑,可以用位运算符实现。&:

df['A'] < 50    False1     True2     True3     True4    FalseName: A, dtype: bool

df['B'] > 50    False1     True2    False3     True4     TrueName: B, dtype: bool


(df['A'] < 5) & (df['B'] > 5)0    False1     True2    False3     True4    Falsedtype: bool

接下来的过滤步骤很简单,

df[(df['A'] < 5) & (df['B'] > 5)]

   A  B  C1  3  7  93  4  7  6

圆括号用于覆盖按位运算符的默认优先顺序,后者比条件运算符具有更高的优先级。<>..见算子优先在蟒蛇的文档里。

如果不使用括号,则将错误地计算表达式。例如,如果您意外地尝试了诸如

df['A'] < 5 & df['B'] > 5

它被解析为

df['A'] < (5 & df['B']) > 5

变成,

df['A'] < something_you_dont_want > 5

(请参阅python文档)链式算子比较),

(df['A'] < something_you_dont_want) and (something_you_dont_want > 5)

变成,

# Both operands are Series...something_else_you_dont_want1 and something_else_you_dont_want2

抛出

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

所以,别犯那个错误!1

避免部分分组
解决办法其实很简单。大多数操作符都有相应的DataFrame绑定方法。如果单个掩码是使用函数而不是条件运算符构建的,则不再需要按父母分组来指定计算顺序:

df['A'].lt(5)0     True1     True2     True3     True4    FalseName: A, dtype: bool

df['B'].gt(5)0    False1     True2    False3     True4     TrueName: B, dtype: bool


df['A'].lt(5) & df['B'].gt(5)0    False1     True2    False3     True4    Falsedtype: bool

灵活的比较。..总之,我们有

╒════╤════════════╤════════════╕│    │ Operator   │ Function   │╞════╪═══════════
═╪════════════╡│  0 │ >          │ gt         │├────┼────────────┼────────────
┤│  1 │ >=         │ ge         │├────┼────────────┼────────────┤│  2 │ <          │
 lt         │├────┼────────────┼────────────┤│  3 │ <=         │ le         │├────┼
 ────────────┼────────────┤│  4 │ ==         │ eq         │├────┼────────────┼─
 ───────────┤│  5 │ !=         │ ne         │╘════╧════════════╧════════════╛

避免括号的另一个选择是使用DataFrame.query(或eval):

df.query('A < 5 and B > 5')

   A  B  C1  3  7  93  4  7  6

我有过广泛记录在案queryeval在……里面熊猫动态表达评价的pd.val().

operator.and_
允许您以功能方式执行此操作。内部呼叫Series.__and__它对应于位操作符。

import operator 

operator.and_(df['A'] < 5, df['B'] > 5)# Same as,# (df['A'] < 5).__and__(df['B'] > 5) 0    False1     True2    False3     True4   
 Falsedtype: bool

df[operator.and_(df['A'] < 5, df['B'] > 5)]

   A  B  C1  3  7  93  4  7  6

你通常不需要这个,但是知道是有用的。

概括:np.logical_and(和logical_and.reduce)
另一种选择是使用np.logical_and,也不需要括号分组:

np.logical_and(df['A'] < 5, df['B'] > 5)0    False1     True2    False3     True4    FalseName: A, dtype: bool

df[np.logical_and(df['A'] < 5, df['B'] > 5)]

   A  B  C1  3  7  93  4  7  6

np.logical_andUfunc(通用职能),而且大多数运行程序都有一个reduce方法。这意味着更容易泛化。logical_and如果你有多个面具。例如,to和掩码m1m2m3带着&,你必须做

m1 & m2 & m3

然而,一个更容易的选择是

np.logical_and.reduce([m1, m2, m3])

这是强大的,因为它允许您在此基础上构建更复杂的逻辑(例如,在列表理解中动态生成掩码并添加所有掩码):

import operator

cols = ['A', 'B']ops = [np.less, np.greater]values = [5, 5]m = np.logical_and.reduce([op(df[c], v) for op, c, v in zip(ops, cols, values)])m 
# array([False,  True, False,  True, False])df[m]
   A  B  C1  3  7  93  4  7  6

我知道我是在唠叨这一点,但请容忍我。这是一个非常非常普通初学者的错误,必须非常彻底地解释。


逻辑OR

df上面,假设您想返回A=3或B=7的所有行。

重载位|

df['A'] == 30    False1     True2     True3    False4    FalseName: A, dtype: bool

df['B'] == 70    False1     True2    False3     True4    FalseName: B, dtype: bool


(df['A'] == 3) | (df['B'] == 7)0    False1     True2     True3     True4    Falsedtype: bool

df[(df['A'] == 3) | (df['B'] == 7)]

   A  B  C1  3  7  92  3  5  23  4  7  6

如果您还没有,请阅读逻辑与以上,所有的警告都适用于此。

或者,可以用

df[df['A'].eq(3) | df['B'].eq(7)]

   A  B  C1  3  7  92  3  5  23  4  7  6

operator.or_
打电话Series.__or__在引擎盖下面。

operator.or_(df['A'] == 3, df['B'] == 7)# Same as,# (df['A'] == 3).__or__(df['B'] == 7)0    False1     True2     True3     True4 
   Falsedtype: bool

df[operator.or_(df['A'] == 3, df['B'] == 7)]

   A  B  C1  3  7  92  3  5  23  4  7  6

np.logical_or
对于两个条件,请使用logical_or:

np.logical_or(df['A'] == 3, df['B'] == 7)0    False1     True2     True3     True4    FalseName: A, dtype: bool

df[np.logical_or(df['A'] == 3, df['B'] == 7)]

   A  B  C1  3  7  92  3  5  23  4  7  6

对于多个掩码,请使用logical_or.reduce:

np.logical_or.reduce([df['A'] == 3, df['B'] == 7])# array([False,  True,  True,  True, False])df[np.logical_or.reduce([df['A'] 
== 3, df['B'] == 7])]

   A  B  C1  3  7  92  3  5  23  4  7  6

逻辑不

戴上面具,如

mask = pd.Series([True, True, False])

如果您需要反转每个布尔值(因此最终结果是[False, False, True]),则可以使用以下任何方法。

按位~

~mask0    False1    False2     Truedtype: bool

同样,表达式需要加括号。

~(df['A'] == 3)0     True1    False2    False3     True4     TrueName: A, dtype: bool

这内部呼叫

mask.__invert__()0    False1    False2     Truedtype: bool

但不要直接用。

operator.inv
内部呼叫__invert__在系列赛上。

operator.inv(mask)0    False1    False2     Truedtype: bool

np.logical_not
这是矮胖的变体。

np.logical_not(mask)0    False1    False2     Truedtype: bool

注:np.logical_and可以代替np.bitwise_andlogical_or带着bitwise_or,和logical_not带着invert.


查看完整回答
反对 回复 2019-06-23
  • 3 回答
  • 0 关注
  • 3607 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信