Python绘图:小提琴图的理解与绘制

metafullstack / 2023-08-26 / 原文

目录
  • 一、小提琴图简介
    • 1.1 小提琴图的概念
    • 1.2 小提琴图与箱线图之间的关系与区别
  • 二、箱线图的绘制
    • 2.1 基于matplotlib库的箱线图绘制
      • (1)函数主要参数及功能
      • (2)函数返回值
      • (3)示例
    • 2.2 基于seaborn库的箱线图绘制
      • (1)函数主要参数功能及其返回值
      • (2)示例
    • 附录
    • Python绘图待扩展阅读

一、小提琴图简介

1.1 小提琴图的概念

小提琴图Violin Plot)通常用于显示数据的分布及其概率密度,其结合了箱形图和密度函数的特征,可以很好的显示数据的分布形状。如下图所示,中间的黑色粗线条表示四分位数的范围,从其上延伸出来的细黑线表示95%置信区间,而白色点则为中位数。

下面内容待定
箱形图在数据显示方面受到限制,简单的设计往往隐藏了有关数据分布的重要细节。例如使用箱形图时,我们不能了解数据分布是双模还是多模。虽然小提琴图可以显示更多详情,但它们也可能包含较多干扰信息。

小提琴图的内部是箱线图(有的图中位数会用白点表示,但归根结底都是箱线图的变化);外部包裹的就是核密度图,某区域图形面积越大,某个值附近分布的概率越大。

通过箱线图,可以查看有关数据的基本分布信息,例如中位数,平均值,四分位数,以及最大值和最小值,但不会显示数据在整个范围内的分布。如果数据的分布有多个峰值(也就是数据分布极其不均匀),那么箱线图就无法展现这一信息,这时候小提琴图的优势就展现出来了!

与箱形图相比,小提琴图毫无疑问的优势在于:除了显示上述的统计数据外,它还显示了数据的整体分布。这个差异点很有意义,特别是在处理多模态数据时,即有多峰值的分布。

1.2 小提琴图与箱线图之间的关系与区别

小提琴图与箱线图核可以更为直观地展示密度函数以及高斯混合体的数据分布情况。在理解小提琴图与箱线图之间的关系与区别之前,需要了解一下几个概念:

核密度函数图:本质上是直方图的拟合曲线,其可以看作概率密度曲线。以正态分布的核密度函数为例,可结合博文📖 如何通俗的理解正态分布 - 知乎来理解核密度函数图。
高斯混合体:一种多模态分布,即多个高斯分布的混合(即叠加),同样可以将其看作直方图的概率密度曲线。以高斯混合模型(Gaussian Mixture Models)为例子,可结合博文📖 如何通俗的理解高斯混合模型(Gaussian Mixture Models) - 知乎来理解。
箱线图的理解可以参考📖 Python绘图:箱线图的理解与绘制 - 人工智能技术栈 - 博客园。

下面我们分别绘制小提琴图箱线图关于核密度函数高斯混合体的结果图来理解他们之间的关系与区别。

(1)标准正态分布核密度函数、箱线图以及小提琴图的绘制

对于正态分布数据,下面定义一个函数用于绘制如下内容:

  • 带有内核密度函数的直方图;
  • 箱线图;
  • 小提琴图
import seaborn as sns
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import rcParams

#! 解决不显示的问题:中文设置为宋体格式
plt.rcParams['font.family'] = ["Times New Roman", 'SimSun']

rcParams['xtick.direction'] = 'in'
rcParams['ytick.direction'] = 'in'

# 绘制正态分布核密度函数、箱线图以及小提琴图的函数
def plot_comparison(x, title):
    fig, ax = plt.subplots(3, 1, figsize=(7, 5), sharex=True)

    sns.distplot(x, ax=ax[0])
    ax[0].set_title("Histogram + KDE", fontsize=12)
    ax[0].tick_params(axis="both", labelsize=11)
    # ax[0].yaxis.grid(True, zorder=-1)

    sns.boxplot(x, ax=ax[1])
    ax[1].set_title("Boxplot", fontsize=12)
    ax[1].set_ylabel("label", fontsize=12)
    # ax[1].xaxis.grid(True)

    sns.violinplot(x, ax=ax[2])
    ax[2].set_title("Violin plot", fontsize=12)
    ax[2].set_ylabel("label", fontsize=12)
    ax[2].tick_params(axis="both", labelsize=11)
    # ax[2].xaxis.grid(True)

    fig.suptitle(title, fontsize=14)
    plt.show()

# 函数的调用与图片绘制
N = 10 ** 4
sample_gaussian = np.random.normal(size=N)
plot_comparison(sample_gaussian, '标准正态分布')

由上图可以看出,小提琴图的核密度图与添加在直方图上的核密度图是一样的。小提琴图中较宽的部分代表观测值取值的概率较高,较窄的部分则对应于较低的概率。然而这在箱线图中是无法直观表示的,因此小提琴图比箱形图包含更多的数据分布信息。

(2)高斯混合体核密度函数、箱线图以及小提琴图的绘制

下面我们通过高斯混合体的密度函数来构建一个双模态分布,来进一步直观地理解:相对于箱线图,小提琴图包含更多的数据分布信息。

二、箱线图的绘制

本文给出基于matplotlib与seaborn库的两种箱线图绘制方法。

2.1 基于matplotlib库的箱线图绘制

matplotlib中绘制箱线图的函数为boxplot(),其函数原型如下所示:

matplotlib.pyplot.boxplot()

(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)。在官网示例的基础上,本文添加了相关参数的使用方法并对代码进行注释,代码如下所示:


代码执行结果如下图所示

后续替换中文为宋体的图片

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参数的功能:


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

附录

博文鉴赏:

  • 📖 如何通俗的理解小提琴图 - 知乎
  • 📖 解读文献里的那些图——小提琴图、核密度图、箱线图 - 知乎
  • 📖
  • 📖 三分钟掌握盒须图,轻松了解数据分布

Python绘图待扩展阅读