如何高效统计大数据集下多维度移动操作的频次?
大规模数据集分组统计优化方案
问题描述
我有一个规模较大的数据集,包含超过1000种唯一产品,结构如下:
| Hour | Date | Pallet ID | PRODUCT | Move Type |
|---|---|---|---|---|
| 1 PM | 10/01 | 101 | Shoes | Storage |
| 1 PM | 10/01 | 202 | Pants | Load |
| 1 PM | 10/01 | 101 | Shoes | Storage |
| 1 PM | 10/01 | 101 | Shoes | Load |
| 1 PM | 10/01 | 202 | Pants | Storage |
| 3 PM | 10/01 | 202 | Pants | Storage |
| 3 PM | 10/01 | 101 | Shoes | Load |
| 3 PM | 10/01 | 202 | Pants | Storage |
需要生成按Hour、Date、Pallet ID、PRODUCT、Move Type分组,统计对应操作总次数(Total Moves)的新表,结果如下:
| Hour | Date | Pallet ID | PRODUCT | Move Type | Total Moves |
|---|---|---|---|---|---|
| 1 PM | 10/01 | 101 | Shoes | Storage | 2 |
| 1 PM | 10/01 | 101 | Shoes | Load | 1 |
| 1 PM | 10/01 | 202 | Pants | Load | 1 |
| 1 PM | 10/01 | 202 | Pants | Storage | 1 |
| 3 PM | 10/01 | 101 | Shoes | Load | 1 |
| 3 PM | 10/01 | 202 | Pants | Storage | 2 |
低效实现(嵌套循环)
我尝试用嵌套循环实现,但代码运行数小时,效率极低:
listy = df['PROD_CODE'].unique().tolist() calc_df = pd.DataFrame() count = 0 for x in listy: new_df = df.loc[df['PROD_CODE'] == x] dates = new_df['Date'].unique().tolist() count = count + 1 print(f'{count} / {len(listy)} loops have been completed') for z in dates: dates_df = new_df[new_df['Date'] == z] hours = new_df['Hour'].unique().tolist() for h in hours: hours_df = dates_df.loc[new_df['Hour'] == h] hours_df[['Hour','Date','PALLET_ID','PROD_CODE','CASE_QTY','Move Type']] hours_df['Total Moves'] = hours_df.groupby('Move Type')['Move Type'].transform('count') calc_df = calc_df.append(hours_df,ignore_index=False)
高效解决方案
直接使用Pandas的向量化分组方法,完全避免嵌套循环,效率提升显著:
方法1:生成去重后的汇总表
如果只需要最终的分组统计结果,一行代码即可完成:
# 按指定字段分组,统计每组数量,并重命名统计列 result_df = df.groupby( ['Hour', 'Date', 'Pallet ID', 'PRODUCT', 'Move Type'], as_index=False ).size().rename(columns={'size': 'Total Moves'})
方法2:保留原始行并添加统计列
如果需要给原始数据的每一行都标注对应分组的操作次数,用transform实现:
# 给原数据添加分组统计列 df['Total Moves'] = df.groupby( ['Hour', 'Date', 'Pallet ID', 'PRODUCT', 'Move Type'] )['Move Type'].transform('count') # 如需去重后的结果,执行以下语句 result_df = df.drop_duplicates(subset=['Hour', 'Date', 'Pallet ID', 'PRODUCT', 'Move Type'])
原代码低效原因
- 嵌套循环完全浪费了Pandas的向量化优势,Python循环效率远低于C实现的内置方法
- 反复调用
df.append()会频繁创建新DataFrame,内存开销极大 - 内层循环存在索引错误:
hours_df = dates_df.loc[new_df['Hour'] == h]中,过滤条件应该用dates_df['Hour']而非new_df['Hour'],额外增加了无效计算
内容的提问来源于stack exchange,提问作者Ronald Johnson
相关产品推荐
相关产品推荐

