您可以使用1)
pd.eval()
, 2)
df.query()
,或3)
df.eval()
示例将涉及这些数据帧(除非另有规定)。
np.random.seed(0)
df1 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
df2 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
df3 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
df4 = pd.DataFrame(np.random.choice(10, (5, 4)), columns=list('ABCD'))
这是熊猫文档应该包含的“缺失手册”。
pd.eval
df.eval
df.query
呼叫
评估
在三个功能中保持一致,但有一些次要的语义
稍后将突出显示的变体。本节将
介绍所有三个功能中通用的功能-包括(但不限于)
允许的语法、优先规则
和
关键字参数。
可以计算由变量和/或文字组成的算术表达式。这些表达式必须作为字符串传递。所以
回答问题
x = 5
pd.eval("df1.A + (df1.B * x)")
这里需要注意的是:
-
-
df1
,
df2
x
引用全局命名空间中的变量,这些变量由
eval
-
使用属性访问器索引访问特定列。你也可以使用
"df1['A'] + (df1['B'] * x)"
同样的效果。
我将在解释以下内容的章节中讨论重新分配的具体问题:
target=...
属性。但就目前而言,这里有一些更简单的有效操作示例
评估
:
pd.eval("df1.A + df2.A") # Valid, returns a pd.Series object
pd.eval("abs(df1) ** .5") # Valid, returns a pd.DataFrame object
等等条件表达式也以同样的方式得到支持。下面的语句都是有效的表达式,将由引擎计算。
pd.eval("df1 > df2")
pd.eval("df1 > 5")
pd.eval("df1 < df2 and df3 < df4")
pd.eval("df1 in [1, 2, 3]")
pd.eval("1 < 2 < 3")
documentation
. 总之,
-
除左移位外的算术运算(
<<
)右移(
>>
)运营商,例如:。,
df + 2 * pi / s ** 4 % 42
-黄金比率
-
2 < df < df2
-
布尔运算,例如。,
df < df2 and df3 < df4
或
not df_bool
list
和
tuple
[1, 2]
或
(1, 2)
-
属性访问,例如。,
df.a
-
下标表达式,例如。,
df[0]
-
简单变量评估,例如:。,
pd.eval('df')
-
阿尔茨坦2。
本节文档还指定了不受支持的语法规则,包括
set
/
dict
文字、if-else语句、循环和理解以及生成器表达式。
pd.eval('df1.A * (df1.index > 1)')
1a)解析器选择:
parser=...
论点
评估
pandas
和
python
. 两者之间的主要区别在于优先级规则略有不同。
使用默认解析器
,重载的按位运算符
&
和
|
对pandas对象实现矢量化AND和OR操作的运算符优先级与
and
和
or
. 所以
pd.eval("(df1 > df2) & (df3 < df4)")
pd.eval("df1 > df2 & df3 < df4")
# pd.eval("df1 > df2 & df3 < df4", parser='pandas')
也和
pd.eval("df1 > df2 and df3 < df4")
这里,括号是必要的。按照惯例,要做到这一点,将需要paren重写位运算符的更高优先级:
(df1 > df2) & (df3 < df4)
没有这一点,我们最终会
df1 > df2 & df3 < df4
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
parser='python'
pd.eval("(df1 > df2) & (df3 < df4)", parser='python')
这两种解析器之间的另一个区别是
==
和
!=
具有列表和元组节点的运算符,其语义与
in
not in
'pandas'
解析器。例如
pd.eval("df1 == [1, 2, 3]")
是有效的,并将使用与相同的语义运行
pd.eval("df1 in [1, 2, 3]")
奥托,
pd.eval("df1 == [1, 2, 3]", parser='python')
NotImplementedError
1b)后端选择:
engine=...
论点
numexpr
(默认)和
python
numexpr
选项使用
numexpr
对性能进行了优化的后端。
具有
'python'
在后端,表达式的计算类似于将表达式传递给python的
评估
df = pd.DataFrame({'A': ['abc', 'def', 'abacus']})
pd.eval('df.A.str.contains("ab")', engine='python')
0 True
1 False
2 True
Name: A, dtype: bool
不幸的是,这种方法提供了
过去一年的绩效效益
引擎,并且很少有安全措施来确保不计算危险表达式,所以
使用风险自负
“python”
1c)
local_dict
和
global_dict
有时,为表达式中使用但当前未在命名空间中定义的变量提供值很有用。你可以把字典递给我
地方法院
例如:
pd.eval("df1 > thresh")
UndefinedVariableError: name 'thresh' is not defined
thresh
pd.eval("df1 > thresh", local_dict={'thresh': 10})
当您需要从字典中提供变量时,这非常有用。或者,使用
引擎,您可以简单地执行以下操作:
mydict = {'thresh': 5}
# Dictionary values with *string* keys cannot be accessed without
# using the 'python' engine.
pd.eval('df1 > mydict["thresh"]', engine='python')
但这可能是
很
'numexpr'
引擎并将字典传递给
地方法院
全球规则
. 希望这能为使用这些参数提供令人信服的理由。
target
(+
inplace
这通常不是一个要求,因为通常有更简单的方法,但您可以指定
评估
__getitem__
例如
字典
考虑问题中的例子
x = 5
df2['D'] = df1['A'] + (df1['B'] * x)
将列“D”指定给
是的
pd.eval('D = df1.A + (df1.B * x)', target=df2)
A B C D
0 5 9 8 5
1 4 3 0 52
2 5 0 2 22
3 8 1 3 48
4 3 7 0 42
(但它可以……继续读下去)。再举一个例子:
pd.eval('df1.A + df2.A')
0 10
1 11
2 7
3 16
4 10
dtype: int32
目标
论点如下:
df = pd.DataFrame(columns=list('FBGH'), index=df1.index)
df
F B G H
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN NaN NaN NaN
4 NaN NaN NaN NaN
df = pd.eval('B = df1.A + df2.A', target=df)
# Similar to
# df = df.assign(B=pd.eval('df1.A + df2.A'))
df
F B G H
0 NaN 10 NaN NaN
1 NaN 11 NaN NaN
2 NaN 7 NaN NaN
3 NaN 16 NaN NaN
4 NaN 10 NaN NaN
如果你想对基因进行原位突变
df
设置
inplace=True
pd.eval('B = df1.A + df2.A', target=df, inplace=True)
# Similar to
# df['B'] = pd.eval('df1.A + df2.A')
df
F B G H
0 NaN 10 NaN NaN
1 NaN 11 NaN NaN
2 NaN 7 NaN NaN
3 NaN 16 NaN NaN
4 NaN 10 NaN NaN
如果
是没有目标的,一个
ValueError
而
目标
如果你想这样做的话
评估
,您将使用包含赋值的表达式:
df = df.eval("B = @df1.A + @df2.A")
# df.eval("B = @df1.A + @df2.A", inplace=True)
df
F B G H
0 NaN 10 NaN NaN
1 NaN 11 NaN NaN
2 NaN 7 NaN NaN
3 NaN 16 NaN NaN
4 NaN 10 NaN NaN
笔记
什么之中的一个
评估
的非预期用途是以非常类似的方式解析文本字符串
ast.literal_eval
:
pd.eval("[1, 2, 3]")
array([1, 2, 3], dtype=object)
它还可以使用
发动机:
pd.eval("[[1, 2, 3], [4, 5], [10]]", engine='python')
[[1, 2, 3], [4, 5], [10]]
和字符串列表:
pd.eval(["[1, 2, 3]", "[4, 5]", "[10]"], engine='python')
[[1, 2, 3], [4, 5], [10]]
但是,问题在于长度大于100的列表:
pd.eval(["[1]"] * 100, engine='python') # Works
pd.eval(["[1]"] * 101, engine='python')
AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis'
here
.
如上所述,
评估
评估
v0.23 source code
这表明:
def eval(self, expr, inplace=False, **kwargs):
from pandas.core.computation.eval import eval as _eval
inplace = validate_bool_kwarg(inplace, 'inplace')
resolvers = kwargs.pop('resolvers', None)
kwargs['level'] = kwargs.pop('level', 0) + 1
if resolvers is None:
index_resolvers = self._get_index_resolvers()
resolvers = dict(self.iteritems()), index_resolvers
if 'target' not in kwargs:
kwargs['target'] = self
kwargs['resolvers'] = kwargs.get('resolvers', ()) + tuple(resolvers)
return _eval(expr, inplace=inplace, **kwargs)
评估
创建参数,进行少量验证,并将参数传递给
评估
有关更多信息,请阅读:
when to use DataFrame.eval() versus pandas.eval() or python eval()
使用差异
带数据帧的表达式与系列表达式
对于与整个数据帧关联的动态查询,您应该更喜欢
. 例如,没有简单的方法来指定
pd.eval("df1 + df2")
当你打电话的时候
df1.eval
df2.eval
.
2a2)
指定列名
df1
,你会打电话吗
使用以下表达式:
pd.eval("df1.A + df1.B")
使用df.eval,只需提供列名:
df1.eval("A + B")
因为,在
df1
,显然“A”和“B”指的是列名。
您还可以使用引用索引和列
index
(除非索引已命名,否则您将使用该名称)。
df1.eval("A + index")
使用变量的表达式中索引的级别
它代表“
我
无损检测
k级
“.IOW,上面的表达式可以写成
df1.eval("A + ilevel_0")
.
这些规则也适用于
.
访问本地/全局命名空间中的变量
A = 5
df1.eval("A > @A")
同样的道理也适用于
query
.
不用说,列名必须遵循python中有效标识符命名的规则,才能在内部访问
评估
here
有关命名标识符的规则列表。
2a4)
一个鲜为人知的事实是
查询
没有)。例如,要在df1中基于对某些列的一些算术运算创建两个新列“E”和“F”,并基于先前创建的“E”和“F”创建第三列“G”,我们可以这样做
df1.eval("""
E = A + B
F = @df2.A + @df2.B
G = E >= F
""")
A B C D E F G
0 5 0 3 3 5 14 False
1 7 9 3 5 16 7 True
2 2 4 7 6 6 5 True
3 8 8 1 6 16 9 True
4 7 7 8 1 14 10 True
3)
vs
查询
这有助于思考
作为使用
评估
作为一个子程序。
查询
(顾名思义)用于计算条件表达式(即,导致真/假值的表达式)并返回与
True
后果然后将表达式的结果传递给
loc
(在大多数情况下)返回满足表达式的行。根据文件,,
此表达式的计算结果首先传递给
DataFrame.loc
如果由于多维密钥而失败
(例如,数据帧)然后将结果传递给
DataFrame.__getitem__()
.
此方法使用顶级
pandas.eval()
已通过查询。
和
评估
如上所述,这两者之间的关键区别在于它们如何处理表达式结果。当您实际通过这两个函数运行表达式时,这一点变得很明显。例如,考虑
df1.A
0 5
1 7
2 2
3 8
4 7
Name: A, dtype: int32
df1.B
0 9
1 3
2 0
3 1
4 7
Name: B, dtype: int32
获取“A”>所在的所有行中的“B”
,我们会使用
评估
m = df1.eval("A >= B")
m
0 True
1 False
2 False
3 True
4 True
dtype: bool
m
表示通过计算表达式“A>=B”生成的中间结果。然后我们使用遮罩进行过滤
df1
:
df1[m]
# df1.loc[m]
A B C D
0 5 0 3 3
3 8 8 1 6
4 7 7 8 1
但是,
,中间结果“m”直接传递给
loc
,因此
查询
,你只需要
df1.query("A >= B")
A B C D
0 5 0 3 3
3 8 8 1 6
4 7 7 8 1
确切地
df1_big = pd.concat([df1] * 100000, ignore_index=True)
%timeit df1_big[df1_big.eval("A >= B")]
%timeit df1_big.query("A >= B")
14.7 ms ± 33.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
14.7 ms ± 24.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
但后者更简洁,在一个步骤中表达相同的操作。
请注意,你也可以做一些奇怪的事情
查询
df1.query("index")
# Same as df1.loc[df1.index] # Pointless,... I know
A B C D
0 5 0 3 3
1 7 9 3 5
2 2 4 7 6
3 8 8 1 6
4 7 7 8 1
但是不要。
底线:请使用
查询
基于条件表达式查询或筛选行时。