Python绘图:箱线图的理解与绘制
一、箱线图简介
如下图所示,箱线图(箱形图、盒须图)是一种基于5
个统计量(上边界、上四分位数、中位数、下四分位数以及下边界)显示数据分布的标准化方法,其可以用来检测数据的异常值和数据分布的形状,以及数据集的离散程度。图中矩形框显示数据集的上下四分位数,而矩形框中延伸出的线段(触须)则用于显示其余数据的分布位置,剩下超过上下四分位间距的数据点则被视为“异常值”。
箱线图主要的组成元素及其具体含义如下所示:
- 下四分位数
Q1
:将所有数据按照从小到大的顺序排在第25%
的数; - 上四分位数
Q3
:将所有数据按照从小到大的顺序排在第75%
的数; - 四分位间距(IQR, Interquartile Range):统计学中的一种数学表示方法(也称为四分差),为上四分位数与下四分位之间的距离,可表示为\(\Delta = Q3 - Q1\)。
- 上边界:除异常点以外数据中的最大值,可表示为\(Q3 + 1.5 \Delta\);
- 下边界:除异常点以外数据中的最小值,可表示为\(Q1 - 1.5 \Delta\);
- 异常值:小于下边界与大于上边界的值。
二、箱线图的绘制
本文给出基于matplotlib与seaborn库的两种箱线图绘制方法。
2.1 基于matplotlib库的箱线图绘制
matplotlib中绘制箱线图的函数为boxplot()
,其函数原型如下所示:
matplotlib.pyplot.boxplot(x, notch=None, sym=None, vert=None, whis=None, positions=None, widths=None, patch_artist=None, bootstrap=None, usermedians=None, conf_intervals=None, meanline=None, showmeans=None, showcaps=None, showbox=None, showfliers=None, boxprops=None, labels=None, flierprops=None, medianprops=None, meanprops=None, capprops=None, whiskerprops=None, manage_ticks=True, autorange=False, zorder=None, capwidths=None, *, data=None)
(1)函数主要参数及功能
常用的参数及功能如下表所示,为了方便理解各个参数的含义,本文将其划分为三个不同类别:常规参数、显示控制参数以及细节属性参数。
参数 | 功能 | 参数 | 功能 |
---|---|---|---|
常规参数 | |||
x |
指定要绘制箱形图的数据 | notch |
是否绘制带缺口的箱形图 |
patch_artist |
是否填充箱体的颜色 | vert |
是否将箱线图垂直摆放 |
widths |
指定箱线图的宽度 | sym |
指定异常点的形状 |
whis |
指定上下边界与上下四分位数的距离 | labels |
为箱线图添加标签 |
capwidths |
设置须线帽长度 | position |
指定箱线图的位置 |
显示控制参数 | |||
showmeans |
是否显示均值点 | meanline |
是否显示均值线 |
showbox |
是否显示箱形图的箱体 | showcaps |
是否显示须线帽 |
showfliers |
是否显示异常值 | ||
细节属性参数 | |||
medianprops |
设置中位线属性 | meanprops |
设置均值点属性 |
boxprops |
设置箱体属性 | capprops |
设置须帽属性 |
whiskerprops |
设置须线属性 | flierprops |
设置异常点属性 |
注意💥:对于细节属性参数需要输入字典格式的数据,其设置方法可参考📖 python-matplotlib | 箱线图及解读 - 知乎
(2)函数返回值
boxplot()
函数是以字典格式返回箱线图的每个组件对象,每个键的键值为matplotlib.lines.Line2D
类对象的列表,具体包括:
boxes
:箱体的主体显示四分位数;medians
:每个箱体的中位数水平线;whiskers
:每个箱体的须线;caps
:须线末端的直线,即须线帽;fliers
:异常值;means
:均值点或直线。
注意💥:如果不启用箱线图的相应元素,相应键值则返回空列表。
(3)示例
更为详细的内容可参考matplotlib官方手册📚:matplotlib.pyplot.boxplot — Matplotlib 3.7.2 documentation。这里选取matplotlib官网上一个具有代表性的箱线图示例作为演示对象(参考🎨:Box plots with custom fill colors — Matplotlib 3.7.2 documentation)。在官网示例的基础上,本文添加了相关参数的使用方法并对代码进行注释,代码如下所示:
import matplotlib.pyplot as plt
import numpy as np
#! 解决不显示的问题:中文设置为宋体格式
plt.rcParams['font.family'] = ["Times New Roman", 'SimSun']
# 生成一个包含三个随机数的数组,每个随机数包含100个数据,且他们的标准差分别为1,2,3
all_data = [np.random.normal(0, std, size=100) for std in range(1,4)]
labels = ['$x_1$', '$x_2$', '$x_3$']
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(9, 4))
# 绘制矩形箱线图
bplot_rect = ax1.boxplot(
x=all_data, # 需要绘制的数据
vert=True, # 垂直排列箱线图
widths=0.3, # 箱形宽度
labels=labels, # 箱形图的标签
patch_artist=True, # 是否为箱子填充颜色,默认为False
medianprops={ # 设置中位线属性
'linestyle': '-', 'color': 'r', 'linewidth': 1.5
},
# showmeans=True, # 是否显示均值点,默认为False
# meanline=True, # 是否显示均值线,默认为False
# meanprops={ # 设置均值点属性
# 'marker': 'o', 'markersize': 7.5, 'markeredgewidth': 0.75, 'markerfacecolor': '#b7e1a1', 'markeredgecolor': 'r', 'color': 'k', 'linewidth': 1.5
# },
showfliers=True, # 是否显示异常值,默认为True
flierprops={ # 设置异常点属性
'marker': '^', 'markersize': 6.75, 'markeredgewidth': 0.75, 'markerfacecolor': '#ee5500', 'markeredgecolor': 'k'
},
whiskerprops={ # 设置须的线条属性
'linestyle': '--', 'linewidth': 1.2, 'color': '#480656'
},
capprops={
'linestyle': '-', 'linewidth': 1.5, 'color': '#480656'
}
)
title_rect = ax1.set_title("矩形箱形图")
# 绘制带缺口象形图
bplot_notch = ax2.boxplot(
x=all_data, # 需要绘制的数据
notch=True, # 是否带有缺口,默认False
# vert=True, # 垂直排列箱线图,默认为True
widths=0.3, # 箱形宽度
labels=labels, # 箱形图的标签
patch_artist=True, # 是否为箱子填充颜色,默认为False
medianprops={ # 设置中位线属性
'linestyle': '-', 'color': 'r', 'linewidth': 1.5
},
# showmeans=True, # 是否显示均值点,默认为False
# meanline=True, # 是否显示均值线,默认为False
# meanprops={ # 设置均值点属性
# 'marker': 'o', 'markersize': 7.5, 'markeredgewidth': 0.75, 'markerfacecolor': '#b7e1a1', 'markeredgecolor': 'r', 'color': 'k', 'linewidth': 1.5
# },
showfliers=True, # 是否显示异常值,默认为True
flierprops={ # 设置异常点属性
'marker': '^', 'markersize': 6.75, 'markeredgewidth': 0.75, 'markerfacecolor': '#ee5500', 'markeredgecolor': 'k'
},
whiskerprops={ # 设置须的线条属性
'linestyle': '--', 'linewidth': 1.2, 'color': '#480656'
},
capprops={
'linestyle': '-', 'linewidth': 1.5, 'color': '#480656'
},
)
title_notch = ax2.set_title("带有缺口的箱形图")
# 为箱形图填充颜色
colors = ['pink', 'lightblue', 'lightgreen']
for bplot in (bplot_rect, bplot_notch):
for patch, color in zip(bplot['boxes'], colors):
patch.set_facecolor(color)
# 添加水平网格线并设置轴标签
for ax in [ax1, ax2]:
ax.yaxis.grid(True)
ax.set_xlabel("样本")
ax.set_ylabel("观测值")
代码执行结果如下图所示
后续替换中文为宋体的图片
2.2 基于seaborn库的箱线图绘制
Seaborn是基于matplotlib的python数据可视化库。它提供了高层级的接口用于画出统计图。它与pandas库数据接口非常相近,可以直接使用pandas的数据结构。相比较于matplotlib的箱线图绘制,searborn绘制的更加美观。seaborn中绘制箱线图的函数为boxplot()
,其函数原型如下所示:
seaborn.boxplot(data=None, *, x=None, y=None, hue=None, hue_order=None, orient=None, color=None, palette=None, saturation=0.75, width=0.8, dodge=True, fliersize=5, linewidth=None, whis=1.5, ax=None, **kwargs)
注意💥:
(1)虽然seaborn的boxplot()
能以array
、list
以及DataFrame
。但是其更适合于对DataFrame
格式的数据进行箱线图绘制。因此,在绘制箱线图之前,建议将数据转换为DataFrame
格式。本文的介绍以DataFrame
格式的数据为例。
(2)由于seaborn是基于matplotlib的,因此我们可以直接调用matplotlib.boxplot
的参数对箱线图进行设置。
(1)函数主要参数功能及其返回值
常用的参数及功能如下表所示:
参数 | 功能 | 参数 | 功能 |
---|---|---|---|
x 、y |
数据或向量的变量名 | data |
用于绘图的数据集 |
width |
箱体的宽度 | linewidth |
构成图元素的灰线宽度 |
orient |
绘图方向,v (垂直)、h (水平) |
color |
所有元素的颜色 |
fliersize |
异常值标记的大小 | notch |
是否绘制带缺口的箱形图 |
whis |
控制在超过高低四分位时IQR的比例 | ax |
使用的Axes 轴对象,默认使用当前轴 |
palette |
调色板名称 | saturation |
控制用于绘制颜色的原始饱和度比例 |
hue |
指定色调的分组 | dodge |
使用色调嵌套时,元素是否沿分类轴移动 |
kwargs |
可调用matplotlib.axes.Axes.boxplot 参数,比如medianprops 、boxprops 等 |
seaborn.boxplot()
函数的返回值为当前绘制图像数matplotlib.Axes
据格式的句柄对象。
更为详细的内容可参考seaborn官方手册📚:seaborn.boxplot — seaborn 0.12.2 documentation。
(2)示例
下面通过若干个绘图示例来理解seaborn.boxplot
参数的功能:
import seaborn as sns
import matplotlib.pyplot as plt
#! 解决不显示的问题:中文设置为宋体格式
plt.rcParams['font.family'] = ["Times New Roman", 'SimSun']
df = sns.load_dataset("titanic")
fig, axs = plt.subplots(nrows=2, ncols=3, figsize=(14,11))
sns.boxplot(ax=axs[0,0], data=df, x ="age", y="class")
axs[0,0].set_title("图1:舱位等级的年龄分布", fontsize=14)
axs[0,0].xaxis.grid(True)
# sns.boxplot(ax=axs[0,1], data=df, x="age", y="class", hue="alive")
sns.boxplot(ax=axs[0,1], data=df, x="class", y="age", hue="alive") # 对掉x、y参数可以切换水平、垂直绘图
axs[0,1].set_ylabel('')
axs[0,1].set_title("图2:基于存活与否分组的舱位等级年龄分布", fontsize=14)
axs[0,1].yaxis.grid(True)
sns.boxplot(ax=axs[0,2], data=df[["age", "fare"]], orient="h")
axs[0,2].set_title("图3:绘制多列数值型数组的箱线图", fontsize=14)
axs[0,2].xaxis.grid(True)
sns.boxplot(ax=axs[1,0], data=df, x="fare", y="deck", hue="deck", dodge=False)
axs[1,0].set_title("图4:hue参数与dodge参数的作用", fontsize=14)
axs[1,0].xaxis.grid(True)
sns.boxplot(ax=axs[1,1], data=df, x="fare", y="deck", order=["G", "F", "E", "D", "C", "B", "A"], hue="deck", dodge=False)
axs[1,1].set_title("图5:改变图4中y轴的排列次序", fontsize=14)
axs[1,1].xaxis.grid(True)
sns.boxplot(
ax=axs[1,2], data=df, x="age", y="class",
notch=True, showcaps=False,
flierprops={"marker": "^"},
# boxprops={"facecolor": (.4, .6, .8, .5)},
medianprops={"color": "r"}
)
axs[1,2].set_title("图6:使用matplotlib.boxplot参数进行配置", fontsize=14)
axs[1,2].xaxis.grid(True)
防采坑💣:在使用
df = sns.load_dataset("titanic")
导入seaborn自带的数据时,由于网络原因会出现加载不了的问题。对此,可参考博文📖 解决seaborn数据无法导入的问题_无法解析导入 seaborn_ryo007gnnu的博客-CSDN博客进行排雷。
附录
博文鉴赏:
Python绘图待扩展阅读
本文来自博客园,作者:人工智能技术栈,转载请注明原文链接:https://www.cnblogs.com/metafullstack/p/17651922.html