前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Python实现箱线图

Python实现箱线图

作者头像
用户11172986
发布2025-03-06 23:29:06
发布2025-03-06 23:29:06
1100
代码可运行
举报
文章被收录于专栏:气python风雨气python风雨
运行总次数:0
代码可运行

箱线图

  箱线图是一种统计图形,自身的各个部件自带统计学意义,这是与其他图形不同的特点。对于plot、scatter、contourf等图像,所见即所得,每个图像或颜色均代表一个数值,例如气温折线图表达气温的变化,每个点即代表该时刻气温。箱线图不同,绝大部分部件,无法看到具体数值,这是一种统计图而非数据原值。

箱线图的统计学及图形意义

  箱线图的统计学意义可以参考气象出版社出版的图书《大气科学中的统计方法》p上的内容。其图像各部分对应的意义如下图:

  根据上图,可得到箱线图各部件的意义。箱体中间横线默认为中位值。箱体数据样本量占总样本量的50%。   在matplotlib中,使用boxplot命令绘制箱线图,boxplot绘图命令比一般的plot、scatter更为高级,他拥有改变子图布局并固定其格式的底层。   boxplot命令绘制的箱线图在默认时是Line2D绘制,简单来说,就是类似plot命令,所有图形由Line2D线条构成,而非polygon。这个在后面对图形进行修饰美化时需要用到;boxplot还提供额外命令将箱体变为polygon。  箱线图中,箱体为中间矩形框,矩形框中间默认为中位线,上下伸出者为须,伸出者末尾横线为上(下)四分位线,箱体外点状物为flier。

纯手工箱线图与boxplot快速箱线图命令

  为了进一步理解箱线图的绘制,我们使用boxplot直接绘制箱线图,再使用纯手工的方式绘制一个箱线图。

代码语言:javascript
代码运行次数:0
复制
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import matplotlib.ticker as mticker
import matplotlib.colors as mcolors
import matplotlib as mpl
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#构造数据
data=np.array([0]+[1]*5+[2,3,4,5]+[10]+[11,12,13,14]+[15]*5+[30])
#计算中位值
median=np.median(data)
计算下四分位
Q1=np.percentile(data,25)
计算上四分位
Q3=np.percentile(data,75)
计算IQR
IQR=Q3-Q1

  因为Q3+1.5×IQR=36 大于data.max=30,所以该数据没有上异常值   因为Q1-1.5×IQR=-20 小于data.min=0,所以该数据没有下异常值   由于没有异常值,所以箱线图没有哪些外部的散点。

代码语言:javascript
代码运行次数:0
复制
fig=plt.figure(figsize=(8.5,4),dpi=400)
ax1=plt.subplot(121)
ax2=plt.subplot(122)
ax1.set_title('boxplot命令直接绘图')
ax1.boxplot(data)
ax1.scatter(1+np.random.rand(len(data))/20,data,c='tab:green',s=10,marker='^')
ax2.scatter(np.random.rand(len(data))/10,data,c='tab:green',s=10,marker='^')
ax2.set_title('纯手工打造箱线图')
ax2.plot([-0.25,0.25],[median,median],c='tab:orange',lw=1)
ax2.plot([-0.25,0.25],[Q1,Q1],c='k',lw=1)
ax2.plot([-0.25,0.25],[Q3,Q3],c='k',lw=1)
ax2.plot([-0.25,-0.25],[Q1,Q3],c='k',lw=1)
ax2.plot([0.25,0.25],[Q1,Q3],c='k',lw=1)
ax2.plot([-0.2,0.2],[30,30],c='k',lw=1)
ax2.plot([-0.2,0.2],[0,0],c='k',lw=1)
ax2.plot([0,0],[Q3,30],c='k',lw=1)
ax2.plot([0,0],[0,Q1],c='k',lw=1)
ax2.set(xlim=(-2,2),ylim=(-1,31))
plt.show()

箱线图的命令及主要修饰参数

  箱线图不同于之前我们提到的plot、contourf等绘图函数,这些绘图函数以绘图为主,需要出图后人工归纳特征,而箱线图出图即归纳好特征了。   matplotlib中的箱线图命令boxplot只需一个统计数据数组即可绘图,在传入后,x轴变为与数据对应的列数,而且不能再使用set_xlim、set_xticks等命令更改x轴样式。箱线图数据可以是列表、嵌套列表、一维数组、二维数组。   当数据源为列表、一维数组时,boxplot默认将这个数据作为一组数据进行统计,例如:

代码语言:javascript
代码运行次数:0
复制
data_list=[0]*4+[1]*5+[2]*3+[6]+[7]+[8]
ax.boxplot(data_list)

  由于仅传入一个单纯列表,输出的便是这个列表数据的统计特征,6、7、8作为flier形成三个点,中位值是1。   若传入的数据是嵌套列表或二维数组,则将嵌套列表每个嵌套作为一组数据,二维数组则是将每一列作为一组数据:

代码语言:javascript
代码运行次数:0
复制
data1=[0]*4+[1]*5+[2]*3+[6]+[7]+[8]
data2=[0]*5+[1]*7+[2]*9+[6]*3+[7]+[8]*4
data3=[-1]*5+[0]*7+[1]*9+[3]*3+[4]+[5]*4+[8]*4
data=[data1,data2,data3]
ax.boxplot(data)

  不难看出,箱线图将嵌套列表的三个列表拆为三个数据分别进行了统计。   若是二维数组,则按照列数分别统计,例如:

代码语言:javascript
代码运行次数:0
复制
data=np.random.rand(12).reshape(4,3)*10
ax.boxplot(data)

  这里我们创建了一个四行三列的二维数组,则生成三个箱线图以对应三列数据。   接下来,我们开始讲解常见的箱线图美化命令。前面已经提到,箱线图默认情况是以Line2D模式绘制的,简单来说,全图都是线条而已,所以我们修饰命令也是类似于plot命令。

箱线图的常见美化

  在第二小节中我们已经尝试了手工打造一个箱线图,而matplotlib的boxplot命令与我们手工绘制的箱线图没有本质区别,只是进行了更高级的封装,将明面上的箱线图绘制过程转向后台。   不过,当绘制默认的箱线图时,默认使用线命令Line2d绘制,这样的箱线图没有面积,也不能修改箱体颜色。当我们设置patch_artist=True时,就将开启箱线图的面元素,可以给其箱体上色了。   箱线图的美化主要依靠字典来进行,medianprops控制中位值线的样式,boxprops控制箱体样式,whiskerprops控制延长须样式,capprops控制延长须终止线样式,flierprops控制异常值散点样式。下面是一个分月风速统计箱线图美化后的程序及美化命令:

代码语言:javascript
代码运行次数:0
复制
plt.rcParams['font.sans-serif']=['FangSong']
fig=plt.figure(figsize=(4,2),dpi=500)
ax=fig.add_axes([0,0,1,1])
P1=ax.boxplot(result12,positions=np.arange(1,8),widths=0.5,patch_artist=True,notch=True,labels=station,
                medianprops={"linewidth": 0.5},
                boxprops={"linewidth": 0.5},
                whiskerprops={"linewidth": 0.5},
                capprops={"linewidth": 0.5},
                flierprops={"markersize": 1,},showfliers=True)
P2=ax.boxplot(result1,positions=np.arange(1,8)+8,widths=0.5,patch_artist=True,notch=True,labels=station,
                medianprops={"linewidth": 0.5},
                boxprops={"linewidth": 0.5},
                whiskerprops={"linewidth": 0.5},
                capprops={"linewidth": 0.5},
                flierprops={"markersize": 1,},showfliers=True)
P3=ax.boxplot(result2,positions=np.arange(1,8)+16,widths=0.5,patch_artist=True,notch=True,labels=station,
                medianprops={"linewidth": 0.5},
                boxprops={"linewidth": 0.5},
                whiskerprops={"linewidth": 0.5},
                capprops={"linewidth": 0.5},
                flierprops={"markersize": 1,},showfliers=True)
#给每个箱体上色
[p.set_facecolor('#99FFFF') for p in P1['boxes']]
[p.set_facecolor('#CCFFCC') for p in P2['boxes']]
[p.set_facecolor('#FF6666') for p in P3['boxes']]
ax.tick_params(axis='x',rotation=45,labelsize=5,pad=1)
ax.tick_params(axis='y',labelsize=7,pad=1)
ax.set_ylabel('风速m/s',fontsize=7)
ax.set_yticks([0,5,10,15,20,25])
ax.set_ylim(-5,25)
ax.set_xlim(0,24)
ax.grid(axis='y',linewidth=0.3,linestyle='--',ydata=[5,10,15,20,25])
ax.legend([mpatches.Rectangle((0, 0), 1, 1, facecolor=i,edgecolor='k',linewidth=0.3)for i in ['#99FFFF','#CCFFCC','#FF6666']],
           ['12月','1月','2月'],fontsize=7,frameon=False,loc='best', bbox_to_anchor=(0.75, -0.1), fancybox=False,ncols=3)

使用seaborn绘制箱线图

  作为一个架设在matplotlib上的更高级的统计图形快速绘制图包,seaborn集合了快速绘制箱线图的绘图命令。以下面一个虚构的降水数据为例:

代码语言:javascript
代码运行次数:0
复制
import pandas as pd
import numpy as np
file=r'C:\Users\Administrator\Desktop\三地降水量.xlsx'
df=pd.read_excel(file)

  这是一个三个地方的逐日降水量序列,但是对于seaborn来说是不合适的,这是一个宽格式的数据,seaborn要求数据必须是长格式的,所以需要进行转化:

代码语言:javascript
代码运行次数:0
复制
long_df=pd.melt(df,id_vars=['时间'],var_name='县市',value_name='降水量')

  然后使用seaborn提供的箱线图绘图命令直接绘制,指定x为三个地区,y为降水量:

代码语言:javascript
代码运行次数:0
复制
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['FangSong']
plt.rcParams['axes.unicode_minus']=False 
f,ax=plt.subplots(figsize=(5,4),dpi=500)
sns.boxplot(long_df,x='县市',y='降水量',width=0.2,flierprops={"marker": "x"})
ax.xaxis.grid(True)

  如果需要添加原始数据点,seaborn提供了一个抖动散点绘图命令stripplot,可以尽量避免原始数据之间的遮挡并绘制原始数据点:

代码语言:javascript
代码运行次数:0
复制
sns.stripplot(long_df,x='县市',y='降水量',size=2,color=".3")
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 气python风雨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 箱线图
    • 箱线图的统计学及图形意义
    • 纯手工箱线图与boxplot快速箱线图命令
    • 箱线图的命令及主要修饰参数
    • 箱线图的常见美化
    • 使用seaborn绘制箱线图
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档