如何高效获取pandas DataFrame各file_number分组下phase=3的最后N行
测试数据生成
我们使用如下代码生成测试用DataFrame:
import pandas as pd import numpy as np d = {'p1': np.random.rand(32), 'a1': np.random.rand(32), 'phase': [0,0,0,0, 1,1,1,1, 2,2,2,2, 3,3,3,3, 0,0,0,0, 1,1,1,1, 2,2,2,2, 3,3,3,3], 'file_number': [1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2] } df = pd.DataFrame(d)
需求说明
对每个file_number分组,phase值为0、1、2的子组保留全部行,仅phase值为3的子组取最后N行。
原有实现问题
现有双层循环实现代码如下:
def phase_3_last_n_observations(df, n): result = [] for fn in df['file_number'].unique(): file_df = df[df['file_number']==fn] for phase in [0,1,2,3]: phase_df = file_df[file_df['phase']==phase] if phase == 3: phase_df = phase_df[-n:] result.append(phase_df) df = pd.concat(result, axis=0) return df phase_3_last_n_observations(df, 2)
该实现依赖Python层面的双层循环,处理TB级数据时迭代开销极高,运行速度极慢。
优化方案
直接使用pandas原生向量化API替代Python循环,所有计算逻辑下沉到C层面执行,性能提升显著,代码如下:
def phase_3_last_n_observations(df, n): # 拆分出phase不为3的部分,直接全量保留 df_normal = df[df['phase'] != 3] # 拆分出phase为3的部分,按file_number分组后取每组最后n行 df_phase3 = df[df['phase'] == 3].groupby('file_number', group_keys=False).tail(n) # 合并两部分后按原始索引排序,保留原数据顺序 return pd.concat([df_normal, df_phase3]).sort_index()
优化效果说明
- 完全规避Python层面循环开销,处理大数据量时速度比原实现提升至少两个数量级
- 内存占用更低,不需要逐次拆分存储子表后再合并,中间临时对象数量大幅减少
- 输出结果与原实现完全一致
内容的提问来源于stack exchange,提问作者Evangelista01
相关产品推荐
相关产品推荐

