pandas DataFrame apply中lambda与命名函数的性能差异咨询
性能差异的核心来源
你观察到的速度差距和lambda与命名函数的语言层面差异完全无关,更不是什么普遍存在的特性——只要两个函数的计算逻辑完全等价,lambda生成的匿名函数和def定义的命名函数在pandas的apply场景下,执行速度没有可测量的区别。
你测试里lambda版本更慢,本质是这个lambda的代码本身写了大量无意义的重复计算:
- 没有任何临时变量存储中间值,每次用到列值都重复通过
x['列名']访问,反复触发字典式的行索引查找 - 判别式
(b**2 -4*a*c)的逻辑完整写了两遍,同一个值算了两次 cmath.sqrt重复调用了两次- 最明显的逻辑bug是:返回的两个根用了完全相同的计算公式,本该计算
-b + sqrt(dis)的分支根本没写,相当于多跑了一整遍完全没有产出的计算流程
这种冗余带来的性能损耗,哪怕你把这段逻辑用def写成正式的命名函数,运行速度也会和你写的lambda版本一样慢。可以做个简单的对照实验:
# 完全照搬你lambda逻辑的命名函数 def redundant_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) ) # 用这个函数跑apply,耗时会和lambda版本几乎完全一致
为什么普遍不会出现lambda比命名函数慢的情况
从Python解释器的实现层面看,lambda和def生成的函数对象没有本质区别:
- 除了lambda生成的函数默认
__name__是<lambda>,二者的字节码结构、函数调用流程、参数传递逻辑完全一致 - 不存在解释器对匿名函数的特殊优化或额外开销
只要你把lambda的逻辑调整成和之前的命名函数完全等价的写法,去掉所有重复计算,二者的性能差会直接落到测量误差范围内:
# 和命名函数计算逻辑完全一致的lambda实现 df['roots_lambda_fixed'] = df.apply( lambda x: ( lambda a, b, c: ( np.round((-b - cmath.sqrt(b**2 - 4*a*c))/(2*a), 2), np.round((-b + cmath.sqrt(b**2 - 4*a*c))/(2*a), 2) ) )(x['col1'], x['col2'], x['col3']), axis=1 )
容易被混淆的性能误区
很多人在测pandas的apply性能时,经常把代码本身的冗余错归因到lambda的特性上。实际上pandas的apply本质是逐行循环调用你传入的函数,不管你传的是def定义的函数还是lambda生成的匿名函数,单次调用的框架级开销是完全一样的。真正影响速度的永远是函数内部的计算逻辑:有没有重复计算、有没有不必要的列访问、有没有把本该批量向量化的操作拆成逐行执行——这些问题和你用什么形式定义函数没有任何关系。
内容的提问来源于stack exchange,提问作者pakpe
相关产品推荐
相关产品推荐

