Seaborn 0.7.1箱线图四分位数疑问:Q1结果与预期不符
为什么Seaborn 0.7.1的箱线图Q1和手动计算的不一样?
这其实是四分位数计算方法的差异导致的,你手动用的是经典的Tukey四分位数法,但Seaborn 0.7.1底层依赖的计算逻辑和它不同。
先拆解一下细节:
- 你的数据排序后是:
[2, 4, 5, 5, 8, 8, 9](共7个元素) - 你手动计算的逻辑:
- 中位数Q2是第4个元素:
5 - Q1取前半部分(
[2,4,5])的中位数:4 - Q3取后半部分(
[8,8,9])的中位数:8
- 中位数Q2是第4个元素:
但Seaborn 0.7.1在绘制箱线图时,底层调用的是Matplotlib的boxplot函数,而当时的Matplotlib是用numpy.percentile来计算分位数,默认采用线性插值的方式。具体计算过程是:
- 25%分位数的位置公式为:
(n-1)*p,这里n=7,p=0.25,得到(7-1)*0.25=1.5 - 这个位置对应数组中索引1(值4)和索引2(值5)之间的位置,用线性插值计算:
4 + (5-4)*0.5 = 4.5,这就是你图里看到的Q1。
你可以用下面的代码验证这个结果:
import numpy as np arr = np.array([2, 4, 5, 5, 8, 8, 9]) print(np.percentile(arr, 25)) # 输出:4.5
如果想要得到和手动计算一致的箱线图,你可以手动计算分位数后用Matplotlib直接绘制,或者使用scipy.stats里的分位数计算方法(对应Tukey的逻辑):
import matplotlib.pyplot as plt from scipy.stats.mstats import mquantiles arr = np.array([2,4,5,5,8,8,9]) # 用Tukey方法计算分位数 q1, q2, q3 = mquantiles(arr, [0.25, 0.5, 0.75], alphap=0.5, betap=0.5) # 手动绘制符合预期的箱线图 fig, ax = plt.subplots() box = ax.boxplot(arr, showfliers=False) # 调整箱子的关键位置为手动计算的分位数 box['boxes'][0].set_ydata([q1, q1, q3, q3, q1]) box['medians'][0].set_ydata([q2, q2]) box['caps'][0].set_ydata([arr.min(), arr.min()]) box['caps'][1].set_ydata([arr.max(), arr.max()]) box['whiskers'][0].set_ydata([arr.min(), q1]) box['whiskers'][1].set_ydata([q3, arr.max()]) plt.show()
简单来说,不同统计工具对四分位数的计算没有统一标准,常见的就有五六种方法,Seaborn旧版本用的是Numpy默认的线性插值法,和你手动的Tukey法逻辑不同,所以结果出现了差异。
内容的提问来源于stack exchange,提问作者Vishesh
相关产品推荐
相关产品推荐

