我在熊猫中使用布尔索引。 问题是为什么声明:
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 10
In: 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()
重要的是要认识到,不能在
pandas.Series
或pandas.DataFrame
上使用任何Python逻辑运算符(and
、or
或not
)(类似地,不能在具有多个元素的numpy.array
上使用它们)。您不能使用它们的原因是,它们隐式地调用操作数上的bool
,这会引发异常,因为这些数据结构决定了数组的布尔值是不明确的:我确实更广泛地讨论过这个问题。
NumPys逻辑函数
但是NumPy提供了这些运算符的元素级操作等价物,作为可以在
numpy.array
、pandas.Series
、pandas.DataFrame
或任何其他(一致的)numpy.array
子类上使用的函数:and
有^{or
有^{not
有^{因此,本质上,应该使用(假设
df1
和df2
是pandas数据帧):布尔值的位函数和位运算符
但是,如果您有布尔型NumPy数组、pandas系列或pandas数据帧,则还可以使用element-wise bitwise functions(对于布尔型,它们与逻辑函数或至少应该是不可区分的):
&
运算符|
运算符np.bitwise_not
)或~
运算符^
运算符通常使用运算符。但是,当与比较运算符组合时,必须记住将比较括在括号中,因为按位运算符有一个higher precedence than the comparison operators:
这可能会让人恼火,因为Python逻辑运算符的优先级比比较运算符低,所以通常编写
a < 10 and b > 10
(其中a
和b
是简单整数)而不需要括号。逻辑操作和按位操作之间的差异(在非布尔操作上)
必须强调的是,位和逻辑操作只对布尔NumPy数组(以及布尔序列和数据帧)等效。如果它们不包含布尔值,则操作将给出不同的结果。我将包括使用NumPy数组的示例,但对于pandas数据结构,结果将类似:
由于NumPy(和类似的pandas)对boolean(Boolean or “mask” index arrays)和integer(Index arrays)索引做了不同的事情,因此索引的结果也将不同:
汇总表
其中,逻辑运算符不适用于NumPy数组、pandas系列和pandas数据帧。其他的则处理这些数据结构(和普通的Python对象)和工作元素。 但是,在普通Python
bool
s上按位反转时要小心,因为bool在这个上下文中将被解释为整数(例如~False
返回-1
,而~True
返回-2
)。当你说
您隐式地要求Python将
(a['x']==1)
和(a['y']==10)
转换为布尔值。NumPy数组(长度大于1)和Pandas对象(如Series)没有布尔值,换句话说,它们会提高
当用作布尔值时。那是因为它的unclear when it should be True or False。一些用户可能会假设它们是真的,如果它们具有非零长度,比如Python列表。其他人可能希望它是真的,只要它的所有元素都是真的。其他人可能希望它是真的,如果它的任何元素都是真的。
因为有太多相互矛盾的期望,NumPy和Pandas的设计者拒绝猜测,反而提出了一个价值错误。
相反,您必须是显式的,通过调用
empty()
、all()
或any()
方法来指示您想要的行为。然而,在这种情况下,看起来您不需要布尔求值,而是需要逻辑和。这就是
&
二进制运算符执行的操作:返回布尔数组。
顺便说一下,作为alexpmil notes, 括号是必需的,因为
&
的operator precedence比==
高。 如果没有圆括号,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
。这就是为什么括号是强制性的。熊猫的TLDR;逻辑运算符是
&
、|
和~
,括号(...)
很重要!Python的
and
、or
和not
逻辑运算符被设计为与标量一起工作。因此,Pandas必须做得更好,并重写按位运算符,以实现此功能的矢量化版本。因此,python中的以下表达式(
exp1
和exp2
是求值为布尔结果的表达式)。。。…将转换为。。。
为了熊猫。
如果在执行逻辑操作的过程中得到
ValueError
,则需要使用括号进行分组:例如
等等。
Boolean Indexing:一个常见的操作是通过逻辑条件计算布尔掩码来过滤数据。Pandas提供三个运算符:逻辑与的
&
,逻辑或的|
,逻辑非的~
。考虑以下设置:
逻辑和
对于上面的
df
,假设您希望返回A<;5和B>;5所在的所有行。这是通过分别计算每个条件的掩码,并对它们进行运算来实现的。按位重载
&
运算符在继续之前,请注意文档的这一特定摘录,其中说明
因此,考虑到这一点,可以使用按位运算符
&
实现元素逻辑和:接下来的过滤步骤很简单
括号用于重写按位运算符的默认优先级顺序,这些运算符的优先级高于条件运算符
<
和>
。请参见python文档中的Operator Precedence部分。如果不使用括号,则表达式的计算结果不正确。例如,如果您不小心尝试了
它被解析为
变成了
它变成(参见chained operator comparison上的python文档)
变成了
它抛出
所以,不要犯那个错误!1
避免括号分组
解决方法其实很简单。大多数运算符对数据帧都有相应的绑定方法。如果单个掩码是使用函数而不是条件运算符构建的,则不再需要按parens分组来指定求值顺序:
请参阅Flexible Comparisons.部分。总而言之,我们有
避免括号的另一个选项是使用^{} (或
eval
):我在Dynamic Expression Evaluation in pandas using pd.eval()中广泛地记录了
query
和eval
。^{}
允许您以功能方式执行此操作。内部调用对应于按位运算符的
Series.__and__
。你通常不需要这个,但知道它是有用的。
泛化:^{} (和
logical_and.reduce
)另一种方法是使用
np.logical_and
,它也不需要括号分组:np.logical_and
是一个ufunc (Universal Functions),大多数ufunc都有一个^{logical_and
进行泛化。例如,使用&
来屏蔽m1
、m2
和m3
,则必须执行以下操作不过,更简单的选择是
这很强大,因为它可以让您在这个基础上构建更复杂的逻辑(例如,在列表理解中动态生成掩码并添加所有掩码):
我知道我在唠叨这一点,但请容忍我。这是一个很常见的初学者错误,必须解释得非常透彻。
逻辑或
对于上面的
df
,假设您希望返回A==3或B==7的所有行。按位重载
|
如果您还没有,请阅读上面关于逻辑和的部分,此处适用所有警告。
或者,此操作可以指定为
^{}
在引擎盖下调用
Series.__or__
。^{}
对于两种情况,使用
logical_or
:对于多个遮罩,使用
logical_or.reduce
:逻辑不
给一个面具,比如
如果需要反转每个布尔值(以便最终结果为
[False, False, True]
),则可以使用下面的任何方法。按位
~
同样,表达式需要用括号括起来。
这在内部调用
但不要直接使用。
operator.inv
内部调用序列上的
__invert__
。^{}
这是核弹变种。
注,
np.logical_and
可以用bitwise_or
代替np.bitwise_and
,logical_or
,用invert
代替logical_not
。相关问题 更多 >
编程相关推荐