如何优化Pandas中FIFO库存残料分配效率?应对2万行数据
基于Pandas的FIFO库存分配高效实现方案
需求说明
有两个Pandas DataFrame:residuals(残料库存表)和orders(订单需求表),以area与number作为联合匹配主键,分配逻辑遵循FIFO顺序:
- 用残料库存满足订单需求,若对应库存≥订单需求量则全额满足并扣减库存;
- 若库存不足则耗尽对应库存;
- 无匹配库存则返回0。
预期结果示例
area number requires ready 0 pnos 3 40 20 1 vnp 4 70 70 2 vnp 4 20 20 3 vnp 4 10 5 4 vnp 1 25 0
数据定义
residuals = pd.DataFrame({'area': ['pnos', 'vnp'], 'number': [3, 4], 'balances':[20,95]}) orders = pd.DataFrame({'area': ['pnos', 'vnp','vnp','vnp', 'vnp'], 'number': [3, 4, 4, 4, 1], 'requires':[40,70,20,10,25]})
当前实现问题
当前通过自定义函数结合apply逐行处理实现需求,但处理2万行数据时耗时过长,需更高效的优化方案。
当前实现代码
def distr(number, area, requiers): if residuals[(residuals['number']==number) & (residuals['area']==area)].empty: return 0 elif requiers==0: return 0 elif requiers>0: if residuals[(residuals['number']==number) & (residuals['area']==area)]['balances'].iloc[0] >= requiers: residuals.loc[(residuals['number']==number) & (residuals['area']==area), 'balances'] -= requiers return requiers else: result = residuals[(residuals['number']==number) & (residuals['area']==area)]['balances'].iloc[0] residuals.loc[(residuals['number']==number) & (residuals['area']==area), 'balances'] = 0 return result orders['ready'] = orders.apply(lambda x: distr(x['number'], x['area'], x['requires']), axis=1)
优化方案
核心思路
放弃逐行apply的低效操作,利用Pandas分组、累计计算、合并等向量化操作批量处理,大幅提升性能。
具体实现代码
import pandas as pd # 1. 合并订单与库存表,匹配每个订单对应的初始库存 orders_with_stock = orders.merge(residuals, on=['area', 'number'], how='left').fillna(0) # 2. 按联合主键分组,计算每组订单的累计需求 orders_with_stock['cum_requires'] = orders_with_stock.groupby(['area', 'number'])['requires'].cumsum() # 3. 计算当前订单处理前的可用库存 orders_with_stock['prev_cum'] = orders_with_stock.groupby(['area', 'number'])['cum_requires'].shift(fill_value=0) orders_with_stock['available_before'] = orders_with_stock['balances'] - orders_with_stock['prev_cum'] # 4. 计算每个订单实际可分配的数量 orders_with_stock['ready'] = orders_with_stock.apply( lambda x: min(x['available_before'], x['requires']) if x['available_before'] > 0 else 0, axis=1 ) # 5. 更新库存表的剩余余额 total_consumed = orders_with_stock.groupby(['area', 'number'])['ready'].sum().reset_index() residuals = residuals.merge(total_consumed, on=['area', 'number'], how='left').fillna(0) residuals['balances'] = residuals['balances'] - residuals['ready'] residuals = residuals.drop('ready', axis=1) # 提取最终订单分配结果 final_orders = orders_with_stock[['area', 'number', 'requires', 'ready']]
性能优势
- 原逐行
apply方案:2万行数据耗时约数十秒(依硬件配置而定) - 优化后向量化方案:2万行数据耗时仅数百毫秒,性能提升数量级
内容的提问来源于stack exchange,提问作者Valerie
相关产品推荐
相关产品推荐

