我想用一个或条件来过滤我的数据帧,以保持特定列的值超出范围[-0.25,0.25]的行。我尝试了:
df = df[(df['col'] < -0.25) or (df['col'] > 0.25)]
但我得到了错误:
级数的真值不明确。使用a.empty、a.bool()、a.item()、.any()或.all()
我想用一个或条件来过滤我的数据帧,以保持特定列的值超出范围[-0.25,0.25]的行。我尝试了:
df = df[(df['col'] < -0.25) or (df['col'] > 0.25)]
但我得到了错误:
级数的真值不明确。使用a.empty、a.bool()、a.item()、.any()或.all()
当前回答
Pandas使用位&|。此外,每个条件都应该包装在()内。
这是有效的:
data_query = data[(data['year'] >= 2005) & (data['year'] <= 2010)]
但没有括号的相同查询不会:
data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]
其他回答
Pandas使用位&|。此外,每个条件都应该包装在()内。
这是有效的:
data_query = data[(data['year'] >= 2005) & (data['year'] <= 2010)]
但没有括号的相同查询不会:
data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]
这个出色的答案很好地解释了正在发生的事情,并提供了解决方案。我想添加另一种可能适用于类似情况的解决方案:使用查询方法:
df = df.query("(col > 0.25) or (col < -0.25)")
请参见索引和选择数据。
(我目前正在使用的数据帧的一些测试表明,这种方法比在一系列布尔运算中使用逐位运算符要慢一点:2毫秒对870µs)
一条警告:至少有一种情况是列名恰好是Python表达式,这一点并不简单。我的列名为WT_38hph_IP_2、WT_38ph_input_2和log2(WT_38kph_IP_2/WT_38lph_input_2),希望执行以下查询:“(log2(WT_38hph_IP_2/WT_38hph_input_3)>1)和(WT_38h ph_IP_2>20)”
我获得了以下异常级联:
键错误:“log2”UndefinedVariableError:未定义名称“log2”ValueError:“log2”不是受支持的函数
我想发生这种情况是因为查询解析器试图从前两列中提取一些内容,而不是用第三列的名称来标识表达式。
这里提出了一种可能的解决方法。
我遇到了同样的错误,并在PySpark数据帧中停滞了几天。由于我比较了两个字段中的整数值,所以通过用0填充na值,我成功地解决了这个问题。
这是初学者在Pandas中创建多个条件时非常常见的问题。一般来说,有两种可能的情况导致此错误:
条件1:Python运算符优先级
有一段布尔索引|索引和选择数据-panda文档解释了这一点:
另一个常见的操作是使用布尔向量来过滤数据。运算符为:| for or,&for and,~ for not。这些必须使用括号进行分组。默认情况下,Python会将df['A']>2&df['B']<3这样的表达式求值为df['A']>(2&df['B'])<3,而所需的求值顺序是(df['A']>2)&(df['B']<3)。
# Wrong
df['col'] < -0.25 | df['col'] > 0.25
# Right
(df['col'] < -0.25) | (df['col'] > 0.25)
有一些可能的方法可以去掉括号,稍后我将介绍这一点。
条件2:操作员/声明不当
正如前面的报价中所解释的,您需要使用| for or、&for and和~ for not。
# Wrong
(df['col'] < -0.25) or (df['col'] > 0.25)
# Right
(df['col'] < -0.25) | (df['col'] > 0.25)
另一种可能的情况是在if语句中使用布尔级数。
# Wrong
if pd.Series([True, False]):
pass
很明显,Python if语句接受类似布尔的表达式,而不是Pandas系列。您应该根据需要使用错误消息中列出的pandas.Series.any或方法将Series转换为值。
例如:
# Right
if df['col'].eq(0).all():
# If you want all column values equal to zero
print('do something')
# Right
if df['col'].eq(0).any():
# If you want at least one column value equal to zero
print('do something')
让我们来讨论在第一种情况下如何避开括号。
使用Pandas数学函数Pandas定义了许多数学函数,包括比较,如下所示:pandas.Series.lt()表示小于;pandas.Series.gt()表示大于;pandas.Series.le()表示小于等于;pandas.Series.ge()表示大于或等于;pandas.Series.ne()表示不相等;pandas.Series.eq()表示相等;因此,您可以使用df=df[(df['col']<-0.25)|(df['col']>0.25)]#等于df=df[df['col'].lt(-0.25)|df['col'].gt(0.25)]使用pandas.Series.between()如果要在两个值之间选择行,可以使用pandas.Series.between:df['col]。between(左,右)等于(左<=df['col'])&(df['cor']<=右);df['col].bween(左,右,包括='left)等于(左<=df['col'])&(df['cor']<右);df['col].bween(left,right,inclusive='right')等于(左<df['col'])&(df['cor']<=右);df['col].bween(左,右,包括='norther')等于(左<df['col'])&(df['cor']<右);df=df[(df['col']>-0.25)&(df['col']<0.25)]#等于df=df[df['col'].介于(-0.25,0.25,包括“任一”)]使用pandas.DataFrame.query()前面引用的文档有一章query()方法很好地解释了这一点。pandas.DataFrame.query()可以帮助您选择带有条件字符串的DataFrame。在查询字符串中,可以使用按位运算符(&和|)及其布尔表(和/或)。此外,可以省略括号,但出于可读性的原因,我不建议使用。df=df[(df['col']<-0.25)|(df['col']>0.25)]#等于df=df.query('col<-0.25或col>0.25')使用pandas.DataFrame.eval()pandas.DataFrame.eval()计算描述DataFrame列操作的字符串。因此,我们可以使用此方法来构建多个条件。语法与pandas.DataFrame.query()相同。df=df[(df['col']<-0.25)|(df['col']>0.25)]#等于df=df[df.eval('col<-0.25或col>0.25')]pandas.DataFrame.query()和pandas.DetaFrame.eval()可以做的事情比我在这里描述的要多。建议您阅读他们的文档并与他们一起玩得开心。
我将尝试给出三种最常见的方法的基准(上面也提到过):
from timeit import repeat
setup = """
import numpy as np;
import random;
x = np.linspace(0,100);
lb, ub = np.sort([random.random() * 100, random.random() * 100]).tolist()
"""
stmts = 'x[(x > lb) * (x <= ub)]', 'x[(x > lb) & (x <= ub)]', 'x[np.logical_and(x > lb, x <= ub)]'
for _ in range(3):
for stmt in stmts:
t = min(repeat(stmt, setup, number=100_000))
print('%.4f' % t, stmt)
print()
结果:
0.4808 x[(x > lb) * (x <= ub)]
0.4726 x[(x > lb) & (x <= ub)]
0.4904 x[np.logical_and(x > lb, x <= ub)]
0.4725 x[(x > lb) * (x <= ub)]
0.4806 x[(x > lb) & (x <= ub)]
0.5002 x[np.logical_and(x > lb, x <= ub)]
0.4781 x[(x > lb) * (x <= ub)]
0.4336 x[(x > lb) & (x <= ub)]
0.4974 x[np.logical_and(x > lb, x <= ub)]
但是,熊猫系列不支持*,NumPy Array比熊猫数据帧快(大约慢1000倍,见数字):
from timeit import repeat
setup = """
import numpy as np;
import random;
import pandas as pd;
x = pd.DataFrame(np.linspace(0,100));
lb, ub = np.sort([random.random() * 100, random.random() * 100]).tolist()
"""
stmts = 'x[(x > lb) & (x <= ub)]', 'x[np.logical_and(x > lb, x <= ub)]'
for _ in range(3):
for stmt in stmts:
t = min(repeat(stmt, setup, number=100))
print('%.4f' % t, stmt)
print()
结果:
0.1964 x[(x > lb) & (x <= ub)]
0.1992 x[np.logical_and(x > lb, x <= ub)]
0.2018 x[(x > lb) & (x <= ub)]
0.1838 x[np.logical_and(x > lb, x <= ub)]
0.1871 x[(x > lb) & (x <= ub)]
0.1883 x[np.logical_and(x > lb, x <= ub)]
注意:添加一行代码x=x.to_numpy()大约需要20µs。
对于喜欢%timeit的人:
import numpy as np
import random
lb, ub = np.sort([random.random() * 100, random.random() * 100]).tolist()
lb, ub
x = pd.DataFrame(np.linspace(0,100))
def asterik(x):
x = x.to_numpy()
return x[(x > lb) * (x <= ub)]
def and_symbol(x):
x = x.to_numpy()
return x[(x > lb) & (x <= ub)]
def numpy_logical(x):
x = x.to_numpy()
return x[np.logical_and(x > lb, x <= ub)]
for i in range(3):
%timeit asterik(x)
%timeit and_symbol(x)
%timeit numpy_logical(x)
print('\n')
结果:
23 µs ± 3.62 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
35.6 µs ± 9.53 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
31.3 µs ± 8.9 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
21.4 µs ± 3.35 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
21.9 µs ± 1.02 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
21.7 µs ± 500 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
25.1 µs ± 3.71 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
36.8 µs ± 18.3 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
28.2 µs ± 5.97 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)