一、项目背景:现有一家零售超市2017-2020年的订单信息,2020年各销售指标持续上升,但是利润总额年增长率下滑,净利润率下滑,分析该超市的历年销售业绩表现和利润构成,探究利润总额增长速度下滑的原因。
二、项目指标如下:
三、分析思路
利润总额是衡量企业盈利能力的核心指标,首先对利润总额公式进行拆分:
利润总额=销售总额-总成本=订单总量*平均单价-订单总量* 平均成本=订单总量* 平均定价*(1-折扣率) -(订单总量* 平均成本)
可以从订单总量、平均单价、总成本的角度探究利润增长速度下降的原因。
从逻辑关系上讲:
如果订单总量下降,其他因素不变得情况下,利润总额下降。
折扣力度加大,平均单价降低,如果打折后订单量大幅增加,平均单价降低的影响被抵消,利润总额会上升;如果打折后订单量没有大幅增加,利润总额会下降。
如果成本上升,其他因素不变的情况下,利润总额下降,在这个拆分公式里,成本属于会影响利润的独立因素。
所以,选取的主要指标为:销售总额、订单总量、利润总额,并计算出平均单价(销售总额/订单总量)和净利润率(利润总额/净利润率)。(注:案例提供了折扣数据,折扣影响平均单价,平均单价可以推算,折扣不易计算)
为探究利润增长下滑的原因,还需要找到是哪些月份,哪些产品,哪些地区的利润总额出现了异常,这些异常是由订单总量下降,还是由平均单价降低引起的,还是要归因于成本上升
(注:平均单价会影响订单总量;由于成本数据缺失,这里归因于成本上升只是一种逻辑上的假设,需要更多的成本数据验证)。
四、数据清洗
读取数据,查看基本特征
import pandas as pd
import numpy as np
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
np.set_printoptions(suppress=True)
pd.set_option('display.float_format', lambda x: '%.2f' % x)
# 读取数据
df = pd.read_excel('./super_market.xls')
print(df.head())
print(df.info())
行 ID 销售额 数量 折扣 利润
count 9959.000000 9959.000000 9959.000000 9959.000000 9959.000000
mean 5002.143187 1613.510807 3.768852 0.106406 215.638008
std 2886.562485 2641.237786 2.236739 0.187477 858.710532
min 1.000000 13.440000 1.000000 0.000000 -7978.320000
25% 2508.500000 250.460000 2.000000 0.000000 7.756000
50% 5003.000000 636.300000 3.000000 0.000000 74.200000
75% 7503.500000 1785.210000 5.000000 0.200000 277.200000
max 10000.000000 35621.355000 14.000000 0.800000 10108.280000
查找并处理空值、重复值,根据分析需要增加列
# 查看数据特征
print(df.info())
RangeIndex: 9959 entries, 0 to 9958
Data columns (total 20 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 行 ID 9959 non-null int64
1 订单 ID 9959 non-null object
2 订单日期 9959 non-null datetime64[ns]
3 发货日期 9959 non-null datetime64[ns]
4 邮寄方式 9959 non-null object
5 客户 ID 9959 non-null object
6 客户名称 9959 non-null object
7 细分 9959 non-null object
8 城市 9959 non-null object
9 省/自治区 9959 non-null object
10 国家/地区 9959 non-null object
11 地区 9959 non-null object
12 产品 ID 9959 non-null object
13 类别 9959 non-null object
14 子类别 9959 non-null object
15 产品名称 9959 non-null object
16 销售额 9959 non-null float64
17 数量 9959 non-null int64
18 折扣 9959 non-null float64
19 利润 9959 non-null float64
dtypes: datetime64[ns](2), float64(3), int64(2), object(13)
#(1)查看空值、重复值(无空值重复值)
print(df.isnull().sum())
print(df.duplicated("订单ID").sum())
#(2)df['订单日期']和df['发货日期']自动导入的数据类型是datetime64[ns],
可以直接作为时间序列索引,进行重采样操作以查看时间趋势
# (3) 为统计用户的习惯下单时间,对订单日期的月、日、周取详细信息
比如2020-4-27,["月"]为4,["日"]为 27,["周"]为 1(星期一)
df["年"]=df["订单日期"].dt.year
df["月"]=df["订单日期"].dt.month
df["日"]=df["订单日期"].dt.day
df["星期"]=df["订单日期"].apply(lambda x: x.weekday()+1)
print(df.loc[:,["订单日期","年","月","日","星期"]].head())
订单日期 年 月 日 星期
0 2020-04-27 2020 4 27 1
1 2020-06-15 2020 6 15 1
2 2020-06-15 2020 6 15 1
3 2020-12-09 2020 12 9 3
4 2019-05-31 2019 5 31 5
五、分析过程
总体指标
# 计算总数
total_sale = df["销售额"].sum()
total_order = df["订单 ID"].nunique()
total_price = total_sale/total_order
total_revenue = df["利润"].sum()
total_rate = total_revenue/total_sale
total = pd.Series([total_sale,total_order,total_price,total_revenue,total_rate],index=["销售总额","订单总量","平均单价","利润总额","净利润率"])
print(total)
销售总额 16068954.12
订单总量 2770.00
平均单价 5801.07
利润总额 2147538.92
净利润率 0.13
1. 时间趋势分析(时间序列)
(1)计算各年总量及环比变化
时间序列使用resample进行聚合
pct_change()算环比,pct_change()能计算变化率,即(后一个值-前一个值)/前一个值
df.set_index("订单日期",inplace=True)
# 时间序列方法计算各年总数
grouped_year = df.resample("Y").agg({"销售额":"sum","订单 ID":pd.Series.nunique,"利润":"sum"}).reset_index()
grouped_year = grouped_year.rename(columns={"销售额":"销售总额","订单 ID":"订单总量","利润":"利润总额"})
grouped_year["平均单价"] = grouped_year["销售总额"]/grouped_year["订单总量"]
grouped_year["净利润率"]=grouped_year["利润总额"]/grouped_year["销售总额"]
# 计算年增长率 pct_change()
grouped_year_pct = grouped_year.loc[:,["销售总额","订单总量","平均单价","利润总额","净利润率"]].pct_change()
grouped_year_pct["订单日期"]=grouped_year["订单日期"]
grouped_year_pct = grouped_year_pct.rename(columns={"销售总额":"销售总额年增长","订单总量":"订单总量年增长","平均单价":"平均单价年增长","利润总额":"利润总额年增长","净利润率":"净利润率年增长"})
# 合并表格
grouped_year = grouped_year.merge(grouped_year_pct,how="left",on="订单日期")
#日期只显示年 %
grouped_year["订单日期"]=grouped_year["订单日期"].apply(lambda x: x.strftime("%Y"))
print(grouped_year)
订单日期 销售总额 订单总量 利润总额 平均单价 净利润率 销售总额年增长 订单总量年增长 平均单价年增长 \
0 2017 2931056.42 569 373011.28 5151.24 0.13 nan nan nan
1 2018 3431919.46 655 471470.22 5239.57 0.14 0.17 0.15 0.02
2 2019 4243539.86 730 621943.00 5813.07 0.15 0.24 0.11 0.11
3 2020 5462438.39 816 681114.43 6694.16 0.12 0.29 0.12 0.15
利润总额年增长 净利润率年增长
0 nan nan
1 0.26 0.08
2 0.32 0.07
3 0.10 -0.15
可以看到,该超市的销售总额、订单总量、利润总额都持续上升,但利润总额的年增长率有所下降,2020年净利润率年增长率为负值,盈利能力有所下降。
从年度数据上看,订单总量和平均单价仍然在持续增长,推断影响因素更大的是成本上升。
但是从更详细的维度上看呢?
(2)计算各月总量及同比变化
使用diff(periods=1, axis=0)) 一阶差分函数
periods:移动的幅度, 默认值为1
axis:移动的方向,{0 or ‘index’, 1 or ‘columns’},如果为0或者’index’,则上下移动,如果为1或者’columns’,则左右移动。默认列向移
# 计算月同比 diff函数
df_temp1 = grouped_month.loc[:,["销售总额","订单总量","利润总额","净利润率"]]
df_temp = df_temp1.diff(12)
df_temp.fillna(0,inplace=True)
grouped_month_diff12 = df_temp/(df_temp1 - df_temp)
grouped_month_diff12["订单日期"]=grouped_month["订单日期"]
grouped_month_diff12 = grouped_month_diff12.rename(columns={"销售总额":"销售总额同比","订单总量":"订单总量同比","利润总额":"利润总额同比","净利润率":"净利润同比"})
# 合并表格
grouped_month = grouped_month.merge(grouped_month_diff12,how="left",on="订单日期")
#日期只显示年月 %
grouped_month["订单日期"]=grouped_month["订单日期"].apply(lambda x: x.strftime("%Y-%m"))
print(grouped_month)
订单日期 销售总额同比 订单总量同比 平均单价同比 利润总额同比 净利润率同比
36 2020-01 0.25 0.44 -0.14 0.41 0.13
37 2020-02 0.50 0.49 0.01 0.58 0.05
38 2020-03 0.92 0.28 0.50 0.44 -0.25
39 2020-04 0.51 0.24 0.22 -0.24 -0.50
40 2020-05 0.59 0.33 0.19 0.24 -0.22
41 2020-06 0.28 0.32 -0.03 0.73 0.35
42 2020-07 0.52 0.28 0.19 1.21 0.46
43 2020-08 0.33 0.21 0.09 -0.31 -0.48
44 2020-09 0.09 0.09 -0.01 0.32 0.21
45 2020-10 0.19 0.18 0.01 0.12 -0.06
46 2020-11 -0.11 0.13 -0.21 -0.52 -0.47
47 2020-12 0.18 0.33 -0.12 -0.19 -0.31
查看2020年各月同比销售情况,可以看到利润总额同比下跌的月份是4、8、11、12(净利润率也在同比下降)。
其中11和12月的平均单价同比下降,订单总量同比上升,说明这两个月的订单折扣力度比较大,虽然促成了销量提升,但造成了利润总额下降。(11月的销售总额也下降了,说明打折没有带动总体销售额的提升)
而4月和8月的平均单价同比上升,订单总量同比上升,这两个月可能是成本上升引起利润下滑。
(4)用户下单时间分布(月/周)
month_distr = df.groupby(["月"]).agg({"销售额":"sum","订单 ID":pd.Series.nunique,"利润":"sum"}).reset_index()
month_distr = month_distr.rename(columns={"销售额":"销售总额","订单 ID":"订单总量","利润":"利润总额"})
month_distr["净利润率"]=month_distr["利润总额"]/month_distr["销售总额"]
月 销售总额 订单总量 利润总额 净利润率
0 1 805987.20 239 131077.86 0.16
1 2 698382.86 225 80989.30 0.12
2 3 969566.88 273 141371.69 0.15
3 4 778286.14 257 116593.36 0.15
4 5 1692457.49 489 216534.37 0.13
5 6 1691432.50 473 209722.76 0.12
6 7 883221.88 267 122438.23 0.14
7 8 1813231.06 515 265710.40 0.15
8 9 1602679.83 455 205313.51 0.13
9 10 1706620.61 500 201983.21 0.12
10 11 1746088.72 507 202688.68 0.12
11 12 1680998.93 463 253115.55 0.15
从用户时间消费习惯上分析,8月、11月、12月的销售总额排名靠前,占全年总销量的比重较高,所以这三个月份的异常对年度利润增长速度下滑的影响会更大。
总结:通过对时间维度的销售指标分析,我们发现造成2020年利润增长速度下滑的异常月份主要是8月、11月、12月,其中8月份可能是因为成本上升,11、12月是由于折扣力度大,11月份销量同比下降,说明11月份的打折促销的效更果不好。
2、产品类型分布(类别和子类别)
(1)各类产品总量及占比
# 各产品总量及占比
product_category = df.groupby(["类别","子类别"]).agg({"销售额":"sum","订单 ID":pd.Series.nunique,"利润":"sum"}).reset_index()
product_category = product_category.rename(columns={"销售额":"销售总额","订单 ID":"订单总量","利润":"利润总额"})
product_category["净利润率"]=product_category["利润总额"]/product_category["销售总额"]
# print(product_category)
pc=product_category
pc["%销售总额"]=pc["销售总额"]/pc["销售总额"].sum()
pc["%订单总量"]=pc["订单总量"]/pc["订单总量"].sum()
pc["%利润总额"]=pc["利润总额"]/pc["利润总额"].sum()
print(pc)
# 如果想查看大类别
pc_t=pc.groupby(by="类别").agg({"子类别":"count","销售总额":"sum","订单总量":"sum","利润总额":"sum",
"净利润率":"sum","%销售总额":"sum","%订单总量":"sum","%利润总额":"sum"}).reset_index()
pc_t["净利润率"]=pc_t["利润总额"]/pc_t["销售总额"]
类别 子类别 销售总额 订单总量 利润总额 净利润率 %销售总额 %订单总量 %利润总额
0 办公用品 9 4865589.79 4933 757640.35 0.16 0.30 0.57 0.35
1 家具 4 5734340.83 1936 638735.63 0.11 0.36 0.22 0.30
2 技术 4 5469023.50 1775 751162.94 0.14 0.34 0.21 0.35
从产品大类别上看,三种产品的销售总额、利润总额贡献差异并不大,但是有的产品属于高利润率产品,有的产品属于高销售额产品。
具体来讲,办公用品属于类别多,订单总量高的小型商品,而且净利润率最高;家具和技术产品作为大型商品,类别较少,家具产品的利润率最低。
类别 子类别 销售总额 订单总量 利润总额 净利润率 %销售总额 %订单总量 %利润总额
0 办公用品 信封 287486.08 544 72505.02 0.25 0.02 0.06 0.03
1 办公用品 器具 2160183.00 496 199027.02 0.09 0.13 0.06 0.09
2 办公用品 收纳具 1152527.74 660 316843.38 0.27 0.07 0.08 0.15
3 办公用品 标签 97077.96 503 23945.74 0.25 0.01 0.06 0.01
4 办公用品 用品 287970.48 529 40576.34 0.14 0.02 0.06 0.02
5 办公用品 系固件 129010.73 516 18628.99 0.14 0.01 0.06 0.01
6 办公用品 纸张 263334.12 482 61622.26 0.23 0.02 0.06 0.03
7 办公用品 美术 196222.77 469 -18266.89 -0.09 0.01 0.05 -0.01
8 办公用品 装订机 291776.91 734 42758.49 0.15 0.02 0.08 0.02
9 家具 书架 2307203.22 525 361136.86 0.16 0.14 0.06 0.17
10 家具 桌子 862010.43 169 -133405.67 -0.15 0.05 0.02 -0.06
11 家具 椅子 2085435.97 714 325836.73 0.16 0.13 0.08 0.15
12 家具 用具 479691.21 528 85167.71 0.18 0.03 0.06 0.04
13 技术 复印机 1991498.88 491 252897.26 0.13 0.12 0.06 0.12
14 技术 电话 1799653.46 505 223349.64 0.12 0.11 0.06 0.10
15 技术 设备 874465.14 295 144110.62 0.16 0.05 0.03 0.07
16 技术 配件 803406.02 484 130805.42 0.16 0.05 0.06 0.06
从产品子类别上看,利润总额贡献比值较高(超过10%)的办公用品中的收纳具,家具中的书架、椅子,技术中的复印机。
利润总额为负值的产品是,办公用品中的美术产品,家具中的桌子,而且两者的销售额占比都不高。
(2)2020年各类产品年度增长变化
要计算年度增长变化,首先要计算每年的各产品总量,然后使用diff计算差别
# 每年各产品类别
df["订单日期"] = df["订单日期"].apply(lambda x: x.strftime("%Y"))
pc_year = df.groupby(["订单日期","类别","子类别"]).agg({"销售额":"sum","订单 ID":pd.Series.nunique,"利润":"sum"}).reset_index()
pc_year = pc_year.rename(columns={"销售额":"销售总额","订单 ID":"订单总量","利润":"利润总额"})
pc_year["平均单价"] = pc_year["销售总额"] / pc_year["订单总量"]
pc_year["净利润率"]=pc_year["利润总额"]/pc_year["销售总额"]
# 计算年增长 diff(17)
temp = pc_year.loc[:,["销售总额","订单总量","平均单价","利润总额","净利润率"]]
temp1 = temp.diff(17)
temp1.fillna(0,inplace=True)
pc_year_diff = temp1/(temp-temp1)
pc_year_diff = pc_year_diff.rename(columns={"销售总额":"销售总额年增长","订单总量":"订单总量年增长","平均单价":"平均单价年增长","利润总额":"利润总额年增长","净利润率":"净利润率年增长"})
pc_year_diff["订单日期"]=pc_year["订单日期"]
pc_year_diff["类别"]=pc_year["类别"]
pc_year_diff["子类别"]=pc_year["子类别"]
pc_year_diff = pc_year_diff.loc[:,["订单日期","类别","子类别","销售总额年增长","订单总量年增长","平均单价年增长","利润总额年增长","净利润率年增长"]]
print(pc_year_diff)
订单日期 类别 子类别 销售总额年增长 订单总量年增长 平均单价年增长 利润总额年增长 净利润率年增长
51 2020 办公用品 信封 0.43 0.28 0.12 0.38 -0.03
52 2020 办公用品 器具 0.29 0.23 0.05 0.86 0.44
53 2020 办公用品 收纳具 0.24 0.06 0.16 0.30 0.05
54 2020 办公用品 标签 0.38 0.50 -0.08 0.19 -0.14
55 2020 办公用品 用品 0.57 0.38 0.14 0.24 -0.21
56 2020 办公用品 系固件 0.26 0.22 0.04 0.16 -0.08
57 2020 办公用品 纸张 0.15 0.18 -0.03 0.09 -0.05
58 2020 办公用品 美术 0.42 0.24 0.15 -0.63 -0.74
59 2020 办公用品 装订机 0.25 0.25 -0.00 0.16 -0.07
60 2020 家具 书架 0.44 0.38 0.04 0.38 -0.04
61 2020 家具 桌子 1.16 0.62 0.33 2.47 0.61
62 2020 家具 椅子 0.15 0.23 -0.06 0.01 -0.13
63 2020 家具 用具 0.41 0.38 0.02 0.45 0.03
64 2020 技术 复印机 -0.01 0.20 -0.18 -0.38 -0.37
65 2020 技术 电话 0.30 0.17 0.11 0.20 -0.08
66 2020 技术 设备 0.39 0.35 0.03 0.26 -0.10
67 2020 技术 配件 0.16 0.07 0.09 -0.08 -0.21
可以看到比较明显的是,办公用品中的美术产品和技术中的复印机,利润总额和净利润率都出现了大幅下跌;
美术产品的订单总量和平均单价没有下降,猜测是由于成本上升;由于其销售总额占比仅有1%,而且本身就是负利润的,现在利润下滑更加严重,如果成本数据验证了成本上升,可以考虑下架美术产品;
而复印机的订单总量上升,平均单价下降,说明折扣力度加大造成了利润下降;由于复印机本身是利润贡献占比较大的产品,现在打折促销提升了销量,但没有提升销售额,而且造成了利润总额下降,说明复印机可能不适合折扣促销。
除此之外,剩下的大部分产品都出现了不同程度的净利润率下降,平均单价没有明显的上升,推出可能是因为成本上升导致利润空间的压缩。
3、地区分布(地区、省/自治区、城市)
此部分计算方法和产品类型大致相同,只展示统计结果和分析结论。
(1)各地区总量及占比
地区 省/自治区 销售总额 订单总量 利润总额 净利润率 %销售总额 %订单总量 %利润总额
2 华东 7 4684506.44 1480 607218.68 0.13 0.29 0.30 0.28
1 中南 6 4137415.09 1294 670885.31 0.16 0.26 0.26 0.31
0 东北 3 2681567.47 836 242191.51 0.09 0.17 0.17 0.11
3 华北 5 2447301.02 653 431053.22 0.18 0.15 0.13 0.20
5 西南 6 1303124.51 437 97636.73 0.07 0.08 0.09 0.05
4 西北 5 815039.60 237 98553.48 0.12 0.05 0.05 0.05
从大区维度看,华东大区的销售总额和订单总量最高,中南大区的利润总额最高
西北地区的销售总额和利润总额最低,西南地区的净利润率最低。
place_minus = place_t[place_t["利润总额"]<0]
省/自治区 城市 销售总额 订单总量 利润总额 净利润率 %销售总额 %订单总量 %利润总额
3 辽宁 33 862569.74 330 -168038.72 -0.19 0.05 0.07 -0.08
7 江苏 32 649967.22 286 -107603.02 -0.17 0.04 0.06 -0.05
10 湖北 35 621960.33 286 -132032.35 -0.21 0.04 0.06 -0.06
15 浙江 26 452108.24 201 -131729.00 -0.29 0.03 0.04 -0.06
18 四川 16 400877.60 186 -89487.52 -0.22 0.02 0.04 -0.04
22 内蒙古 16 273453.01 106 -57707.89 -0.21 0.02 0.02 -0.03
24 甘肃 7 179270.03 78 -42682.19 -0.24 0.01 0.02 -0.02
从省份维度看,利润为负值的省份是辽宁,江苏、湖北、浙江、四川、内蒙、甘肃,这几个省份的负利润率都不低,而且辽宁江苏的销售额排名靠前,拉低了全国平均净利润率。
(2)2020年各省份年度增长变化
# 按照利润总额年度增长率排序(筛选出利润下滑验证的前10个省份)
订单日期 地区 省/自治区 销售总额年增长 订单总量 平均单价 利润总额 净利润率
年增长 年增长 年增长 年增长
0 2020 西南 西藏 -0.55 -0.83 1.69 -0.87 -0.70
1 2020 西北 青海 -0.41 0.00 -0.41 -0.68 -0.46
2 2020 西南 海南 0.11 -0.40 0.86 -0.62 -0.66
3 2020 西南 重庆 -0.40 -0.45 0.10 -0.57 -0.28
4 2020 西南 贵州 -0.62 -0.53 -0.19 -0.54 0.21
5 2020 西南 云南 -0.47 -0.48 0.02 -0.40 0.13
6 2020 华东 福建 -0.12 0.17 -0.25 -0.31 -0.21
7 2020 中南 海南 -0.36 0.38 -0.53 -0.28 0.12
8 2020 华东 江苏 0.11 0.15 -0.03 -0.26 -0.33
9 2020 华东 上海 -0.22 0.03 -0.24 -0.18 0.05
10 2020 西北 陕西 0.22 0.18 0.04 -0.11 -0.28
其中西藏、海南、重庆、贵州、云南的订单总量下降,销售状况下滑是主要影响因素;
青海、福建、海南、上海的平均单价下降,促销后销售额未明显增长是主要影响因素
陕西省推测是由于成本上升引起利润下降。
上一步分析的利润为负值的省份销售和利润情况在好转。
总结如下:
1、从年度数据上看,该超市的销售总额、订单总量、利润总额都持续上升,但利润总额的年增长率有所下降,2020年净利润率年增长率为负值,盈利能力有所下降。
由于订单总量和平均单价仍然在持续增长,推断影响因素更大的是成本上升。
2、从月同比数据看,造成2020年利润增长速度下滑的异常月份主要是8月、11月、12月(利润总额下滑),其中8月份可能是因为成本上升,11、12月是由于折扣力度大,11月份销量同比下降,说明11月份的打折促销的效果更不好。
3、从产品维度看,利润总额下滑的主要是办公用品中的美术产品和技术中的复印机:
其中美术产品的订单总量和平均单价没有下降,猜测是由于成本上升;由于其销售总额占比仅有1%,而且本身就是负利润的,现在利润下滑更加严重,如果成本数据验证了成本上升,可以考虑下架美术产品;
而复印机的订单总量上升,平均单价下降,说明折扣力度加大造成了利润下降;由于复印机本身是利润贡献占比较大的产品,现在打折促销提升了销量,但没有提升销售额,而且造成了利润总额下降,说明复印机可能不适合折扣促销。
除此之外,剩下的大部分产品都出现了不同程度的净利润率下降,平均单价没有明显的上升,推出可能是因为成本上升导致利润空间的压缩。
4、从地区维度看,利润下滑的地区主要有10个,其中西藏、海南、重庆、贵州、云南的订单总量下降,销售状况下滑是主要影响因素;青海、福建、海南、上海的平均单价下降,促销后销售额未明显增长是主要影响因素,陕西省推测是由于成本上升引起利润下降。