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

一、小提琴图简介

1.1 小提琴图的概念

小提琴图Violin Plot)通常用于显示数据的分布及其概率密度,其结合了箱形图和密度函数的特征,可以很好的显示数据的分布形状。小提琴图使用核密度函数(KDE, Kernel Density Estimation)来计算样本的分布情况,其要素包括中位数、四分位间距以及置信区间。如下图所示,中间的黑色粗线条表示四分位数的范围,从其上延伸出来的细黑线表示95%置信区间,而白色点则为中位数。

与箱形图相比,小提琴图优势在于除了显示诸如中位数、四分位间距以及置信区间统计信息外,它还显示了数据的整体分布。小提琴图的内部是箱线图(有的图中位数会用白点表示,但归根结底都是箱线图的变化);外部包裹的就是核密度图,某区域图形面积越大,某个值附近分布的概率越大。特别是在处理多模态数据时,即有多峰值的分布数据时,小提琴图的优势就被更加地体现出来。

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

相比较于箱线图,小提琴图与箱线图核可以更为直观地展示数据的核密度分布情况。在理解小提琴图与箱线图之间的关系与区别之前,需要了解几个概念:

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

(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)高斯混合核密度函数、箱线图以及小提琴图的绘制

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

import numpy as np
import matplotlib.pyplot as plt

class TwoNomal():
    # mu1、sigma1为第一个高斯分布的均值与标准差
    # mu2、sigma2为第二个高斯分布的均值与标准差
    def __init__(self,mu1,mu2,sigma1,sigma2):
        self.mu1 = mu1
        self.sigma1 = sigma1
        self.mu2 = mu2
        self.sigma2 = sigma2
    # 双峰值密度函数生成方法
    def doubledensity(self,x):
        mu1 = self.mu1
        sigma1 = self.sigma1
        mu2 = self.mu2
        sigma2 = self.sigma2
        N1 = np.sqrt(2 * np.pi * np.power(sigma1, 2))
        fac1 = np.power(x - mu1, 2) / np.power(sigma1, 2)
        density1=np.exp(-fac1/2)/N1

        N2 = np.sqrt(2 * np.pi * np.power(sigma2, 2))
        fac2 = np.power(x - mu2, 2) / np.power(sigma2, 2)
        density2=np.exp(-fac2/2)/N2
        #print(density1,density2)
        density=0.5*density2+0.5*density1
        return density

# 生成双峰值高斯混合核函数类对象
N2 = TwoNomal(10,80,10,10)
#创建等差数列作为X
X = np.arange(-20,120,0.05)
# 生成双峰值高斯混合核函数样本
sample_two_gaussian = N2.doubledensity(X)
Y = N2.doubledensity(X)

# 调用plot_comparison函数绘图
plot_comparison(Y, "双峰分布")

代码执行结果如下图所示:

由上图可以看出,对于具有多模态性质的双峰分布,相比较于箱线图小提琴图不仅刻画了数据的中位数、四分位数的范围信息,还刻画了数据的核密度分布情况。

二、箱线图的绘制

本文给出基于matplotlib与seaborn库的两种小提琴图绘制方法。

2.1 基于matplotlib库的小提琴图绘制

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

matplotlib.pyplot.boxplot(dataset, positions=None, vert=True, widths=0.5, showmeans=False, showextrema=True, showmedians=False, quantiles=None, points=100, bw_method=None, *, data=None)

(1)函数主要参数及功能

常用的参数及功能如下表所示,为了方便理解各个参数的含义,本文将其划分为三个不同类别:常规参数显示控制参数以及细节属性参数

参数 功能 参数 功能
常规参数
dataset 输入的数据 position 小提琴的位置,默认为[1, 2, ..., n]
vert 小提琴的绘制方向,默认为True即垂直绘制 widths 小提琴的宽度,默认为0.5
showmeans 是否绘制样本均线,默认为False showextrema 是否绘制极值,默认为True
showmedians 是否绘制中位线 quantiles 如果为None,为每个小提琴设置一个[0,1]区间的浮动列表,用以绘制分位数
points 计算样本高斯核的样本数,默认为100 bw_method 计算带宽的方法,比如scottsilverman
显示控制参数
showmeans 是否显示均值点 meanline 是否显示均值线
showbox 是否显示箱形图的箱体 showcaps 是否显示须线帽
showfliers 是否显示异常值
细节属性参数
medianprops 设置中位线属性 meanprops 设置均值点属性
boxprops 设置箱体属性 capprops 设置须帽属性
whiskerprops 设置须线属性 flierprops 设置异常点属性

注意💥:对于细节属性参数需要输入字典格式的数据,其设置方法可参考📖 python-matplotlib | 箱线图及解读 - 知乎

(2)函数返回值

vilinplot()函数的返回值为包含小提琴图相应组件的字典,每个字典元素以列表形式表示:

  • bodies:每个小提琴填分布充面积的PolyCollection实例对象;
  • cmeans:每个小提琴分布的均值的LineCollection实例对象;
  • cmins:小提琴分布下边界的LineCollection实例对象;
  • cmaxes:小提琴分布上边界的LineCollection实例对象;
  • cbars:小提琴分布的分为数线条的LineColletion实例对象;
  • cmedians:每个小提琴分布的中位数的LineCollection实例对象。
  • cquantiles:每个小提琴分位数的LineCollection实例对象。

注意💥:如果不启用小提琴图的相应元素,相应键值则返回空列表。

(3)示例

更为详细的内容可参考matplotlib官方手册📚:matplotlib.pyplot.violinplot — Matplotlib 3.7.2 documentation。这里选取matplotlib官网上一个具有代表性的小提琴图示例作为演示对象(参考🎨:Violin plot customization — 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博客进行排雷。

附录

博文鉴赏:

本文相关待扩展阅读

posted @ 2023-08-26 13:54  人工智能技术栈  阅读(4854)  评论(0编辑  收藏  举报