📊 第10章 京东电商销售数据分析与预测
📄 一句话概括

按月看,6 月 1606.69 万最高、2 月 912.80 万最低,差 1.76 倍。 按季看四季度占全年 28.11%;按星期看周末日均 42.06、工作日 39.81,差 5.7%。 粒度越细波动越大:52 个自然周里最低 201.83 万、最高 425.13 万。

📝 本章和前面几章的关系

数据洗完带上了四个派生列,这一篇就是它们的用处:月、季、星期、周,四个粒度各统计一遍。 用的还是 groupby,和第 3 章、第 7 章一模一样,换的只是分组键。

一、按月:两个高峰一个坑

按月份 groupby 求和,十二行一眼看完。 6 月 1606.69 万最高,11 月 1541.36 万第二,2 月 912.80 万最低。 全年 14766.53 万,月均 1230.54 万。高于均线的只有 1、6、10、11、12 五个月, 正好是年初和年末两头。

6 月是 618,11 月是双 11,2 月春节快递停——三条都能用业务解释。 但要记住:这三条是造数据时写进去的。真数据里有没有这个形状,得算完才知道,不能先有结论再找数。

二、按季:不被单月带偏的视角

四个季度分别是 3323.66、3790.56、3501.63、4150.68 万。 第四季度最高,占全年 28.11%;一季度最低,3323.66 万。 按季看的好处是不被单月促销带偏。双 11 落在四季度,把整季都拉起来了。

粒度越粗越平稳,代价是看不见具体哪个月出的问题。所以月表和季表要一起摆,不能只报一张。

三、按星期:周末效应有多大

星期 日均销售额
周一 40.57
周二 39.17
周三 40.97
周四 39.10
周五 39.25
周六 42.44
周日 41.69

周六 42.44、周日 41.69,工作日五天挤在 39.10 到 40.97 之间。 周末两天日均 42.06,工作日平均 39.81,差 5.7%。 造数据时按加 8% 写进去,噪声把它摊薄到 5.7%。这就是设计值和实测值的差别,报数报实测的。

这个数决定排班:客服周末加人、仓库周五备货、投放预算按周内周外分两档,都从这里来。

四、按周:52 个点看节奏

按自然周汇总,周号用 dt.isocalendar().week 取,一年拿到 52 个点。 一周最低 201.83 万、最高 425.13 万,最高的落在第 25 周,正好是 6 月含 618 的那一周。 粒度越细,波动越大。月看趋势、周看节奏、日看异常,三个粒度各有各的用处。

周表还有一个用处:看一次促销到底拉动了几天。看它前后两周是不是被抽空了,就知道有没有透支。

五、显示出来:表比一串数字好读

终端里用 to_string() 对齐,Notebook 里直接打 DataFrame,会自动排版。 统计结果要摆成表,不要 print 成一串。表能对齐,高低一眼看出来。 这一步看着简单,其实是「把数变成人能读的东西」,很多人就卡在这:数算对了,报出去没人看懂。

下一篇开始画图。图比表直观,表比图精确,两个都要会,别只挑顺手的那个。

六、动手 Demo:日期数据统计并显示

月、季、星期、周,四个粒度各 groupby 一次,结果都摆成表。 注意按周那一节:周号要从 isocalendar() 取,不能自己除 7。

import pandas as pd

df = pd.read_excel("销售数据_clean.xlsx")

m = df.groupby("月份")["销售额"].sum()
print("全年 %.2f 万,月均 %.2f 万" % (m.sum(), m.mean()))
print("最高 %d 月 %.2f 万,最低 %d 月 %.2f 万"
      % (m.idxmax(), m.max(), m.idxmin(), m.min()))

q = df.groupby("季度")["销售额"].sum()
print("四季度占比 %.2f%%" % (q.loc[4] / q.sum() * 100))

order = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
w = df.groupby("星期")["销售额"].mean().reindex(order)
print("周末 %.2f,工作日 %.2f"
      % (w[ ["周六", "周日"]].mean(), w[order[:5]].mean()))

df["周"] = df["日期"].dt.isocalendar().week.astype(int)
wk = df.groupby("周")["销售额"].sum()
print("周数 %d,从 %.2f 到 %.2f 万" % (len(wk), wk.min(), wk.max()))

实跑输出:

--------------------------------------------------------------------
日期数据统计并显示
--------------------------------------------------------------------

  ① 按月
  --------------------------------------------------------------------

| 月份 | 销售额 | 广告费 | 订单量 |
|---|---:|---:|---:|
| 1 月 | 1345.45 | 526.17 | 198277 |
| 2 月 | 912.80 | 480.95 | 138249 |
| 3 月 | 1065.41 | 500.15 | 157199 |
| 4 月 | 1119.54 | 539.94 | 164635 |
| 5 月 | 1064.33 | 466.92 | 157019 |
| 6 月 | 1606.69 | 560.90 | 236861 |
| 7 月 | 1120.42 | 524.93 | 165064 |
| 8 月 | 1157.78 | 520.89 | 170156 |
| 9 月 | 1223.43 | 535.33 | 179395 |
| 10 月 | 1316.42 | 547.86 | 192893 |
| 11 月 | 1541.36 | 475.96 | 225602 |
| 12 月 | 1292.90 | 525.39 | 189719 |

  全年合计 14766.53 万元,月均 1230.54 万元。
  最高 6 月 1606.69 万,最低 2 月 912.80 万,差 1.76 倍。
  6 月最高、2 月最低。6 月是 618、11 月是双 11,都是大促;2 月春节,快递停、消费也停。

  ② 按季
  --------------------------------------------------------------------
  四个季度:3323.66、3790.56、3501.63、4150.68。
  四季度最高,占全年 28.11%。
  最低是第 1 季度,3323.66 万。
  按季看的好处是四平八稳,不会被某个月的促销带偏。

  ③ 按星期
  --------------------------------------------------------------------

| 星期 | 日均销售额 |
|---|---:|
| 周一 | 40.57 |
| 周二 | 39.17 |
| 周三 | 40.97 |
| 周四 | 39.10 |
| 周五 | 39.25 |
| 周六 | 42.44 |
| 周日 | 41.69 |

  周末两天明显高,日均 42.06,工作日平均 39.81。
  差的那 5.7% 就是「周末效应」。造数据时按 +8% 写进去,噪声把它摊薄了一点。
  真项目里这个数要看,它决定客服、仓库、投放该按什么节奏排班。

  ④ 按周
  --------------------------------------------------------------------
  一年 52 个自然周,周销售额从 201.83 万到 425.13 万。
  最高那一周是第 25 周,落在 6 月。
  粒度越细,波动越大。月看趋势、周看节奏、日看异常,各有各的用处。

  ⑤ 显示出来
  --------------------------------------------------------------------
  终端里用 to_string() 对齐,Notebook 里直接打 DataFrame 更好看。
  统计结果要摆成表,不要打成一串。表能对齐,一眼看出高低。
  这一步看着简单,其实是「把数变成能读的东西」,很多人就卡在这。
  ! 真项目里下一步是画图。图比表直观,但表比图精确,两个都要会。

isocalendar().week 给的是 ISO 周号,一年 52 或 53 周,和「第几天除以 7」不是一回事。 reindex(order) 是让星期按周一到周日排。不排,groupby 会按字母或者首次出现顺序给。 groupby(...)["销售额"].mean() 算的是日均,.sum() 算的是周总量。 同一列换个聚合函数,意思全变。

30 秒实验

  1. 把按月的 sum 改成 mean,看 6 月还是不是第一。
  2. 把按星期那张表加上订单量,看周末的单量是不是也跟着涨。
  3. 想一想:如果按「ISO 周」和「自然月内第几周」两种口径各算一次,数会差在哪?

常见误区

  1. 自己用「第几天除以 7」算周号:跨年那一周会错,得用 isocalendar()。
  2. 只报月表:月表看不出节奏,周表看不出趋势,两张都要。
  3. 把造数的设计值当实测值报:写进去 8%,算出来 5.7%,报 5.7%。
  4. groupby 完不排序就画图:星期会按字母序排,图看着像乱序。
自测三问(点开对答案) 1. 为什么这次的月均销售额要算出来? —— 它是判断「这个月好不好」的基准线。高于均线的只有五个月,这个结论光看十二个数看不出来。 2. 周末和工作日差 5.7%,为什么不是造数时写的 8%? —— 噪声把差距摊薄了。造的是期望值,跑出来是样本值,报数报样本值。 3. 按周统计为什么要用 isocalendar? —— ISO 周号按周一到周日切,跨年也对得上;自己除 7 会在年末年初错位。

四个粒度的形状都有了。下一篇往深一层:走势、环比、贡献度、客单价。

相关笔记