箱型图绘制中使用的四分位数(quantiles)的计算,网上存在有多种算法,各种软件之间并没有统一。导致自己用matplotlib画出来的图和隔壁用jump画出来的不一样。网上查阅了一些资料,各种资料之间的说明不完全相同(核心应该是一样的),作为笔记记录下自己目前最能理解的一种解释。
目录
1.四分位点(Q1,Q2,Q3)的定义
来源wiki英文版(wiki不要随便切语言,不是翻译,感觉是换了语种的人重新写的,内容不完全一样)Quartile - Wikipedia
- The first quartile (Q1) is defined as the 25th percentile where lowest 25% data is below this point. It is also known as the lower quartile.
- The second quartile (Q2) is the median of a data set; thus 50% of the data lies below this point.
- The third quartile (Q3) is the 75th percentile where lowest 75% data is below this point. It is known as the upper quartile, as 75% of the data lies below this point.[1]
- Q1(第一四分位数):你的数据中有25%在此点以下。(可以理解为小于或等于)
- Q2(第二四分位数):这个计算一般不会出歧义,定义为median(中位数),你数据的50%在此点以下。
- Q3(第三四分位数):数据中的75%在此点以下。
2.计算方法
英文wiki上记载了method1~4一共四种计算方法,为了方便记忆,在此仅列出statistics.quantiles' 的method="exclusive" 以及 method="inclusive"的两种计算方法。对应excel function的QUARTILE.EXC和QUARTILE.INC。
exclusive(“排外的”计算方法)
Q1,Q3的位置确定方法为:
例如数据data = [10, 40, 60, 90],n=4,用来表示第n号位置上的数。带入计算如下:
说明:Q1计算得到的整数部分是1,也就是说第一四分位数在第一个数(本例中为10)右侧。之后看小数部分为0.25,则使用其后的40减去10,再乘以此0.25。求和即可得到第一四分位数为17.5。同理得到Q3第三四分位数为82.5。如果你的n+1可以被4整除,则直接取整除所得位置上的数。
inclusive(“包含一切的”计算方法)
计算公式为:
计算方法与exclusive相同,依然使用同一组数据,计算得:
Q2的计算方法几乎没什么争议,中位数。如果是偶数个数据则取中间两个数的平均,如果是奇数个数据直接取最中间位置上的数。
使用python的statistics.quantiles计算显示如下:
from statistics import quantiles
data3=[10,40,60,90]
print(quantiles(data3,method='exclusive'))
print(quantiles(data3,method='inclusive'))
[17.5, 50.0, 82.5] [32.5, 50.0, 67.5]
使用Excel绘制箱型图的时候,默认的是按照exclusive结果,但是其实可以右键在格式设定里面自由选择想用的方法(鼠标分别选中箱色块之后右键在右侧栏调)。如下图,个人感觉使用inclusive的话更能看清楚各组数据是更靠近中心还是更靠近两头…?
目前主要软件各自使用的计算方法:来自wiki
据说在真正应用场景数据量很大的时候,这两种方法计算出来的Q1,Q3也会更加接近。并且,Q1和Q3只是用来表示1/4以下的数据,3/4以下的数据所在位置,即使计算方法不同也能同样的表示数据的分布趋势。(只要别把不同方法绘制的图混在一起看)所以应该不存在对错的问题。
3.使用Matplotlib绘制时
回到matplotlib的使用上来说。根据官网提供的boxplot的源代码链接,可以看到其使用cbook.boxplot_stats来计算,而boxplot_stats又使用numpy.percentile来计算q1,q3。
查看numpy的官方说明https://numpy.org/doc/stable/reference/generated/numpy.quantile.html
这里面的计算方法就罗列的更加细致了。总而言之就是如果numpy计算的时候发现你要求的q分位点落在和
之间,那么他会根据用户指定的method去计算一个位于二者之间虚拟的数
。
默认的method使用的是“linear”,linear情况下 alpha=beta=1,也就是i+g=q*(n-1)+1。也就是刚才的inclusive计算方法。如果你把他method改成“weibull”,这时他会用alpha=beta=0,也就是i+g=q*(n+1)方法,即exclusive方法。
可惜的是matplotlib调用np.percentile()的时候没有给method参数,所以默认即为使用inclusive的结果。
所以如果非要改的话,这儿有个参考就是强行复制一份boxplot_stats,然后根据需要修改参数…如果哪位朋友知道针对这个情况的更新,能告知的话感激不尽orz
在Matplotlib中给出Boxplot的自定义四分位数范围-腾讯云开发者社区-腾讯云 (tencent.com)
补充:关于箱型图的其他细节
参考来源:Box-Plots with Statistical Details - all you need to know - YouTube
IQR,Outlier,Extreme
绘制成图后,Q1到Q3之间的部分为IQR(Interquartile Range 四分位距),从Q3往上,Q1往下1.5倍的IQR距离分别为上界和下界,超出这个边界的数据称为outlier(异常值,离群值)。如果有数据超出了Q3+3*IQR,这些就被判定为Extreme,并且应当在分析数据时被排除。而Outlier要视情况而定,有时Outlier甚至可以提供非常有意义的参考。
Max, Min, Whisker
方块两侧伸出来的水平线貌似称为whisker(胡须),胡须末端的两条段线其实是用来表示数据中的Max和Min值的位置。弧线线的长度受到IQR的制约,如果最大值落在Q3+1.5倍IQR内,那么短竖线所在位置即为Max(Min同理)。而Max的位置不会无限延长,当你数据中的最大值超过1.5*IQR,那么超出部分会被视为异常值,以点的形式展示。
以Matplotlib绘制示例展示:
import matplotlib.pyplot as plt
fig,ax =plt.subplots(nrows=1,ncols=2,figsize=(10,4))
fig.suptitle("TITLE")
# fig.supylabel("YY") # 距离太远,不好用,不如直接给ax[0]设置Y轴
data1 = [[10,20,30,40,70],
[9,20,33,40,72],
[10,20,30,40,50]
]
bplot1 = ax[0].boxplot(data1,notch = False)
ax[0].yaxis.grid(True)
三组数据的IQR均为(40-20)*1.5=30,也就是说计算出的胡须上限应该是70,但是当各组数据中的Max值分别为70,72,50时,绘制的箱型图如下所示。中间数据的最大值72被判定为outlier,此时上方的胡须末端直接落在倒数第二大的数字处,本例和Q3直接重叠。
Notch(缺口)
当你对数据进行对比时,你可以查看他们的median(中位数)是否相同,但是光看计算出来的,Median貌似不够,这里引入了中位数的置信区间(Condicence Interval of median)的概念。用
来计算notch的上下端所在的位置。如下图所示,因为计算公式中的n代表的是样本的数量,当数据太小时,计算出来的notch上下端经常会超过Q3,Q1(少量的样本导致了一个大的置信区间),画出一个翻折的图,这种情况下其实不推荐使用这个置信区间。【绘图建议标明样本的数量n。】
如果两组数据的notches(Median置信区间)有重叠,那么这些样本们很可能没有大不同。
Average(平均值)
另外,也建议在箱型图中绘制出样本的平均值(Average)。如果样本的均值和中位数很近,那么数据通常是呈现正态分布的。但是如果平均值和中位数很远,那么数据很有可能是歪曲的(不是一个漂亮的正态曲线)。
相关参考链接汇总
- Matplotlib绘制箱线图_方差平均数做图-CSDN博客
- statistics.quantiles statistics — Mathematical statistics functions — Python 3.12.2 documentation
- numpy.quantile官方说明numpy.quantile — NumPy v1.26 Manual
- matplotlib.axes.Axes.boxplot
- Quartile - Wikipedia
- Box plot - Wikipedia
- 四分位数_百度百科 (baidu.com)
- Matplotlib boxplot select方法计算四分位数值 - IT工具网 (coder.work)
- 外网提问:
- Matplotlib boxplot select method to calculate the quartile values - Stack Overflow
- python - numpy.quantile and statistics.quantiles are calculating different. which one is true? - Stack Overflow