如何使用Pandas Dataframe列解析和评估数学表达式?

5
我希望能够解析这样的表达式:
result = A + B + sqrt(B + 4)

其中A和B是数据框的列。因此,为了获得结果,我必须解析表达式:

new_col = df.B + 4
result = df.A + df.B + new_col.apply(sqrt)

其中df是数据框。

我尝试过使用re.sub,但最好只替换列变量(而不是函数),如下所示:

import re

def repl(match):
    inner_word = match.group(1)
    new_var = "df['{}']".format(inner_word)
    return new_var

eq = 'A + 3 / B'
new_eq = re.sub('([a-zA-Z_]+)', repl, eq)
result = eval(new_eq)

所以,我的问题是:

  • 是否有一个用于此的Python库?如果没有,我如何简单地实现它?
  • 创建递归函数可能是解决方案吗?
  • 如果我使用“逆波兰表示法”,是否可以简化解析过程?
  • 我是否需要使用ast模块?

你尝试过 result = df["A"] + df["B"] + sqrt(df["B"] + 4) 吗?它应该可以工作。 - Dimuth Tharaka Menikgama
@DimuthTharakaMenikgama 请仔细阅读完整的问题,它不仅仅是相同的表达式。 - bhansa
你能展示一下你的数据框(至少几行)吗? - Dimuth Tharaka Menikgama
如果我按照你所说使用 sqrt 函数,我会得到这个错误 TypeError: cannot convert the series to <class 'float'>, 因此必须使用 apply 来调用该函数。 - ChesuCR
数据框中可以有float64值,int32值,甚至是numpy.nan值。 - ChesuCR
2个回答

9

Pandas数据框确实有eval函数。使用您的示例方程式:

import pandas as pd
# create an example DataFrame to work with
df = pd.DataFrame({"A": [1, 2], "B": [3, 4]})
# define equation
eq = 'A + 3 / B'
# actual computation
df.eval(eq)

# more complicated equation
eq = "A + B + sqrt(B + 4)"
df.eval(eq)

警告

请注意,eval 允许运行任意代码,如果你将用户输入传递给此函数,可能会使你易受代码注入攻击的威胁。


非常感谢!它运行得很好。我想使用其他函数,但我已经阅读了这个:“支持的数学函数是sin、cos、exp、log、expm1、log1p、sqrt、sinh、cosh、tanh、arcsin、arccos、arctan、arccosh、arcsinh、arctanh、abs和arctan2”。所以我担心只能使用这些函数。是否可以将外部函数添加到表达式中?使用内置的Python eval()函数可以使用local字典将函数添加为对象,但我无法使其与df.eval()一起工作。 - ChesuCR
我已经写了另一个问题来处理这个。 - ChesuCR
1
请在此处添加警告。eval()允许运行任意代码。如果在未经过净化的字符串上调用eval,则可能会带来危险!eval() 这允许_eval_运行任意代码,如果将用户输入传递给此函数,则可能使您容易受到代码注入攻击。 - Tom Myddeltyn
1
你是对的,@Tom。我会在答案中加上警告。谢谢。 - ChesuCR

1

跟随@uuazed提供的示例,更快的方法是使用numexpr

import pandas as pd
import numpy as np
import numexpr as ne

df = pd.DataFrame(np.random.randn(int(1e6), 2), columns=['A', 'B'])
eq = "A + B + sqrt(B + 4)"
timeit df.eval(eq)
# 15.9 ms ± 177 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
timeit A=df.A; B=df.B; ne.evaluate(eq)
# 6.24 ms ± 396 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

numexpr 也可能支持更多的操作


它更快,但你需要提前知道你要使用的变量。如果不知道,你必须在评估之前进行一些解析,这会花费时间。 - ChesuCR
如果您查看eval文档,默认的enginenumexpr - ChesuCR
是的,说得好!很好奇通过评估产生的长时间差异。 - avelo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接