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
作为字符串表达式中的参数传递?您可以使用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'))
这是熊猫doc应该包含的“缺失手册”。注意:在讨论的三个函数中,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")
详细说明所有支持的特性和语法的列表可以在文档中找到。总之,
<<
)和右移(>
)运算符以外的算术运算,例如df+2*pi/s**4%42
-the_golden_ratio2
- 布尔运算,例如
df
或
not df_bool
列表
和
元组
文字,例如
[1,2]
或
(1,2)
- 属性访问,例如
df.a
- 下标表达式,例如
df[0]
- 简单变量求值,例如
pd.eval('df')
(这不是很有用) - 数学函数:sin,cos,exp,log,expm1,log1p,sqrt,sinh,cosh,tanh,arcsin,arccos,arctan,arccosh,arcsinh,arctanh,abs和arctan2。
本节文档还指定了不受支持的语法规则,包括
set
/dict
文字、if-else语句、循环和理解以及生成器表达式。
从列表中可以明显看出,您还可以传递涉及索引的表达式,如
pd.eval('df1.A * (df1.index > 1)')
在解析表达式字符串以生成语法树时,
pd.eval
支持两个不同的解析器选项:pandas
和python
。两者之间的主要区别突出表现在略有不同的优先规则上。
使用默认解析器
pandas
,使用pandas对象实现向量化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")
(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().
如果希望在计算字符串时与Python的实际运算符优先级规则保持一致,请使用
parser='python'
。
pd.eval("(df1 > df2) & (df3 < df4)", parser='python')
这两种类型的解析器之间的另一个区别是带有列表和元组节点的
==
和!=
运算符的语义,当使用'pandas'
解析器时,它们分别具有与in
和not in
相似的语义。例如,
pd.eval("df1 == [1, 2, 3]")
是有效的,并将以与
pd.eval("df1 in [1, 2, 3]")
OTOH,
pd.eval(“df1==[1,2,3]”,parser='python')
将引发NOTIMPLENTEDERROR
错误。
有两个选项-
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_dict
例如:
pd.eval("df1 > thresh")
UndefinedVariableError: name 'thresh' is not defined
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')
考虑问题中的例子
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,可以使用
target
参数,如下所示:
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("[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'
有关此错误、原因、修复方法和解决方法的更多信息可以在这里找到。
如上所述,
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()
对于与整个数据流关联的动态查询,您应该首选
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")
表达式中提供的变量必须在前面加上“@”符号,以避免与列名混淆。
A = 5
df1.eval("A > @A")
对于
query
也是如此。
不言而喻,列名必须遵循python中有效标识符命名的规则,才能在
eval
中访问。有关命名标识符的规则列表,请参阅此处。
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
该表达式的求值结果首先传递给
DataFrame.loc
,如果由于多维键(例如DataFrame)而失败,则结果将传递给DataFrame.__GetItem__()
。
此方法使用顶级
pandas.eval()
函数来计算传递的查询。
就相似性而言,
query
和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
要获取
DF1
中“a”>=“b”的所有行,我们将使用eval
如下所示:
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
但是,对于
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)
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
我想使用对一个或多个数据帧列执行算术。具体来说,我想移植以下计算公式的代码: …使用进行编码。使用的原因是我想自动化许多工作流,因此动态创建它们对我很有用。 我的两个输入数据帧是: 我试图更好地理解的和参数,以确定如何最好地解决我的问题。我已经阅读了文档,但没有向我说明其中的区别。 应该使用什么参数来确保我的代码以最大的性能工作? 是否有办法将表达式的结果赋值回? 另外,为了使事情更复杂,我如何在
问题内容: 给定两个数据框 我想使用对一列或多列进行算术运算pd.eval。具体来说,我想移植以下代码: …使用进行编码eval。使用的原因eval是我想自动执行许多工作流程,因此动态创建它们对我很有用。 我试图更好地理解和参数,以确定如何最好地解决我的问题。我已经浏览了文档,但是对我而言,区别并不明显。 应该使用什么参数来确保我的代码以最高性能工作? 有没有一种方法可以将表达式的结果赋值给df2
问题内容: 我引用的数据框如下(是列名): 但是我不想被硬编码,我想要一个变量来使其动态。怎么做? TIA 问题答案: 您可以使用方括号对列进行索引: 因此,当您接受输入为a时,您可以执行以下操作: 此外,将列作为属性访问可能导致模棱两可的行为。如具有列命名,并尝试做这可能要列不同的值,或者如果你有一个名为一样像任何有效的方法DF柱或那么这将导致语法错误。 因此,我强烈建议您使用方括号来选择列。
我正在使用NPOI从Excel2003文件中读取数据。这些文件包含如下公式('1:2'!$C$17)。NPOI识别像SUM('1'!$C$17)这样的公式(W/O表2),并计算无效的结果。我使用的是NPOI示例中的常规代码,比如
问题内容: 什么是实现将采用字符串并根据运算符优先级输出结果的python程序的最佳方法(例如:“ 4 + 3 * 5”将输出19)。我在谷歌上寻找解决这个问题的方法,但是它们都太复杂了,我正在寻找一个(相对)简单的方法。 澄清:我需要比eval()稍微先进的东西-我希望能够添加其他运算符(例如,最大运算符-4 $ 2 = 4),或者,我对此在学术上比对专业更感兴趣-我想知道 该怎么 做。 问题答
本文向大家介绍评估后缀表达式,包括了评估后缀表达式的使用技巧和注意事项,需要的朋友参考一下 为了求解数学表达式,我们需要前缀或后缀形式。将中缀转换为后缀后,我们需要后缀评估算法来找到正确的答案。 在这里,我们还必须使用堆栈数据结构来解决后缀表达式。 从后缀表达式中,找到一些操作数后,将它们压入堆栈。找到某个运算符后,将从堆栈中弹出两个项目,并按正确的顺序执行操作。之后,结果也被压入堆栈中以备将来使