我想使用pd.eval
对一个或多个数据帧列执行算术。具体来说,我想移植以下计算公式的代码:
x = 5
df2['D'] = df1['A'] + (df1['B'] * x)
…使用pd.eval
进行编码。使用pd.eval
的原因是我想自动化许多工作流,因此动态创建它们对我很有用。
我的两个输入数据帧是:
import pandas as pd
import numpy as np
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'))
df1
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
df2
A B C D
0 5 9 8 9
1 4 3 0 3
2 5 0 2 3
3 8 1 3 3
4 3 7 0 1
我试图更好地理解pd.eval
的引擎
和解析器
参数,以确定如何最好地解决我的问题。我已经阅读了文档,但没有向我说明其中的区别。
df2
?x
作为参数?已经有很多很好的教程,但是请记住,在被其简单的语法吸引而疯狂使用eval/query
之前,如果您的数据集的行数少于15000行,则会出现严重的性能问题。
在这种情况下,只需使用df.loc[mask1,mask2]
。
请参阅:通过eval()进行表达式计算
可以使用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
调用pd.eval
胡德。在这三个函数中,行为和用法或多或少是一致的,只有一些小的语义变化将在后面强调。本节将介绍所有三个函数中常见的功能——包括(但不限于)允许的语法、优先级规则和关键字参数。
pd.eval
可以计算由变量和/或文字组成的算术表达式。这些表达式必须作为字符串传递。所以,要回答前面提到的问题,你可以
x = 5
pd.eval("df1.A + (df1.B * x)")
这里需要注意的是:
df1
、df2
和x
引用全局命名空间中的变量,这些变量在解析表达式时由eval
拾取 “df1['A'](df1['B']*x)
达到相同的效果我将在下面解释Target=...
属性的部分中讨论重新分配的具体问题。但是现在,这里有更多使用pd.eval
进行有效操作的简单示例:
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")
详细列出所有支持的功能和语法的列表可以在留档中找到。总之,
本节文档还指定了不受支持的语法规则,包括
set
/dict
文字、if-else语句、循环和理解以及生成器表达式。
从列表中,很明显,您还可以传递涉及索引的表达式,例如
pd.eval('df1.A * (df1.index > 1)')
pd.eval
在解析表达式字符串以生成语法树时支持两种不同的解析器选项:pandas
和python
。两者之间的主要区别在于优先级规则略有不同。
使用默认解析器
pandas
,重载的位运算符
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")
这里,括号是必要的。按照惯例,需要括号来覆盖位运算符的更高优先级:
(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'
,如果您想在计算字符串时与python的实际操作员优先级规则保持一致。
pd.eval("(df1 > df2) & (df3 < df4)", parser='python')
这两种解析器之间的另一个区别是
==
和的语义=
'pandas'
解析器时,带有列表和元组节点的code>运算符,其语义分别与中的
和
中的
相似。例如
pd.eval("df1 == [1, 2, 3]")
是有效的,并将使用与相同的语义运行
pd.eval("df1 in [1, 2, 3]")
OTOH,
pd.eval("df1==[1,2,3]", parser='python')
将抛出一个Not实现错误
错误。
有两个选项-
numexpr
(默认值)和python
。numexpr
选项使用针对性能优化的numexpr后端。
使用Python后端,表达式的计算类似于将表达式传递给Python的
eval
函数。您可以灵活地执行更多的内部表达式,例如字符串操作。
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
不幸的是,这种方法在
Numexpr
引擎上没有性能优势,并且很少有安全措施来确保危险表达式不被计算,所以使用时请自担风险!通常不建议将此选项更改为'python'
,除非您知道自己在做什么。
有时,为表达式中使用但当前未在命名空间中定义的变量提供值很有用。您可以将词典传递给
local\u dict
例如:
pd.eval("df1 > thresh")
UndefinedVariableError: name 'thresh' is not defined
此操作失败,因为未定义阈值。然而,这是可行的:
pd.eval("df1 > thresh", local_dict={'thresh': 10})
当您需要从字典中提供变量时,这非常有用。或者,使用Python引擎,您可以简单地执行以下操作:
mydict = {'thresh': 5}
# Dictionary values with *string* keys cannot be accessed without
# using the 'python' engine.
pd.eval('df1 > mydict["thresh"]', engine='python')
但是这可能比使用
'Numexpr'
引擎并将字典传递给local_dict
或global_dict
要慢得多。希望这将为使用这些参数提供令人信服的论据。
这通常不是一个要求,因为通常有更简单的方法,但是您可以将
pd.eval
的结果分配给实现\uuuu getitem\uuuuu
的对象,例如dict
s和(您猜到的)数据帧。
考虑问题中的例子
x = 5
df2['D'] = df1['A'] + (df1['B'] * x)
要将列“D”分配给
df2
,我们需要
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
这不是对
df2
的就地修改(但可以…继续阅读)。再举一个例子:
pd.eval('df1.A + df2.A')
0 10
1 11
2 7
3 16
4 10
dtype: int32
如果您想(例如)将其分配回DataFrame,您可以使用以下参数:
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
如果在没有目标的情况下设置了
inplace
,则会引发ValueError
。
虽然
target
参数很有趣,但您很少需要使用它。
如果要对
df.eval
执行此操作,可以使用包含赋值的表达式:
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
笔记
pd.eval
的一个非预期用途是以非常类似于ast.literal\u eval
的方式解析文本字符串:
pd.eval("[1, 2, 3]")
array([1, 2, 3], dtype=object)
它还可以使用
'python'
引擎解析嵌套列表:
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'
可以在此处找到此错误的更多信息、原因、修复和解决方法。
如上所述,
df.eval
在引擎盖下调用pd.eval
,并有一些并列的参数。v0.23源代码显示了以下内容:
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)
eval
创建参数,进行少量验证,并将参数传递给pd.eval
。
有关更多信息,请阅读:何时使用DataFrame.eval()与pandas.eval()或Python eval()比较
对于与整个DataFrames关联的动态查询,您应该首选
pd.eval
。例如,当调用df1.eval
或df2.eval
时,没有简单的方法来指定pd.eval("df1 df2")
的等价物。
另一个主要区别是如何访问列。例如,要在
df1
中添加两列“A”和“B”,可以使用以下表达式调用pd.eval
:
pd.eval("df1.A + df1.B")
使用df.eval,只需提供列名:
df1.eval("A + B")
因为,在
df1
的上下文中,很明显"A"和"B"指的是列名。
您还可以使用
index
引用索引和列(除非索引已命名,在这种情况下,您将使用名称)。
df1.eval("A + index")
或者,更一般地,对于索引具有1个或多个级别的任何数据帧,您可以使用变量“ilevel_k”在表达式中引用索引的kth级别,该变量表示“index at level k”。照此,上面的表达式可以写成
df1.eval(“A ilevel_0”)
。
这些规则也适用于
df.query
。
表达式中提供的变量必须在“@”符号之前,以避免与列名混淆。
A = 5
df1.eval("A > @A")
这同样适用于
查询
。
不用说,列名必须遵循Python中有效标识符命名的规则,才能在
eval
中访问。有关命名标识符的规则列表,请参见此处。
一个鲜为人知的事实是,
eval
支持处理赋值的多行表达式(而query
不支持)。例如,要在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
将
df.query
视为使用pd.eval
作为子例程的函数是有帮助的。
通常,
查询
(顾名思义)用于计算条件表达式(即,导致True/False值的表达式),并返回对应于True
结果的行。然后将表达式的结果传递给loc
(在大多数情况下),以返回满足表达式的行。根据留档,
此表达式的计算结果首先传递给
DataFrame.loc
,如果由于多维键(例如,DataFrame)而失败,则结果将传递给DataFrame.\uuu getitem\uuuuu()
。
此方法使用顶级
pandas.eval()
函数来计算传递的查询。
就相似性而言,
查询
和df.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"所在的所有行
m = df1.eval("A >= B")
m
0 True
1 False
2 False
3 True
4 True
dtype: bool
m
表示通过计算表达式“A”生成的中间结果
df1[m]
# df1.loc[m]
A B C D
0 5 0 3 3
3 8 8 1 6
4 7 7 8 1
但是,使用
query
,中间结果“m”直接传递到loc
,因此使用query
,您只需执行以下操作
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)
但是后者更加简洁,在一个步骤中表达了相同的操作。
请注意,您还可以像这样使用
query
执行一些奇怪的操作(例如,返回由df1.index索引的所有行)
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
但是不要。
底线:查询或筛选基于条件表达式的行时,请使用
查询
。
...使用进行编码。使用的原因是我想要自动化许多工作流,因此动态地创建它们对我会很有用。 我的两个输入数据流是: 我试图更好地理解的和参数,以确定如何最好地解决我的问题。我已经看过了文件,但我并不清楚其中的区别。 应使用哪些参数来确保代码以最大性能工作? 是否有方法将表达式的结果赋回到? 另外,为了使事情更加复杂,如何将作为字符串表达式中的参数传递?
问题内容: 在我们的项目中,我们需要在没有任何数据库服务器的情况下评估SQL语句。您能否建议一个免费的Java库,该库能够评估基于数学的SQL语句并返回结果? 例如; 输入 输出 可能会被称为 问题答案: 如下面的代码所示,可以使用ZQL来实现。但是我严重建议您选择一个简单的嵌入式数据库,例如H2(此处为示例),而应使用它(项目运行状况要高得多)。 使用H2: 输出: 要使用它,请将其添加到您的:
问题内容: 对象在Python中评估的真值是多少? 相关问题 Python中对象的布尔值:有关覆盖对象评估方式的讨论 问题答案: 可以测试任何对象的真值,以在if或while条件中使用或用作以下布尔运算的操作数。以下值为“假”: 没有 假 任何数值类型的零,例如,,,。 任何空序列,例如,,。 任何空映射,例如。 用户定义的类的实例,如果该类定义了或方法,则该方法返回整数0或bool value时
问题内容: 我正在寻找一种相对简单的方法(与编写解析器相比)来评估Java中的布尔表达式,并且我不想使用JEP库。 我有一个String表达式,例如:我的目标是用值替换变量。 有没有一种方法可以评估此表达式? 请记住,这可以是任何深度,因此编写解析器将非常复杂。 问题答案: 您可以使用Java6中的脚本引擎,并选择任何流行的脚本语言,例如Scala,Ruby,Python,Groovy和Jav
问题内容: 什么是实现将采用字符串并根据运算符优先级输出结果的python程序的最佳方法(例如:“ 4 + 3 * 5”将输出19)。我在谷歌上寻找解决这个问题的方法,但是它们都太复杂了,我正在寻找一个(相对)简单的方法。 澄清:我需要比eval()稍微先进的东西-我希望能够添加其他运算符(例如,最大运算符-4 $ 2 = 4),或者,我对此在学术上比对专业更感兴趣-我想知道 该怎么 做。 问题答
本文向大家介绍评估后缀表达式,包括了评估后缀表达式的使用技巧和注意事项,需要的朋友参考一下 为了求解数学表达式,我们需要前缀或后缀形式。将中缀转换为后缀后,我们需要后缀评估算法来找到正确的答案。 在这里,我们还必须使用堆栈数据结构来解决后缀表达式。 从后缀表达式中,找到一些操作数后,将它们压入堆栈。找到某个运算符后,将从堆栈中弹出两个项目,并按正确的顺序执行操作。之后,结果也被压入堆栈中以备将来使