Python与供应链-1需求与库存计划

今天跟大家分享我在供应链三分技术公众号学习的Python+供应链的相关知识,在这里与大家分享,经过实践,作者的模型都能够进行复刻,也在这里感谢小豌豆老师的辛勤付出。


Python在供应链管理,特别是需求与库存计划方面,发挥着重要的作用。Python作为一种功能强大的编程语言,能够处理大量的数据,提供灵活的算法,以及丰富的第三方库,这些特点使其成为供应链管理的理想工具。

以下是一些Python在供应链需求与库存计划中的具体应用:

  1. 数据分析与预测:Python可以帮助分析历史销售数据,预测未来的需求。通过使用机器学习或统计模型,Python可以预测产品的销售的趋势,为库存计划提供数据支持。
  2. 库存优化:Python可以通过算法优化库存水平,降低库存成本,同时避免缺货风险。例如,Python可以根据需求预测结果和库存成本,计算出最佳的再订货点和订货量。
  3. 供应链模拟:Python可以构建复杂的供应链模型,模拟不同情况下的供应链行为。这有助于企业理解供应链中的潜在风险,制定应对措施。
  4. 自动化与集成:Python可以与其他供应链管理系统进行集成,实现数据的自动导入、处理和导出。这可以提高工作效率,减少人为错误。

在Python中,有一些常用的库和工具可以用于供应链需求与库存计划,如pandas用于数据处理和分析,scikit-learn用于机器学习模型构建,numpy用于科学计算,以及matplotlib和seaborn用于数据可视化。此外,还有一些专门针对供应链管理的Python库,如Pyomo用于优化问题求解,SimPy用于模拟问题等。

1需求预测和库存计划实现供需匹配

供应链是一个充满不确定性的系统,不管需求是否可预测都随时会变化,而供给虽然相对固定但也常有提前期波动、供给数量不足等不确定因素。这意味着要做到供应链的供需匹配是很困难的,典型的供需失衡场景是库存不足甚至缺货时需求订单还在不断增加,库存一堆时却只有零星需求订单过来。

那么,如何尽可能实现供需匹配呢?

Mark A.Moon在其《供应链与需求管理:精准需求预测与高效匹配供需》一书提到,高效执行供需匹配一定要具备文化、流程和工具3个要素。文化方面是指公开透明、团结协作致力于实现同一目标;流程是确保各环节紧密衔接并实时跟踪记录;工具是能够在对的时间把对的信息传递给对的人。

Gerard Cachon和Christian Terwiesch专门从供需匹配的视角写了一本《运营管理》,认为有效的运营管理对应着供给与需求的有效匹配,如果企业在运营模式中实施了定量模型和定性策略等运营管理工具,会赢得显著绩效优势。

两者都提到了实现供需匹配需要具备工具,需要了解涵盖Excel、Python、数据库、业务系统、ERP系统……等此类工具,还需要数据挖掘模型、需求预测模型、库存优化模型……型等此类建模技术,唯有两者结合才在能对的时间把对的信息传递给对的人。

再结合工作以来遇到的一些供需失衡问题,个人认为实现供需匹配的一个关键是做好需求预测和库存计划;而量化供需匹配效果的一个指标则是服务水平,即供需匹配是否精准不是由企业自己说了算,而是以顾客体验到的服务水平为主。

2 究竟是理论方法没用,还是知道哪些理论方法可以解决问题?

刚开始工作时间不长、经验不足,觉得脑子都是些条条框框的理论知识,所以每次听到别人说自己的供应链问题有多特殊,不是书上那些理论可以解决的,唯有丰富的实践经验才能解决问题,我都是不置可否但也认真观察学习别人是怎么靠经验解决问题的。但渐渐地,我发现所谓的经验解决问题无非就是天天拉着所有人一起救火解决急急急的问题,而顾客那边经常是等到黄花菜都凉了还见不到货的影子。

虽然问题最后都基本能解决,但所有人给卷进来救火,顾客长时间等货就是所谓的问题特殊要靠经验解决?经常性的靠执行救火解决问题,令我不得不怀疑“究竟是我学的知识不能解决问题,还是我们压根不懂有哪些理论方法可以解决这些问题?”

于是,我找了一个课题的数据,结合学过的知识并参照刘宝红老师的《需求预测和库存计划:一个实践者的角度》一书,先试做了一套解决方案并之后用到上述问题中,发现这套解决方案可以解决70%的问题,起码不至于所有人天天都在执行救火解决问题。在这期间也深刻体会到“多学点理论知识总不会有错,问题也确实有特殊性,但可怕的是你压根不去找找有哪些理论方法可以解决问题”。

现在回看这些文章自觉实践和理论方面都有不足之处,加上今年上半年又碰到几个案例让我深感全面体系的掌握需求预测与库存优化方法的重要性。

案例1因为项目的原因,之前看到供应商和甲方的备货方法实在令人哭笑不得。甲方在全国铺新品,发指令要求供应商在多个省份设仓备货(按约定,甲方给采购订单,货权属于供应商,双方一同承担库存风险)。但供应商因为需求不确定只在一个仓库备了几十台货发全国,结果个别省交付来不及导致甲方痛批了供应商一顿。供应商一怒之下向工厂订了1000台货,扔给甲方让他们给计划在哪些省要备哪些型号的货各多少台,这下轮到甲方给不出计划了。这里的供应商和甲方都是非专业的供应链管理人员,都不知有什么方法可以做好备货计划,才会如此拿备货来痛击对方。

案例2有个甲方计划自己开发需求预测系统,最关键的问题不是用了什么高级模型方法,而是不听劝地(1)拿采购订单数据作为模型输入数据来做需求预测(采购数据都是做过处理的反应不出需求情况),(2)允许使用者在预测时随意调整输入数据的时间范围(会导致一些统计假设不成立),(3)将适用于季节性需求的Holt-Winter模型用到没有季节性特征的产品。这样的需求预测系统大概率就是“垃圾进,垃圾出”,没有多少人愿意用。

案例3“我就是为了库存计划,才做的需求预测”。套用姜文电影《邪不压正》的一句台词“我就是为了这点醋,才包的饺子”。实际库存计划也是如此,需求预测不是最终目的,结合需求预测做出配套的库存计划才是目的。案例1的甲方和供应商,以及后来其他一些人找我帮忙看下如何做备货计划,一般我都会给出需求预测和库存模型。但他们只关注需求预测结果准不准,对最终的库存计划一点兴趣都没有,似乎只要需求预测准了就能解决所有问题。我的回答都是“预测都是错的,总比没有好,关键的是库存计划”。实际上,每次碰到有人问“你这需求预测准不准的?”,我心里都在嘀咕“何为准,需求要是100%准,我还在这预测供应链需求?一早就预测股票价格炒股致富去了”。

上面的案例说了这么多,无非是想说明专业、体系的需求预测与库存优化的重要性。为此,今年以来补充阅读了一些需求预测与库存优化等方面的书,加上对碰到的实践问题的一些思考,所以计划分享下更全面、更体系的需求与库存计划系列。至于为什么选择Python工具,是因为刚好在学且觉得这个工具合适。

3 需求与库存数据

需求与库存计划系列的大概分享计划是,第1部分先写指数平滑、ARMA、Prohet等时间序列方法预测供应链需求,穿插一些需求异常点的处理、需求预测置信区间估计的实现方法;第2部分结合需求预测结果,分享如何基于连续盘点(Continuous review policies)和周期盘点(Periodic review policies)的库存策略设置安全库存、订货点、订货时间等库存计划。

为此模拟了一份需求与库存数据(文末附链接可下载),主要有产品A和产品B两个产品,华东、华南和华北3个仓库,包括从2020-5-1至2022-11-15的订单需求;同时,按照订货周期不完全相同(3,5,7天一次),采购到货提前期都是2天,订货数量是7天移动平均需求的策略,模拟了一份近似“拍脑袋订货”策略的库存数据。

数据明细,以及按不同仓库、不同时间颗粒度绘制每个产品的需求折线的Python代码如下:

#导入相关的库
import numpy as np 
import pandas as pd 
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline

#设置图形的字体和线性颜色
plt.rcParams['font.sans-serif'] = ['SimHei']
r_hex = '#dc2624'
#导入数据,并将Na值填充为0,读取路径为自己电脑的文件路径
ori_data = pd.read_excel("……/InventoryData.xlsx")
ori_data = ori_data.fillna(0)
ori_data

数据输出:

产品区域仓日期需求订货到货在库库存
0产品A华东2020-05-014200558
1产品A华东2020-05-027000488
2产品A华东2020-05-0310300385
3产品A华东2020-05-045900326
4产品A华东2020-05-058500241
........................
5569产品B华南2022-11-111234017
5570产品B华南2022-11-1230014
5571产品B华南2022-11-13503443
5572产品B华南2022-11-1460037
5573产品B华南2022-11-15120025

5574 rows × 7 columns

#列出数据的相关信息
ori_data.info()

数据输出:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5574 entries, 0 to 5573
Data columns (total 7 columns):
 #   Column  Non-Null Count  Dtype         
---  ------  --------------  -----         
 0   产品      5574 non-null   object        
 1   区域仓     5574 non-null   object        
 2   日期      5574 non-null   datetime64[ns]
 3   需求      5574 non-null   int64         
 4   订货      5574 non-null   int64         
 5   到货      5574 non-null   int64         
 6   在库库存    5574 non-null   int64         
dtypes: datetime64[ns](1), int64(4), object(2)
memory usage: 305.0+ KB
# 定义函数demand_agg(),输入相关参数,生成每个产品每个仓库或全部仓库的每天、每周、每月、每季度的汇总需求数据
#data-输入数据,product-产品,warehouse-仓库,period-d,w,m,q分别表示每天、每周、每月、每季度
def demand_agg(data,product,warehouse,period):
    #筛选输入数据的'产品','区域仓','日期','需求'4个字段
    ori_data_filter = ori_data.filter(items=['产品','区域仓','日期','需求'])
   #若参数warehouse == '全部',计算每个产品华东、华南和华北3个仓库的需求总和
    if warehouse == '全部':
        sub_oridata = ori_data[ori_data.产品 == product]
    #否则,根据输入参数warehouse的值,计算每个产品华东、华南或华北单个仓库的需求
    else:
        sub_oridata = ori_data[(ori_data.产品 == product)& (ori_data.区域仓 == warehouse)]
    #将日期设置为时间下标,配合函数resample的使用,根据输入参数period-d,w,m,q,
    #函数resample分别按每天、每周、每月、每季度的时间颗粒度汇总需求
    sub_ts = sub_oridata.set_index('日期')
    oridata1 = sub_ts.resample(period).sum()
    #增加‘产品’和‘区域仓’列字段
    oridata1['产品'] = product
    oridata1['区域仓'] = warehouse
    return oridata1
#定义按仓库画需求线图的函数 demand_plot_bywarehouse,输入参数product-产品
#period-d,w,m,q分别表示每天、每周、每月、每季度
def demand_plot_bywarehouse(product,period):
    #根据参数period生成不同的字符串,用以图形的标题
    if period == 'd':
        str_peroid = '每日需求'
    elif period == 'w':
        str_peroid = '每周需求'
    elif period == 'm':
        str_peroid = '每月需求'
    elif period == 'q':
        str_peroid = '每季度需求'

    #创建仓库的列表,并判断个数
    region = ['全部','华北','华南','华东']
    n = len(region)

    #循环遍历每个仓库
    for i in range(0,n):
        #调用函数demand_agg生成某个产品某个仓位或全部仓位的每天、每周、每月或每季度的汇总需求数据,
        #x等于数据的索引下标,即日期,y等于函数demand_agg汇总计算的需求数据
        x = demand_agg(ori_data,product,region[i],period).index
        y = demand_agg(ori_data,product,region[i],period).需求
        #设置图形的尺寸大小
        plt.figure(figsize=(16,12),dpi=100)
        #创建4x1个子图,逐个画图
        ax = plt.subplot(n,1,i+1)
        #画图,标题label是组合参数{product}-{region[i]}-{str_peroid}
        ax.plot(x,y,color= r_hex,label = f'{product}-{region[i]}-{str_peroid}')
        #设置每个子图的纵轴坐标的范围,最小需求的0.8倍至最大需求的1.2倍,使折线不至于贴着图形的上下边界
        ax.set_ylim(y.min()*0.8,y.max()*1.2)
        #显示图例,自动寻找最佳分布位置
        ax.legend(loc=0,frameon=True)

#调用函数demand_plot_bywarehouse生成产品A每个仓库每天的需求直线图
demand_plot_bywarehouse('产品A','d')

#定义按时间颗粒度画需求线图的函数demand_plot_byperio,输入参数product-产品,warehouse-仓库
#代码解释参照函数demand_plot_bywarehouse的代码解释
def demand_plot_byperiod(product,warehouse):
    period = ['d','w','m','q']

    for i in range(0,len(period)):
        if period[i] == 'd':
            str_peroid = '每日需求'
        elif period[i] == 'w':
            str_peroid = '每周需求'
        elif period[i] == 'm':
            str_peroid = '每月需求'
        elif period[i] == 'q':
            str_peroid = '每季度需求'

        x = demand_agg(ori_data,product,warehouse,period[i]).index
        y = demand_agg(ori_data,product,warehouse,period[i]).需求

        plt.figure(figsize=(16,12),dpi=100)
        ax = plt.subplot(len(period),1,i+1)
        ax.plot(x,y,color= r_hex,label = f'{product}-{warehouse}-{str_peroid}')
        ax.set_ylim(y.min()*0.8,y.max()*1.2)
        ax.legend(loc=0,frameon=True)

demand_plot_byperiod('产品B','全部')

 

 

  • 32
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Py小趴

整理不易,感谢金主!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值