本文共 1652 字,大约阅读时间需要 5 分钟。
在数据分析工作中,Pandas的循环操作一直是一个争议的话题。对于小型DataFrame,循环虽然方便,但效率很低。而当面对大型数据时,问题就更加明显了。德国数据分析师Benedikt Droste曾经在实际项目中遇到了巨大的性能瓶颈,他决定寻找更高效的解决方案,从而实现了循环速度的显著提升。
传统的Python循环在处理Pandas DataFrame时效率非常低下。即使是处理较小的数据,循环也会显得缓慢。此外,当数据规模扩大时,问题会更加严重。Benedikt在处理2016-2019赛季的足球赛数据时,发现传统循环的效率非常低下,完成任务的时间甚至高达20.7秒。
为了解决这一问题,Benedikt尝试了多种优化方法,逐一验证了它们的效率。以下是他探索的几个关键步骤:
Pandas的iterrows()方法可以快速遍历DataFrame的行数据。它返回一个索引对的形式,这使得循环比普通的for循环更高效。在Benedikt的案例中,使用iterrows()的效率提升了321倍,运行时间从20.7秒降低到了68毫秒。
Pandas的apply()方法可以与DataFrame配合使用,通过指定axis参数,可以显著提升效率。Benedikt发现,当apply执行在Cython空间时,其速度远高于普通循环。在他的案例中,完成时间仅为27毫秒,比iterrows()方法快41倍。
为了进一步提升效率,Benedikt采用了Pandas的向量化能力。他通过直接操作DataFrame列,避免了传统的Python循环。这种方法的效率达到了前所未有的水平,完成时间仅为68毫秒。
为了更高效地利用内存,Benedikt将Pandas列转换为Numpy数组。Numpy的内存对齐和局部性优势使得其在数据处理方面速度大大提升。最终,他的代码运行时间仅为0.305毫秒,比传统循环快71803倍。
通过对比多种优化方法,Benedikt得出以下结论:
apply方法:如果必须使用循环,可以选择apply来提升效率,但这并不是最佳选择。在实际操作中,Benedikt使用以下代码实现了优化:
def soc_iter(TEAM, home, away, ftr): df.loc[((home == TEAM) & (ftr == 'D')) | ((away == TEAM) & (ftr == 'D'))] = 'Draw' df.loc[((home == TEAM) & (ftr != 'D')) | ((away == TEAM) & (ftr != 'D'))] = 'No_Draw' df.loc[~(((home == TEAM) & (ftr == 'D')) | ((away == TEAM) & (ftr == 'D'))), ~(((home == TEAM) & (ftr != 'D')) | ((away == TEAM) & (ftr != 'D')))] = 'No_Game'
通过将数据转换为Numpy数组,Benedikt实现了代码的高效运行。这种方法不仅避免了传统循环的低效,还充分发挥了Pandas和Numpy的向量化能力。
Benedikt Droste的经历证明了数据分析中循环优化的重要性。通过合理选择优化方法,可以显著提升效率,实现更高效的数据处理。对于Pandas用户来说,尽量避免传统循环,而是选择更高效的向量化方法,是提升性能的关键。
转载地址:http://zvvfk.baihongyu.com/