
在处理大型Pandas DataFrame时,`apply` 函数尤其是在结合自定义Python函数使用时,可能成为性能瓶颈。本文将深入探讨 `apply` 函数效率低下的原因,并提供一种更高效的替代方案:利用Pandas和NumPy的向量化(或广播)能力,显著提升数据处理速度,从而避免耗时的逐行操作,实现更快的计算。
Pandas的 DataFrame.apply() 方法在处理自定义函数时,通常会逐行或逐列迭代数据。当您将一个Python对象的方法或一个普通的Python函数应用到DataFrame的某个Series上时,Pandas需要执行以下操作:
这些重复的类型转换和函数调用,对于拥有数百万行的大型DataFrame而言,会积累成巨大的性能开销,导致脚本执行时间过长。Pandas的设计哲学之一是利用底层的C/Fortran优化代码(通过NumPy),以实现对整个数据集的批量操作,而 apply 在这种情况下打破了这一优势。
Pandas和NumPy的核心优势在于其向量化(vectorization)能力。这意味着许多操作(如加、减、乘、除、比较等)可以直接应用于整个Series或DataFrame,而无需显式地循环遍历每个元素。这些向量化操作在底层由高度优化的C或Fortran代码执行,因此比纯Python循环快得多。
当一个自定义函数可以被重写为接受整个Series作为输入,并返回一个Series作为输出时,我们就可以利用这种向量化能力。
让我们通过一个具体的例子来演示 apply 和向量化操作之间的性能差异。假设我们有一个包含整数的DataFrame,并且有一个自定义类 MyObj,其 move 方法根据一个值和一个偏移量进行计算。
import pandas as pd
import numpy as np
from timeit import timeit
# 创建一个大型DataFrame
df = pd.DataFrame({"col": np.arange(1000000)}) # 增加到100万行以更明显地展示性能差异
class MyObj:
def __init__(self, position):
self.pos = position
def move(self, value, offset):
"""
一个简单的数值计算方法
这个方法既可以接受单个数值,也可以接受一个NumPy数组/Pandas Series
"""
return value * self.pos + offset
# 实例化MyObj
my_obj = MyObj(1)
print("--- 性能对比(1000次迭代)---")
# 方法1: 使用 apply 函数
apply_time = timeit('df["col"].apply(my_obj.move, args=(1,))',
globals=globals(), number=10) # 减少迭代次数,因为apply可能非常慢
print(f"apply 方法耗时: {apply_time:.4f} 秒")
# 方法2: 使用向量化(广播)操作
broadcast_time = timeit('my_obj.move(df["col"], 1)',
globals=globals(), number=1000)
print(f"向量化方法耗时: {broadcast_time:.4f} 秒")
# 验证结果是否一致
result_apply = df["col"].apply(my_obj.move, args=(1,))
result_broadcast = my_obj.move(df["col"], 1)
print(f"结果是否一致: {np.all(result_apply == result_broadcast)}")示例输出(具体数值可能因机器性能而异):
--- 性能对比(1000次迭代)--- apply 方法耗时: 4.5678 秒 向量化方法耗时: 0.0123 秒 结果是否一致: True
从输出中可以清楚地看到,向量化(广播)方法的执行速度比 apply 方法快了几个数量级。这是因为 my_obj.move 方法内部的数学运算 (* 和 +) 能够直接作用于整个Pandas Series (df["col"]),而无需Python的逐元素循环。
当 my_obj.move(df["col"], 1) 被调用时:
整个过程在底层以C语言速度执行,避免了Python解释器的开销。
DataFrame.apply() 函数在处理大型数据集时,特别是结合自定义Python函数时,由于其逐元素迭代和类型转换的特性,效率低下。为了显著提升性能,我们应优先利用Pandas和NumPy的向量化(广播)能力,将操作重构为直接作用于整个Series或DataFrame。通过这种方式,我们可以充分发挥这些库底层优化代码的优势,实现更快速、更高效的数据处理。在无法直接向量化的情况下,可以考虑使用 Numba 等工具进行性能优化。
以上就是优化Pandas DataFrame apply 函数的性能:利用向量化操作的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号