use*_*577 119 python filtering boolean dataframe pandas
我在Pandas中使用布尔索引.问题是为什么声明:
a[(a['some_column']==some_number) & (a['some_other_column']==some_other_number)]
Run Code Online (Sandbox Code Playgroud)
工作正常,而
a[(a['some_column']==some_number) and (a['some_other_column']==some_other_number)]
Run Code Online (Sandbox Code Playgroud)
存在错误?
例:
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()
Run Code Online (Sandbox Code Playgroud)
unu*_*tbu 176
当你说
(a['x']==1) and (a['y']==10)
Run Code Online (Sandbox Code Playgroud)
你是隐问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().
Run Code Online (Sandbox Code Playgroud)
当用作布尔值时.那是因为它不清楚它应该是真还是假.如果某些用户长度非零,则可能会认为它们是True,如Python列表.其他人可能希望它只有在其所有元素都是真的时才是真的.如果其中任何元素为True,其他人可能希望它为True.
因为有太多相互矛盾的期望,NumPy和Pandas的设计师拒绝猜测,而是提出了一个ValueError.
相反,您必须明确,通过调用empty()
,all()
或any()
方法来指示您想要的行为.
但是,在这种情况下,看起来你不想要布尔评估,你想要元素逻辑和.这就是&
二元运算符执行的操作:
(a['x']==1) & (a['y']==10)
Run Code Online (Sandbox Code Playgroud)
返回一个布尔数组.
顺便说一句,作为alexpmil音符,括号是必须的,因为&
有更高的运算符优先级比==
.没有括号,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
上述相同.这就是为什么括号是强制性的.
cs9*_*s95 35
Python的&
,|
和~
逻辑运算符的设计与标量的工作.因此,Pandas必须做得更好并覆盖按位运算符以实现此功能的矢量化(逐元素)版本.
所以下面的python ......
exp1 and exp2 # Logical AND
exp1 or exp2 # Logical OR
not exp1 # Logical NOT
Run Code Online (Sandbox Code Playgroud)
......将翻译成,
exp1 & exp2 # Element-wise logical AND
exp1 | exp2 # Element-wise logical OR
~exp1 # Element-wise logical NOT
Run Code Online (Sandbox Code Playgroud)
对于熊猫,等等.
如果在执行逻辑操作的过程中得到a (...)
,则需要使用括号进行分组:
(exp1) op (exp2)
Run Code Online (Sandbox Code Playgroud)
例如,
(df['col1'] == x) & (df['col2'] == y)
Run Code Online (Sandbox Code Playgroud)
等等.
常见的操作是通过逻辑条件计算布尔掩码以过滤数据.Pandas提供三个运算符:and
逻辑AND,or
逻辑OR和not
逻辑NOT.
请考虑以下设置:
np.random.seed(0)
df = pd.DataFrame(np.random.choice(10, (5, 3)), columns=list('ABC'))
df
A B C
0 5 0 3
1 3 7 9
2 3 5 2
3 4 7 6
4 8 8 1
Run Code Online (Sandbox Code Playgroud)
对于exp1
上面,假设您要返回A <5和B> 5的所有行.这可以通过分别计算每个条件的掩码并对它们进行AND运算来完成.
重载按位exp2
运算符
在继续之前,请注意文档的这个特定摘录,其中说明了这一点
另一种常见操作是使用布尔向量来过滤数据.运营商是:
ValueError
for&
,|
for~
和df
for&
.必须使用括号对这些进行分组,因为默认情况下,Python将评估表达式,例如|
asor
,而期望的评估顺序是&
.
因此,考虑到这一点,可以使用按位运算符实现元素明智的逻辑AND and
:
df['A'] < 5
0 False
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df['B'] > 5
0 False
1 True
2 False
3 True
4 True
Name: B, dtype: bool
Run Code Online (Sandbox Code Playgroud)
(df['A'] < 5) & (df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
Run Code Online (Sandbox Code Playgroud)
后续的过滤步骤很简单,
df[(df['A'] < 5) & (df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
括号用于覆盖按位运算符的默认优先顺序,其优先级高于条件运算符~
和not
.请参阅python文档中的Operator Precedence部分.
如果不使用括号,则表达式计算不正确.例如,如果你不小心尝试了诸如此类的东西
df['A'] < 5 & df['B'] > 5
Run Code Online (Sandbox Code Playgroud)
它被解析为
df['A'] < (5 & df['B']) > 5
Run Code Online (Sandbox Code Playgroud)
哪个变成,
df['A'] < something_you_dont_want > 5
Run Code Online (Sandbox Code Playgroud)
哪个成为(参见链接运算符比较的python文档),
(df['A'] < something_you_dont_want) and (something_you_dont_want > 5)
Run Code Online (Sandbox Code Playgroud)
哪个变成,
# Both operands are Series...
something_else_you_dont_want1 and something_else_you_dont_want2
Run Code Online (Sandbox Code Playgroud)
哪个投掷
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Run Code Online (Sandbox Code Playgroud)
所以,不要犯那个错误!1
避免括号分组
修复实际上非常简单.大多数运算符都有相应的DataFrames绑定方法.如果使用函数而不是条件运算符构建单个掩码,则不再需要按parens分组来指定评估顺序:
df['A'].lt(5)
0 True
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df['B'].gt(5)
0 False
1 True
2 False
3 True
4 True
Name: B, dtype: bool
Run Code Online (Sandbox Code Playgroud)
df['A'].lt(5) & df['B'].gt(5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
Run Code Online (Sandbox Code Playgroud)
????????????????????????????????
? ? Operator ? Function ?
????????????????????????????????
? 0 ? > ? gt ?
????????????????????????????????
? 1 ? >= ? ge ?
????????????????????????????????
? 2 ? < ? lt ?
????????????????????????????????
? 3 ? <= ? le ?
????????????????????????????????
? 4 ? == ? eq ?
????????????????????????????????
? 5 ? != ? ne ?
????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
避免使用括号的另一个选择是使用df.A > 2 & df.B < 3
(或df.A > (2 &
df.B) < 3
):
df.query('A < 5 and B > 5')
A B C
1 3 7 9
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
我已经广泛地记录(df.A > 2) & (df.B <
3)
和&
在使用pd.eval动态表达评价大熊猫() .
<
允许您以功能方式执行此操作.内部调用>
对应于按位运算符.
import operator
operator.and_(df['A'] < 5, df['B'] > 5)
# Same as,
# (df['A'] < 5).__and__(df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
df[operator.and_(df['A'] < 5, df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
你通常不需要这个,但知道它是有用的.
推广:( DataFrame.query
和eval
)
另一种选择是使用 query
,也不需要括号分组:
np.logical_and(df['A'] < 5, df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
Name: A, dtype: bool
df[np.logical_and(df['A'] < 5, df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
eval
是一个ufunc(通用函数),大多数ufunc都有一个operator.and_
方法.这意味着Series.__and__
如果你有多个AND的掩码,则更容易概括.例如,要和口罩np.logical_and
,并logical_and.reduce
和np.logical_and
用np.logical_and
,你就必须做
m1 & m2 & m3
Run Code Online (Sandbox Code Playgroud)
但是,更简单的选择是
np.logical_and.reduce([m1, m2, m3])
Run Code Online (Sandbox Code Playgroud)
这很强大,因为它允许您使用更复杂的逻辑构建此类(例如,在列表理解中动态生成掩码并添加所有这些掩码):
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 C
1 3 7 9
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
1 - 我知道我在这一点上很难受,但请耐心等待.这是一个非常,非常常见的初学者的错误,必须非常有详尽的解释.
对于reduce
上述情况,假设您要返回A == 3或B == 7的所有行.
按位重载 logical_and
df['A'] == 3
0 False
1 True
2 True
3 False
4 False
Name: A, dtype: bool
df['B'] == 7
0 False
1 True
2 False
3 True
4 False
Name: B, dtype: bool
Run Code Online (Sandbox Code Playgroud)
(df['A'] == 3) | (df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
dtype: bool
df[(df['A'] == 3) | (df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
如果您还没有,请阅读上面的逻辑和部分,所有注意事项都适用于此处.
或者,可以使用指定此操作
df[df['A'].eq(3) | df['B'].eq(7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
m1
m2
引擎盖下的
电话.
operator.or_(df['A'] == 3, df['B'] == 7)
# Same as,
# (df['A'] == 3).__or__(df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
dtype: bool
df[operator.or_(df['A'] == 3, df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
m3
对于两个条件,请使用&
:
np.logical_or(df['A'] == 3, df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df[np.logical_or(df['A'] == 3, df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
对于多个面具,请使用df
:
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 C
1 3 7 9
2 3 5 2
3 4 7 6
Run Code Online (Sandbox Code Playgroud)
给出一个面具,如
mask = pd.Series([True, True, False])
Run Code Online (Sandbox Code Playgroud)
如果您需要反转每个布尔值(以便最终结果是|
),那么您可以使用以下任何方法.
按位 operator.or_
~mask
0 False
1 False
2 True
dtype: bool
Run Code Online (Sandbox Code Playgroud)
同样,表达式需要括起来.
~(df['A'] == 3)
0 True
1 False
2 False
3 True
4 True
Name: A, dtype: bool
Run Code Online (Sandbox Code Playgroud)
内部调用
mask.__invert__()
0 False
1 False
2 True
dtype: bool
Run Code Online (Sandbox Code Playgroud)
但是不要直接使用它.
Series.__or__
内部呼唤np.logical_or
系列赛.
operator.inv(mask)
0 False
1 False
2 True
dtype: bool
Run Code Online (Sandbox Code Playgroud)
logical_or
这是numpy变种.
np.logical_not(mask)
0 False
1 False
2 True
dtype: bool
Run Code Online (Sandbox Code Playgroud)
注意,logical_or.reduce
可以替换[False, False, True]
,~
使用operator.inv
和__invert__
使用np.logical_not
.
Pandas 中布尔索引的逻辑运算符
重要的是要意识到您不能在or s上使用任何 Python逻辑运算符(and
, or
or not
)(同样,您不能在具有多个元素的 s 上使用它们)。你不能使用它们的原因是因为它们隐式调用了抛出异常的操作数,因为这些数据结构决定了数组的布尔值是不明确的:pandas.Series
pandas.DataFrame
numpy.array
bool
>>> import numpy as np
>>> import pandas as pd
>>> arr = np.array([1,2,3])
>>> s = pd.Series([1,2,3])
>>> df = pd.DataFrame([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> bool(df)
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Run Code Online (Sandbox Code Playgroud)
我在回答“系列的真值不明确。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()”的回答中确实更广泛地涵盖了这一点+A。
然而NumPy的提供逐元素的操作等同于这些运营商的功能,可以在被使用numpy.array
,pandas.Series
,pandas.DataFrame
,或任何其他(符合)numpy.array
亚类:
and
已 np.logical_and
or
已 np.logical_or
not
已 np.logical_not
numpy.logical_xor
它没有 Python 等价物,但它是逻辑的“异或”操作因此,本质上,应该使用(假设df1
并且df2
是熊猫数据帧):
np.logical_and(df1, df2)
np.logical_or(df1, df2)
np.logical_not(df1)
np.logical_xor(df1, df2)
Run Code Online (Sandbox Code Playgroud)
但是,如果您有布尔值 NumPy 数组、pandas Series 或 Pandas DataFrames,您也可以使用逐元素按位函数(对于布尔值,它们 - 或者至少应该 - 与逻辑函数无法区分):
np.bitwise_and
或&
运算符np.bitwise_or
或|
运算符np.invert
或别名np.bitwise_not
)或~
运算符np.bitwise_xor
或:或^
运算符通常使用运算符。但是,当与比较运算符结合使用时,必须记住将比较括在括号中,因为按位运算符的优先级高于比较运算符:
(df1 < 10) | (df2 > 10) # instead of the wrong df1 < 10 | df2 > 10
Run Code Online (Sandbox Code Playgroud)
这可能很烦人,因为 Python 逻辑运算符的优先级低于比较运算符,因此您通常编写a < 10 and b > 10
(其中a
和b
是例如简单整数)并且不需要括号。
强调位和逻辑运算仅对布尔 NumPy 数组(以及布尔系列和数据帧)等效,这一点非常重要。如果这些不包含布尔值,则操作将给出不同的结果。我将包括使用 NumPy 数组的示例,但对于 Pandas 数据结构,结果将类似:
>>> import numpy as np
>>> a1 = np.array([0, 0, 1, 1])
>>> a2 = np.array([0, 1, 0, 1])
>>> np.logical_and(a1, a2)
array([False, False, False, True])
>>> np.bitwise_and(a1, a2)
array([0, 0, 0, 1], dtype=int32)
Run Code Online (Sandbox Code Playgroud)
由于 NumPy(以及类似的熊猫)对布尔(布尔或“掩码”索引数组)和整数(索引数组)索引做了不同的事情,索引的结果也会不同:
>>> a3 = np.array([1, 2, 3, 4])
>>> a3[np.logical_and(a1, a2)]
array([4])
>>> a3[np.bitwise_and(a1, a2)]
array([1, 1, 1, 2])
Run Code Online (Sandbox Code Playgroud)
>>> import numpy as np
>>> import pandas as pd
>>> arr = np.array([1,2,3])
>>> s = pd.Series([1,2,3])
>>> df = pd.DataFrame([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> bool(df)
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Run Code Online (Sandbox Code Playgroud)
其中的逻辑运算符不适合与NumPy阵列工作,熊猫系列,和熊猫DataFrames。其他人处理这些数据结构(和普通的 Python 对象)并按元素工作。但是要小心纯 Python bool
s上的按位反转,因为 bool 将在此上下文中被解释为整数(例如~False
返回-1
和~True
返回-2
)。
归档时间: |
|
查看次数: |
137114 次 |
最近记录: |