如何优化计算NFL传球出手时长的双层循环代码效率?
优化NFL进攻回合数据处理的高效方案
原代码的性能瓶颈分析
你的双层循环效率低下的核心原因:
- 每次循环都对DataFrame执行切片操作,这类逐元素的操作在pandas里属于高开销操作,数据量较大时累计耗时会急剧增加。
- 循环内重复执行时间格式转换、
iloc取值,完全没用到pandas的矢量化运算优势。 - 冗余的
print语句会进一步拖慢执行速度。 - 宽泛的
except捕获所有异常,既不利于排查问题,也可能导致错误数据混入结果。
高效实现方案(基于pandas矢量化操作)
直接用pandas的分组、透视等内置函数替代循环,所有操作批量执行,性能能提升几个数量级:
import pandas as pd # 1. 合并所有周的数据,去掉外层循环 all_weeks = pd.concat(weeks, ignore_index=True) # 2. 一次性转换时间格式(矢量化操作,比循环内逐个转换快得多) all_weeks['datetime'] = pd.to_datetime(all_weeks['time'].str.replace('T', ' '), format="%Y-%m-%d %H:%M:%S.%f") # 3. 只保留需要的事件类型,减少后续处理的数据量 filtered_data = all_weeks[all_weeks['event'].isin(['ball_snap', 'pass_forward'])] # 4. 按playId分组,把每个play的两个事件时间转为列 pivoted_data = filtered_data.pivot( index='playId', columns='event', values='datetime' ).reset_index() # 5. 计算QB持球时长,自动跳过缺失任一事件的play pivoted_data['time_to_throw'] = (pivoted_data['pass_forward'] - pivoted_data['ball_snap']).dt.total_seconds() # 6. 生成最终结果DataFrame,丢弃无效数据 df_ttt = pivoted_data[['playId', 'time_to_throw']].dropna(subset=['time_to_throw'])
关键优化点说明
- 合并数据:把所有周的数据合并成一个DataFrame,避免重复处理相同逻辑。
- 矢量化时间转换:
pd.to_datetime和str.replace都是批量操作,比循环内逐个调用datetime.strptime效率高几十倍。 - 透视表替代内层循环:
pivot直接按playId聚合两个事件的时间,不用逐个遍历playId。 - 清晰处理异常:
dropna自动过滤缺少ball_snap或pass_forward记录的play,替代原代码的try-except,逻辑更透明。
内容的提问来源于stack exchange,提问作者Dozer
相关产品推荐
相关产品推荐

