给定两个数据框
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。具体来说,我想移植以下代码:
x = 5
df2['D'] = df1['A'] + (df1['B'] * x)
…使用进行编码eval。使用的原因eval是我想自动执行许多工作流程,因此动态创建它们对我很有用。
我试图更好地理解engine
和parser
参数,以确定如何最好地解决我的问题。我已经浏览了文档,但是对我而言,区别并不明显。
这个答案潜入各种特性和功能的提供pd.eval,df.query
和df.eval
。
设置
示例将涉及这些DataFrame
(除非另有说明)。
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'))
pandas.eval -《失踪手册》
注意
在所讨论的三个功能中,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_ratio
df < df2 and df3 < df4
或)not df_bool list
和tuple
文字(例如[1, 2
]或)(1, 2)
df.a
df[0]
pd.eval('df')
(这不是很有用)文档的此部分还指定了不支持的语法规则,包括set/ dict文字,if-else语句,循环和理解以及生成器表达式。
从列表中可以明显看出,你还可以传递涉及索引的表达式,例如
pd.eval('df1.A * (df1.index > 1)')
解析器选择:parser=…参数
pd.eval
解析表达式字符串以生成语法树时,支持两种不同的解析器选项:pandas
和python
。两者之间的主要区别通过稍有不同的优先级规则突出显示。
使用默认解析器pandas
,重载的逐位运算符&
以及|与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")
在此,括号是必需的。通常,要这样做,需要使用parens来覆盖按位运算符的更高优先级:
(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')
两种类型的解析器之间的另一个区别是带有list
和tuple
节点的==and
!=
运算符的语义,在使用解析器时,它们的语义分别与in和相似。例如,not in'pandas'
pd.eval("df1 == [1, 2, 3]")
有效,并将以与以下相同的语义运行
pd.eval("df1 in [1, 2, 3]")
OTOH,pd.eval(“df1 == [1, 2, 3]”, parser=’python’)将引发NotImplementedError错误。
后端选择:engine=…参数
有两个选项- 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和global_dict论点
有时,为表达式中使用的变量提供值很有用,但当前尚未在名称空间中定义变量。你可以将字典传递给local_dict
例如,
pd.eval("df1 > thresh")
UndefinedVariableError: name 'thresh' is not defined
由于thresh未定义,因此失败。但是,这可行:
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
。希望这应该为使用这些参数提供令人信服的论据。
target(+ inplace)参数,并赋值表达式
这通常不是必需的,因为通常有更简单的方法可以执行此操作,但是你可以将结果分配给pd.eval
实现__getitem__
诸如dicts
和(猜对了)DataFrames
的对象。
考虑问题中的例子
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
则引发a。
尽管该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_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'
有关此错误,原因,修复和解决方法的更多信息,请参见此处。
DataFrame.eval
-与并置 pandas.eval
如上所述,在后台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 v / s系列表达式的表达式
对于与整个DataFrame相关的动态查询,你应该首选pd.eval。例如,没有简单的方法来指定pd.eval(“df1 + df2”)调用df1.eval或时的等效项df2.eval。
指定列名
另一个主要区别是如何访问列。例如,要在中添加两列“ A”和“ B” df1,则可以pd.eval使用以下表达式进行调用:
pd.eval("df1.A + df1.B")
使用df.eval,只需提供列名称:
df1.eval("A + B")
因为在的上下文中df1,很明显“ A”和“ B”是指列名。
你还可以使用引用索引和列index(除非命名索引,否则将使用名称)。
df1.eval("A + index")
或者,更一般地,对于具有1或更多级的索引数据帧的任何,可以参考第k 个使用变量索引的水平在表达“ilevel_k”
表示“ 我 ndex
在等级k
”。IOW
,上面的表达式可以写成df1.eval("A + ilevel_0")
。
这些规则也适用于query
。
在本地/全局命名空间中访问变量
表达式内提供的变量必须以“ @”符号开头,以避免与列名混淆。
A = 5
df1.eval("A > @A")
同样的道理query。
不用说,你的列名必须遵循python
中有效标识符命名的规则,以便在内部访问eval
。有关命名标识符的规则列表,请参见此处。
多行查询和分配
一个鲜为人知的事实是eval支持处理分配的多行表达式。例如,要基于某些列上的某些算术运算在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
真漂亮 但是,请注意,此功能不受支持query
。
evalv / s- query最终词
它有助于将df.query
其pd.eval视为用作子例程的函数。
通常,query
(顾名思义)用于评估条件表达式(即产生True / False
值的表达式)并返回与True结果相对应的行。然后将表达式的结果传递给loc(在大多数情况下)以返回满足表达式的行。根据文档,
该表达式的求值结果首先传递给 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
要获取其中所有“ A”> =“ B”
的行df1
,我们将使用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)
但是后者更为简洁,并且只需一步即可表达相同的操作。
请注意,你也可以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
但是不要。
底线:query
在基于条件表达式查询或过滤行时,请使用。
...使用进行编码。使用的原因是我想要自动化许多工作流,因此动态地创建它们对我会很有用。 我的两个输入数据流是: 我试图更好地理解的和参数,以确定如何最好地解决我的问题。我已经看过了文件,但我并不清楚其中的区别。 应使用哪些参数来确保代码以最大性能工作? 是否有方法将表达式的结果赋回到? 另外,为了使事情更加复杂,如何将作为字符串表达式中的参数传递?
问题内容: 我引用的数据框如下(是列名): 但是我不想被硬编码,我想要一个变量来使其动态。怎么做? TIA 问题答案: 您可以使用方括号对列进行索引: 因此,当您接受输入为a时,您可以执行以下操作: 此外,将列作为属性访问可能导致模棱两可的行为。如具有列命名,并尝试做这可能要列不同的值,或者如果你有一个名为一样像任何有效的方法DF柱或那么这将导致语法错误。 因此,我强烈建议您使用方括号来选择列。
我想使用对一个或多个数据帧列执行算术。具体来说,我想移植以下计算公式的代码: …使用进行编码。使用的原因是我想自动化许多工作流,因此动态创建它们对我很有用。 我的两个输入数据帧是: 我试图更好地理解的和参数,以确定如何最好地解决我的问题。我已经阅读了文档,但没有向我说明其中的区别。 应该使用什么参数来确保我的代码以最大的性能工作? 是否有办法将表达式的结果赋值回? 另外,为了使事情更复杂,我如何在
我是Apache Flink的新手,我正在尝试使用Flink CEP动态评估流中的模式。我正在尝试查找执行以下操作的用户登录、addtocart和注销,并且能够检测到模式,但是如果我定义了多个模式,例如登录,注销,则无法检测到模式 下面是我的代码 动作类 模式类 主类 如果我给出一个模式来评估它的输出,如下所示 如果我试图给多个模式进行评估,如下面所示,它不是评估第二个模式,而是建议我如何评估多个
问题内容: 对象在Python中评估的真值是多少? 相关问题 Python中对象的布尔值:有关覆盖对象评估方式的讨论 问题答案: 可以测试任何对象的真值,以在if或while条件中使用或用作以下布尔运算的操作数。以下值为“假”: 没有 假 任何数值类型的零,例如,,,。 任何空序列,例如,,。 任何空映射,例如。 用户定义的类的实例,如果该类定义了或方法,则该方法返回整数0或bool value时
问题内容: 我正在尝试使用Mongoose制作动态条件,但是它并没有像我想象的那样起作用。 代码是这样的 如您所见,我正在尝试使用“索引”变量创建动态条件。有可能这样做吗? 先感谢您! 问题答案: 您需要分两步创建对象: 更新资料 现在,node.js 4+支持计算的属性名称,您可以一步完成此操作: