商品库存分析
学习目标
- 知道库存管理的ABC模型
- 知道库存管理的XYZ模型
- 完成ABC-XYZ建模案例
无论是传统零售还是电商领域,关键产品的缺货会对销售和营销成本产生巨大的负面影响。在目前这个流量越来越贵的时代,好多流量都是付费购买来的,当我们用真金白银换来了用户的访问,应该尽量避免产品缺货。缺货会给用户带来很差的产品体验,并且会使用户流向竞品,导致用户流失。
虽然我们可以通过保持一个过量库存的方式避免缺货情况,但是这会导致库存周转率较低,带来更大的资金和仓储成本,我们可以通过一套库存管理方法将库存量控制在合理的水平,实现不伤害用户体验,保证日常正常经营的前提下压缩备货带来的资金和仓储成本。
一、电商中的库存管理方法
1.1 概述
- ABC 管理法是管理库存的经典方法。通过计算每个SKU的销售收入在所有SKU产生的总收入中的累积百分比贡献进行排名,来对商品进行分类,它基于帕累托原则(80/20 规则):
- A类商品贡献了80%的销售收入,这些商品需要严格控制库存,避免缺货
- B类商品贡献了接下来的10%的销售收入,对于这类商品,库存控制可以适当放松
- 剩下的10%收入由C类商品贡献,但C类商品种类最多,分配到的进货成本和仓储资源优先级最低
- ABC库存管理虽然有效,但是有自身局限性,它只从销售收入单一维度来衡量商品的重要性。但实际情况确更加复杂,如:
- 某些商品周期性较强
- 某些商品会受季节影响
- 还有些商品的销量受售价的影响比较敏感,竞争对手做活动搞促销都会营销到销量
- 除此之外经济因素,政策影响都会对销量造成影响从而给库存管理带来更大挑战
- 引入XYZ库存管理方法可以帮助我们适应更加复杂的情况。与ABC库存管理不同,ABC库存管理着眼于每个SKU的收入贡献,XYZ库存管理根据SKU的需求变化对其进行分类。当对产品的需求相当稳定时,预测相对简单。然而,当它受到变化的影响时,需求预测就变成了一个挑战
1.2 XYZ库存管理方法
- 通过 XYZ 库存管理,在很长一段时间内测量每个SKU的销售需求,以捕捉需求的季节性变化,然后计算每个SKU的方差,并根据其变化对分数进行排名。
- X 类:需求变化最小的产品。 这些产品的销售比较稳定,这意味着采购经理更容易预测它们,很容易避免缺货。
- Y 类:比X类中的产品变化更大。由于季节性等因素,需求会随时间变化,因此更难准确预测
- Z 类:需求波动起伏较大,比较难预测,除非有冗余较大的备货,否则很难避免缺货
1.3 将ABC与XYZ组合使用
- ABC法和XYZ法是从不同的角度来处理库存管理的问题,而且对运营和采购人员都很有用,所以可以将它们结合起来
- 将ABC与XYZ组合起来的用法很简单,对于每个SKU我们组成 AX、AY、AZ、BX、BY、BZ、CX、CY 和 CZ九个类别,通过这九个类别,我们可以帮助运营和采购人员了解两者对收入的重要性以及需求的变化
- 在这个项目中,我们将使用电子商务交易数据的 12 个月快照来创建一个 ABC-XYZ 库存管理模型,该模型对每个SKU进行分类,并为其管理提出一些建议,以帮助零售商避免出现代价高昂的缺货
二、代码实现
2.1、加载数据&数据清洗
- 导入使用到的模块
from datetime import timedelta
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_style("dark")
sns.set()
-
加载交易数据
我们还是使用在线电商零售数据,计算每个SKU在一段时间内的销售数量和销售收入,这里加载12个月的数据
data1 = pd.read_excel('data/online_retail_II.xlsx',sheet_name='Year 2009-2010')
data2 = pd.read_excel('data/online_retail_II.xlsx',sheet_name='Year 2010-2011')
data = pd.concat([data1,data2],ignore_index=True)
data
- 我们将日期转换成日期时间类型,并从订单日期中提取12个月的数据,我们提取一整年的数据,每个月的销售数据都是完整,这样可以避免分析的误差
data['InvoiceDate']= pd.to_datetime(data['InvoiceDate'])
df_12m = data[(data['InvoiceDate'] > '2010-01-01') & (data['InvoiceDate'] <= '2010-12-31')]
df_12m.info()
- 调整一下列名,方便后续分析,并创建新列提取月份信息
df_12m.columns= ['OrderNo', 'sku', 'Description', 'quantity', 'date_created',
'UnitPrice', 'CustomerID', 'Country']
df_12m = df_12m.assign(month = df_12m['date_created'].dt.month )
df_12m.head()
- 从数据中去掉退货的商品
df_12m = df_12m.query('quantity>0&UnitPrice>0')
#查看数据情况
df_12m.shape[0]
509089
- 为了快速了解数据集中的季节性,使用 Seaborn 绘制每月销售量的柱状图。 从图中可以看出整体销量呈一定周期性,Q1,Q3销量较高
plt.subplots(figsize=(15, 6))
sns.barplot(x="month",
y="quantity",
data=df_12m,
palette="Blues_d")\
.set_title("Quantity by month",fontsize=15)
- 创建销售收入字段,查看订单价值在一年中的变化情况。波动情况跟销量的波动基本相符
df_12m = df_12m.assign(revenue =df_12m['quantity']*df_12m['UnitPrice'])
plt.subplots(figsize=(15, 6))
sns.barplot(x="month",
y="revenue",
data=df_12m,
palette="Blues_d")\
.set_title("Revenue by month",fontsize=15)
2.2、构建XYZ模型
- 我们基本了解了数据情况,为了方便后续计算,我们先将数据按sku和month分组,计算不同sku每个月的总销量
df_12m_units = df_12m.groupby(['sku','month'])['quantity'].sum().to_frame().reset_index