You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas大数据量下库存预测DataFrame操作性能优化求助

优化Pandas库存预测代码的性能方案

嘿,作为Pandas新手能写出实现功能的代码已经很棒了!嵌套循环在数据量小的时候没问题,但面对10万级别的数据时,逐行操作的时间复杂度会让速度骤降。咱们用向量化操作和高效数据合并来重构逻辑,性能会提升好几个数量级,代码也更简洁易维护。

原代码的核心问题

你的嵌套循环+每次循环内的loc查询,本质是Python层面的逐行处理,而Pandas的优势在于底层C实现的向量化操作,能批量处理数据,避免循环的开销。另外原代码还有个小bug:if len(df_purchase_orders.index) > 0应该判断的是匹配到的订单数量len(order_qty) > 0,否则不管有没有对应订单都会执行加量操作。


优化后的实现步骤

下面是一步步的优化方案,完全对齐你原来的业务逻辑:

1. 预处理数据和日期

先把所有日期转成datetime类型,方便后续计算,同时聚合采购订单(避免同一物料同一天多个订单的情况):

import pandas as pd

# 假设today和endofmonth已经定义,先转成datetime
today = pd.to_datetime(today)
endofmonth = pd.to_datetime(endofmonth)
df_dates = pd.date_range(start=today, end=endofmonth, freq='D')

# 预处理采购订单:转日期+聚合同物料同日的到货量
df_purchase_orders['DATE'] = pd.to_datetime(df_purchase_orders['DATE'])
df_po_agg = df_purchase_orders.groupby(['ITEM', 'DATE'])['RECEIVING_AMOUNT'].sum().reset_index()

2. 生成物料-日期的笛卡尔积基础表

我们需要每个物料在每一天都有预测数据,用MultiIndex.from_product快速生成所有组合:

# 获取所有唯一物料
items = df_stock['ITEM'].unique()
# 生成物料和日期的笛卡尔积
index = pd.MultiIndex.from_product([items, df_dates], names=['ITEM', 'DATE'])
df_base = pd.DataFrame(index=index).reset_index()

3. 合并初始库存和日消耗数据

把库存表的初始库存、日消耗关联到基础表:

df_base = df_base.merge(df_stock[['ITEM', 'STOCK', 'DAILY_DEDUCTION']], on='ITEM', how='left')

4. 计算累计消耗量

根据日期与today的天数差,计算到当日为止的累计消耗(完全对齐原代码的每日扣减逻辑):

# 计算每个日期距离today的天数差(today为0,次日为1...)
df_base['days_since_today'] = (df_base['DATE'] - today).dt.days
# 累计消耗:每日扣减 * 已过天数+1(因为today当天就会扣一次)
df_base['cumulative_deduction'] = df_base['DAILY_DEDUCTION'] * (df_base['days_since_today'] + 1)

5. 合并到货量并计算累计到货

把采购订单的到货量匹配到对应日期和物料,然后计算到当日为止的累计到货:

# 合并到货量,无到货的填0
df_base = df_base.merge(df_po_agg, on=['ITEM', 'DATE'], how='left')
df_base['RECEIVING_AMOUNT'] = df_base['RECEIVING_AMOUNT'].fillna(0)

# 按物料分组,计算累计到货量
df_base['cumulative_receiving'] = df_base.groupby('ITEM')['RECEIVING_AMOUNT'].cumsum()

6. 计算最终预测库存

用向量化计算直接生成所有日期的预测库存:

# 计算预测库存:初始库存 - 累计消耗 + 累计到货
df_base['predicted_stock'] = df_base['STOCK'] - df_base['cumulative_deduction'] + df_base['cumulative_receiving']
# 转成int类型,和原代码输出一致
df_base['predicted_stock'] = df_base['predicted_stock'].astype(int)

7. 整理成原代码的输出格式

如果需要和原代码一样的列表格式,直接转换即可:

# 格式化日期并提取所需列
result = df_base.rename(columns={'DATE': 'date_format'})
result['date_format'] = result['date_format'].dt.strftime('%Y-%m-%d')

# 转成和原temptable一样的列表结构
temptable = result[['date_format', 'ITEM', 'predicted_stock']].values.tolist()

为什么这个方案更快?

  • 所有操作都是向量化批量处理,底层由Pandas的C扩展实现,比Python循环快几十到几百倍;
  • 用merge和groupby替代了循环内的loc查询,避免了重复的数据检索开销;
  • 代码逻辑更清晰,也更容易维护和调试。

内容的提问来源于stack exchange,提问作者akelopes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:51:19