一、箱线图简介

如下图所示,箱线图(箱形图、盒须图)是一种基于5个统计量(上边界、上四分位数、中位数、下四分位数以及下边界)显示数据分布的标准化方法,其可以用来检测数据的异常值和数据分布的形状,以及数据集的离散程度。图中矩形框显示数据集的上下四分位数,而矩形框中延伸出的线段(触须)则用于显示其余数据的分布位置,剩下超过上下四分位间距的数据点则被视为“异常值”。

箱线图主要的组成元素及其具体含义如下所示:

  • 下四分位数Q1:将所有数据按照从小到大的顺序排在第25%的数;
  • 上四分位数Q3:将所有数据按照从小到大的顺序排在第75%的数;
  • 四分位间距(IQR, Interquartile Range):统计学中的一种数学表示方法(也称为四分差),为上四分位数与下四分位之间的距离,可表示为Δ=Q3−Q1Δ=𝑄3−𝑄1。
  • 上边界:除异常点以外数据中的最大值,可表示为Q3+1.5Δ𝑄3+1.5Δ;
  • 下边界:除异常点以外数据中的最小值,可表示为Q1−1.5Δ𝑄1−1.5Δ;
  • 异常值:小于下边界与大于上边界的值。

二、箱线图的绘制

本文给出基于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()能以arraylist以及DataFrame。但是其更适合于对DataFrame格式的数据进行箱线图绘制。因此,在绘制箱线图之前,建议将数据转换为DataFrame格式。本文的介绍以DataFrame格式的数据为例
(2)由于seaborn是基于matplotlib的,因此我们可以直接调用matplotlib.boxplot的参数对箱线图进行设置。

(1)函数主要参数功能及其返回值

常用的参数及功能如下表所示:

参数功能参数功能
xy数据或向量的变量名data用于绘图的数据集
width箱体的宽度linewidth构成图元素的灰线宽度
orient绘图方向,v(垂直)、h(水平)color所有元素的颜色
fliersize异常值标记的大小notch是否绘制带缺口的箱形图
whis控制在超过高低四分位时IQR的比例ax使用的Axes轴对象,默认使用当前轴
palette调色板名称saturation控制用于绘制颜色的原始饱和度比例
hue指定色调的分组dodge使用色调嵌套时,元素是否沿分类轴移动
kwargs可调用matplotlib.axes.Axes.boxplot参数,比如medianpropsboxprops

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)

PYTHON 折叠 复制 全屏

防采坑💣:在使用df = sns.load_dataset("titanic")导入seaborn自带的数据时,由于网络原因会出现加载不了的问题。对此,可参考博文📖 解决seaborn数据无法导入的问题_无法解析导入

相关阅读:

1、https://blog.wanwuguiyi.com/python-plt-plot/ 

2、https://blog.wanwuguiyi.com/python-real-esrgan/

3、https://blog.wanwuguiyi.com/python-opencv-lib/

4、https://blog.wanwuguiyi.com/python-matplotlib-pyplot-learning/

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐