Pandas优化迭代:大DataFrame序列占比计算提速方案咨询
Pandas大DataFrame提速方案:替换逐行循环为向量化操作
你的代码处理85万行耗时10秒的核心原因是逐行循环+df.at逐行赋值——df.at每次操作都会触发DataFrame内部的索引更新和数据校验,85万次调用的累积开销极其高昂。以下是完全基于Pandas向量化操作的优化方案,能将耗时压缩到毫秒级。
优化思路
利用Pandas的**游程编码(Run-Length Encoding)**将连续相同的Phase值分组,通过分组统计和高效匹配计算目标占比,最后用向量化填充完成列赋值,全程避免显式Python循环。
完整优化代码
import pandas as pd import time t1 = time.time() # 1. 生成连续相同Phase的分组ID(游程编码) df['group_id'] = df['Phase'].ne(df['Phase'].shift()).cumsum() # 2. 统计每个分组的核心信息:Phase值、长度、最后一行索引 group_info = df.groupby('group_id').agg( phase=('Phase', 'first'), length=('Phase', 'count'), end_idx=('Phase', 'last') ).reset_index() # 3. 筛选所有Phase=1的分组,匹配其最近的Phase=0分组并计算占比 groups_0 = group_info[group_info['phase'] == 0][['group_id', 'length']].rename(columns={'length': 'len_0'}) groups_1 = group_info[group_info['phase'] == 1].copy() # 用merge_asof高效匹配最近的前置0分组 groups_1 = pd.merge_asof(groups_1, groups_0, on='group_id', direction='backward') # 计算占比:仅当存在有效0分组时计算,否则保持0 groups_1['ratio'] = groups_1.apply( lambda x: (x['len_0'] / (x['len_0'] + x['length'])) * 100 if pd.notna(x['len_0']) else 0, axis=1 ) # 4. 初始化并填充Ratio列 df['Ratio'] = 0 # 在1分组结束的位置设置对应占比 df.loc[groups_1['end_idx'], 'Ratio'] = groups_1['ratio'].values # 向前填充:后续行自动继承最近一次更新的占比 df['Ratio'] = df['Ratio'].ffill() # 清理中间列(可选) df.drop(columns='group_id', inplace=True) print("Elapsed: %.2f seconds" % (time.time() - t1))
关键优化点说明
- 游程编码分组:用
df['Phase'].ne(df['Phase'].shift()).cumsum()快速生成连续相同值的分组ID,将85万行数据压缩为远更少的分组数; - 高效匹配:
pd.merge_asof是专门用于有序数据的最近邻匹配方法,比手动循环查找前置分组快几个数量级; - 向量化填充:
ffill()(向前填充)是Pandas内部优化的向量化操作,完全替代逐行赋值的低效逻辑; - 避免逐行操作:所有核心计算都基于分组统计和批量赋值,彻底消除Python循环的开销。
内容的提问来源于stack exchange,提问作者KR51K
相关产品推荐
相关产品推荐

