Python绘图:小提琴图的理解与绘制
一、小提琴图简介
1.1 小提琴图的概念
小提琴图(Violin Plot
)通常用于显示数据的分布及其概率密度,其结合了箱形图和密度函数的特征,可以很好的显示数据的分布形状。小提琴图使用核密度函数(KDE, Kernel Density Estimation)来计算样本的分布情况,其要素包括中位数、四分位间距以及置信区间。如下图所示,中间的黑色粗线条表示四分位数的范围,从其上延伸出来的细黑线表示95%
置信区间,而白色点则为中位数。
与箱形图相比,小提琴图优势在于除了显示诸如中位数、四分位间距以及置信区间统计信息外,它还显示了数据的整体分布。小提琴图的内部是箱线图(有的图中位数会用白点表示,但归根结底都是箱线图的变化);外部包裹的就是核密度图,某区域图形面积越大,某个值附近分布的概率越大。特别是在处理多模态数据时,即有多峰值的分布数据时,小提琴图的优势就被更加地体现出来。
1.2 小提琴图与箱线图之间的关系与区别
相比较于箱线图,小提琴图与箱线图核可以更为直观地展示数据的核密度分布情况。在理解小提琴图与箱线图之间的关系与区别之前,需要了解几个概念:
- 核密度估计(KDE, Kernel Density Estimation):作为一种用于估计概率密度函数的非参数方法,其是采用平滑的峰值函数来拟合样本数据,从而对真实的概率分布曲线进行模拟。核函数估计是通过核函数(比如高斯核)将每个数据点的数据、带宽作为核核函数的参数,得到
N
个核函数,再线性叠加就形成了核密度的估计函数(文献1 📖:KDE概念;文献2 📖: 基于Python的KDE实现方法)。 - 高斯混合模型(GMM, Gaussian Mixture Model):一种多模态分布,即多个高斯分布的混合(即叠加),同样可以将其看作直方图的核密度曲线(文献1 📖:高斯混合模型的概念;文献2 📖: 基于Python的双峰分布实现方法;文献3 📖: 基于Python的三峰分布实现方法)。
- 箱线图的理解可以参考📖 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)高斯混合核密度函数、箱线图以及小提琴图的绘制
下面我们通过高斯混合体的密度函数来构建一个双模态分布,来进一步直观地理解:相对于箱线图,小提琴图包含更多的数据分布信息。下面为生成双峰分布概率密度的代码:
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 |
计算带宽的方法,比如scott 或silverman 等 |
显示控制参数 | |||
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()
能以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
参数的功能:
防采坑💣:在使用
df = sns.load_dataset("titanic")
导入seaborn自带的数据时,由于网络原因会出现加载不了的问题。对此,可参考博文📖 解决seaborn数据无法导入的问题_无法解析导入 seaborn_ryo007gnnu的博客-CSDN博客进行排雷。
附录
博文鉴赏:
本文相关待扩展阅读
本文来自博客园,作者:人工智能技术栈,转载请注明原文链接:https://www.cnblogs.com/metafullstack/p/17658735.html