对数据帧应用lambda与命名函数之间的性能差异

2024-06-12 14:16:07 发布

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

我开始确定lambda表达式在应用于pandas数据帧时是比命名函数慢还是快,并不期望发现实质性的差异。令我惊讶的是,在下面的示例中,lambda方法的速度要慢得多。这是否一贯正确?若然,原因为何

import pandas as pd
import numpy as np
import cmath

df = pd.DataFrame(np.random.randint(1,100,(100000,3)), columns=['col1','col2', 'col3'])

#Named function approach:
def quad_roots(row):
    '''Function that calculates roots of a quadratic equation'''
    a = row['col1']; b = row['col2']; c = row['col3']
    dis = (b ** 2) - (4 * a * c)
    root1 = (-b - cmath.sqrt(dis)) / (2 * a)
    root2 = (-b + cmath.sqrt(dis)) / (2 * a)
    return np.round(root1,2), np.round(root2,2)
df['roots_named'] = df.apply(quad_roots, axis=1)

#Lambda approach
df['roots_lambda'] = df.apply(lambda x: ((np.round((-x['col2'] - cmath.sqrt((x['col2'] ** 2) - (4 * x['col1'] * x['col3']))) / (2 * x['col1']),2) ),
                                   (np.round((-x['col2'] - cmath.sqrt((x['col2'] ** 2) - (4 * x['col1'] * x['col3']))) / (2 * x['col1']),2) ))
                                   , axis=1)

Tags: lambdaimportpandasdfasnpsqrtcol2
1条回答
网友
1楼 · 发布于 2024-06-12 14:16:07

一般来说,它们是等价的Some argue lambda is modestly faster

在这两种情况下,这里的差异与lambda与声明语句无关,而是与代码编译脚本的操作顺序有关。为了证明这一点,我们可以使用与lambda相同的语法声明一个函数并比较结果

%%timeit
df.apply(lambda x: ((np.round((-x['col2'] - cmath.sqrt((x['col2'] ** 2) - (4 * x['col1'] * x['col3']))) / (2 * x['col1']),2) ),
                               (np.round((-x['col2'] - cmath.sqrt((x['col2'] ** 2) - (4 * x['col1'] * x['col3']))) / (2 * x['col1']),2) ))
                               , axis=1)

返回

 7.78 s ± 14.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

同时:

 %%timeit
 def consolidated_func(x):
     return ((np.round((-x['col2'] - cmath.sqrt((x['col2'] ** 2) - (4 * x['col1'] * x['col3']))) / (2 * x['col1']),2) ),
            (np.round((-x['col2'] - cmath.sqrt((x['col2'] ** 2) - (4 * x['col1'] * x['col3']))) / (2 * x['col1']),2) )
          )
 df.apply(consolidated_func,axis=1)

返回

 7.79 s ± 30.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

大致相同的性能

代码中的差异可以归结为python的编译方式。在像df.apply这样的非矢量化代码中,Python必须单独编译每个操作。在lambda示例中,我们强制python在np.roundcmath.sqrt操作之间切换。切换会导致更长的执行时间

为了真正改进,我们可以将此函数的大部分向量化。(我没有对cmath.sqrt进行矢量化。也许可以找到一个等价的函数,但我假设您使用它是有原因的,所以我不讨论它。)

 df['dis'] = (df['col2'] ** 2) - (4 * df['col1'] * df['col3'])
 df['root1'] = np.round((-df['col2'] - df['dis'].apply(cmath.sqrt)) / (2 * df['col1']).values,2)
 df['root2'] = np.round((-df['col2'] + df['dis'].apply(cmath.sqrt)) / (2 * df['col1']).values,2)
 
 df['roots_vectorized'] = df[['root1','root2']].apply(tuple,axis=1) # There is probably a better way to do this.

收益率:

 792 ms ± 6.58 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

这将执行时间减少了10倍

相关问题 更多 >