Python折线图的分析过程和画图的方法

说起折线图,很多人都觉得非常简单,不就是一些点连成的线吗?用 Excel 几秒钟就能画出一张折线图。

真的就这么简单吗?

想一想:在普通的折线图中,如何自动地添加一条代表平均值的横线?如何添加一条带箭头的趋势线?如何快速地标注最大值和最小值?如何标注特殊事件?如何对折线图进行数据分析?

下面我们用一个具体的案例,演示折线图的分析过程和画图的方法。

一个案例

根据某公司 2019 年 9 月份每天的销量数据,画出如下一张折线图:

通过观察可以看到,销量每隔几天就有一个波谷,对照日历,发现一个规律:这些销量比较低的日期,都是周末或节假日。

如果理解了业务的周期性,那么在分析数据时,就能排除一些干扰,更快地找到对业务真正有价值的信息。

排除周期性的因素之后,我们观察折线图中的最大值和最小值,看看它们是否在正常范围以内,如果不是的话,那么要分析背后的原因。

比如说,9 月 30 日的销量最高,明显高于平时的正常水平,经过与业务沟通和分析发现,是因为这一天做了打折促销的运营活动。

在折线图中,有一条代表平均值的横线,以及一条带箭头的趋势线,它们有助于对数据整体趋势的把握。

从上面的图中可以看出,中秋节放假之后,销量有所上升,结合广告费的投入数据进行分析,计算它们相关系数,发现销量与广告费之间具有比较强的正相关性,也就是说,中秋节之后,销量上升的主要原因,是公司加大了广告费的投入。

通过上面的分析解读,我们知道,折线图能直观地反映出数据随着时间变化的趋势,让数据更容易进行对比,发现数据背后规律性的知识,从而帮助管理者更好地做出决策。

画图不是为了炫技,而是为了提高信息传递的效率。你不妨反思一下自己画过的图,是不是提高了信息传递的效率呢?

画图方法

能画折线图的软件工具有很多,本文采用的是 Python中的 matplotlib库。

Jupyter Lab 中运行以下 Python代码,就可以画出上面那张折线图。

读取数据

# 读取每日销售数据
df = pd.read_excel('2019年9月每日销售.xlsx')

df
日期  实际销量
0   2019-09-01  7
1   2019-09-02  16
2   2019-09-03  18
3   2019-09-04  16
4   2019-09-05  18
5   2019-09-06  16
6   2019-09-07  9
7   2019-09-08  7
8   2019-09-09  16
9   2019-09-10  15
10  2019-09-11  17
11  2019-09-12  16
12  2019-09-13  3
13  2019-09-14  6
14  2019-09-15  7
15  2019-09-16  25
16  2019-09-17  23
17  2019-09-18  22
18  2019-09-19  23
19  2019-09-20  21
20  2019-09-21  13
21  2019-09-22  12
22  2019-09-23  22
23  2019-09-24  23
24  2019-09-25  23
25  2019-09-26  22
26  2019-09-27  24
27  2019-09-28  13
28  2019-09-29  12
29  2019-09-30  29

开始分析和画图

# 定义画图的数据
x = df.日期
y = df.实际销量

# 定义颜色
color1 = '#0085c3'
color2 = '#7ab800'
color3 = '#dc5034'

# 设置图像大小
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111)

# 绘制折线图
ax.plot(x, y, marker='o', color=color1)

fig
# 标注最大值
ax.text(x[y.idxmax()]+timedelta(hours=-12),
        y.max()+1, y.max(),
        color=color1, fontsize=15)

# 标注最小值
ax.text(x[y.idxmin()]+timedelta(hours=-9),
        y.min()-2, y.min(),
        color=color1, fontsize=15)
fig
# 计算 7 天移动平均
y2 = y.rolling(7).mean()

# 绘制趋势线
ax.plot(x, y2, ls='--', color=color2, label='7 天移动平均')

fig
# 绘制平均值线
ax.hlines(y.mean(), x[0], x[-1:],
          linestyles='-.', colors=color3)

# 标注平均值
ax.text(x[-1:]+timedelta(days=-7.5), y.mean()-2,
        '平均值: ' + str(round(y.mean(),1)),
        color=color3, fontsize=15)
fig
# 绘制箭头
plt.annotate('', xy=(x[-1:], y2[-1:]),
             xytext=(x[-2:-1], y2[-2:-1]),
             arrowprops=dict(arrowstyle='->',
                             color=color2,
                             shrinkB=0))

# 标注特殊事件
ax.annotate('中秋节', xy=(x[y.idxmin()], y.min()), color=color1,
             xytext=(x[y.idxmin()]+timedelta(days=1.5), y.min()-2),
             arrowprops=dict(arrowstyle='->', color=color1), fontsize=15)

ax.annotate('打折促销', xy=(x[y.idxmax()], y.max()), color=color1,
             xytext=(x[y.idxmax()]+timedelta(days=-5), y.max()+2),
             arrowprops=dict(arrowstyle='->', color=color1), fontsize=15)

fig
# 设置网格线
ax.grid(ls=':', color='gray', alpha=0.6)

# 设置图例的位置和大小
ax.legend(loc='upper left', fontsize=12)

# 设置坐标轴标签的角度和大小
plt.xticks(rotation=90, fontsize=12)
plt.yticks(fontsize=12)

# 设置 y 轴的刻度范围
ax.set_ylim(0, y.max()+5)

# 设置图表标题
_ = ax.set_title('2019年9月每日销量变化趋势', fontsize=25)

fig

补充

Series.idxmax(self,axis = 0,skipna = True,* args,** kwargs )返回最大值的行标签

代码合集

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import timedelta

# 正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']

# 正常显示负号
plt.rcParams['axes.unicode_minus'] = False

# 读取每日销售数据
df = pd.read_excel('./data/2019年9月每日销售.xlsx')

# 定义画图的数据
x = df.日期
y = df.实际销量

# 定义颜色
color1 = '#0085c3'
color2 = '#7ab800'
color3 = '#dc5034'

# 设置图像大小
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111)

# 绘制折线图
ax.plot(x, y, marker='o', color=color1)

# 标注最大值
ax.text(x[y.idxmax()]+timedelta(hours=-12),
        y.max()+1, y.max(),
        color=color1, fontsize=15)

# 标注最小值
ax.text(x[y.idxmin()]+timedelta(hours=-9),
        y.min()-2, y.min(),
        color=color1, fontsize=15)

# 计算 7 天移动平均
y2 = y.rolling(7).mean()

# 绘制趋势线
ax.plot(x, y2, ls='--', color=color2, label='7 天移动平均')

# 绘制箭头
plt.annotate('', xy=(x[-1:], y2[-1:]),
             xytext=(x[-2:-1], y2[-2:-1]),
             arrowprops=dict(arrowstyle='->',
                             color=color2,
                             shrinkB=0))

# 绘制平均值线
ax.hlines(y.mean(), x[0], x[-1:],
          linestyles='-.', colors=color3)

# 标注平均值
ax.text(x[-1:]+timedelta(days=-7.5), y.mean()-2,
        '平均值: ' + str(round(y.mean(),1)),
        color=color3, fontsize=15)

# 标注特殊事件
ax.annotate('中秋节', xy=(x[y.idxmin()], y.min()), color=color1,
             xytext=(x[y.idxmin()]+timedelta(days=1.5), y.min()-2),
             arrowprops=dict(arrowstyle='->', color=color1), fontsize=15)

ax.annotate('打折促销', xy=(x[y.idxmax()], y.max()), color=color1,
             xytext=(x[y.idxmax()]+timedelta(days=-5), y.max()+2),
             arrowprops=dict(arrowstyle='->', color=color1), fontsize=15)

# 设置网格线
ax.grid(ls=':', color='gray', alpha=0.6)

# 设置图例的位置和大小
ax.legend(loc='upper left', fontsize=12)

# 设置坐标轴标签的角度和大小
plt.xticks(rotation=90, fontsize=12)
plt.yticks(fontsize=12)

# 设置 y 轴的刻度范围
ax.set_ylim(0, y.max()+5)

# 设置图表标题
_ = ax.set_title('2019年9月每日销量变化趋势', fontsize=25)

学习来源

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。