繁体   English   中英

将 lambda 与命名 function 应用到 pandas ZBA834BA059A97EB88 之间的性能差异

[英]Performance difference between applying lambda vs. named function to a pandas DataFrame

我开始确定 lambda 表达式在应用于 pandas DataFrame 时是否比命名函数慢或快,没想到会发现实质性差异。 令我惊讶的是,在以下示例中,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)

一般来说,它们是等价的。 有人认为 lambda 稍微快一些

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

%%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 等非矢量化代码中, df.apply必须单独编译每个操作。 在 lambda 示例中,我们强制 python 在np.roundcmath.sqrt操作之间切换。 切换会导致更长的执行时间。

为了真正改进,我们可以对大部分 function 进行矢量化。 (我没有对 cmath.sqrt 进行矢量化。可能会找到等效的 function,但我假设您使用它是有原因的,所以我不理会它。)

 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 倍。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM