何时使用数据帧.eval()与Pandas.eval()或python eval()

2024-09-27 23:16:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我有几十个条件(例如,foo > bar),我需要对DataFrame的~1MM行进行计算,最简洁的编写方法是将这些条件存储为字符串列表,并创建一个DataFrame布尔结果(每个记录一行x每个条件一列)。(正在评估的用户输入是而不是。)

在寻求过早优化的过程中,我试图确定我是应该在DataFrame(例如,df.eval("foo > bar"))内编写这些条件进行求值,还是像eval("df.foo > df.bar")那样将其留给python

根据documentation on enhancing eval performance

You should not use eval() for simple expressions or for expressions involving small DataFrames. In fact, eval() is many orders of magnitude slower for smaller expressions/objects than plain ol’ Python. A good rule of thumb is to only use eval() when you have a DataFrame with more than 10,000 rows.

能够使用df.eval("foo > bar")语法将是一件好事,因为我的列表将更具可读性,但我从来没有找到一个案例,它的评估速度不慢。文档显示了一些例子,其中pandas.eval()比python eval()(这与我的经验相符)快,但是DataFrame.eval()(被列为“实验性的”)没有。在

例如,DataFrame.eval()在一个大的ish DataFrame上的一个不简单的表达式中仍然是一个明显的失败者:

import pandas as pd
import numpy as np
import numexpr
import timeit

someDf = pd.DataFrame({'a':np.random.uniform(size=int(1e6)), 'b':np.random.uniform(size=int(1e6))})

%timeit -n100 someDf.eval("a**b - a*b > b**a - b/a") # DataFrame.eval() on notional expression
%timeit -n100 eval("someDf['a']**someDf['b'] - someDf['a']*someDf['b'] > someDf['b']**someDf['a'] - someDf['b']/someDf['a']")
%timeit -n100 pd.eval("someDf.a**someDf.b - someDf.a*someDf.b > someDf.b**someDf.a - someDf.b/someDf.a")

100 loops, best of 3: 29.9 ms per loop
100 loops, best of 3: 18.7 ms per loop
100 loops, best of 3: 15.4 ms per loop

那么DataFrame.eval()的好处仅仅是简化输入,还是我们可以确定使用这种方法更快的情况?在

对于何时使用哪个eval(),还有其他的指导原则吗?(我知道pandas.eval()不支持完整的操作集。)

^{pr2}$

Tags: ofimportdataframepandasdfforfooeval
1条回答
网友
1楼 · 发布于 2024-09-27 23:16:43

So is the benefit of DataFrame.eval() merely in simplifying the input, or can we identify circumstances where using this method is actually faster?

source code数据帧.eval()显示它实际上只是创建要传递给的参数pd.评估():

def eval(self, expr, inplace=None, **kwargs):

    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)

其中,\u eval()只是的别名pd.评估()在模块开头导入:

^{pr2}$

所以你可以用df.eval()做任何事情,你都可以用pd.eval()+几行额外的行来设置。从目前的情况来看,df.eval()永远不会比pd.eval()快。但这并不意味着df.eval()和{}一样好,但写起来更方便。在

但是,在玩了%prun魔术之后,df.eval()df._get_index_resolvers()的调用给df.eval()方法增加了相当多的时间。最终,_get_index_resolvers()最后调用了.copy().copy()方法,这是最终减慢速度的原因。同时,pd.eval()在某个时候确实调用了numpy.ndarray.copy(),但它花费的时间微不足道(至少在我的机器上)。在

长话短说,df.eval()似乎比pd.eval()慢,因为在引擎盖下,它只是pd.eval()加上额外的步骤,这些步骤是非常重要的。在

相关问题 更多 >

    热门问题