(代码详解)绘制箱线图+找离群点的具体位置+同时绘制多组数据的箱线图

       箱线图,是一种专门用于显示一组数据分散情况的统计图,通常呈现出一个箱子的形状。这种图形的主要作用是反映原始数据的分布特征,以及进行多组数据分布特征的比较。

      每一个箱子都包含一些关键的数学统计量,比如中位数、上四分位数(Q3)、下四分位数(Q1)、最大值、最小值等,它们共同揭示了数据的中心位置和散布范围。这些信息不仅能分析不同类别数据各层次水平的差异,还能揭示数据间的离散程度、异常值、以及分布差异等信息。

      在python中可以使用`matplotlib`和`seaborn`第三方库,来绘制箱线图

两种方法的区别

      使用 Matplotlib 库中的 pyplot 模块绘制箱线图。它提供了基本的箱线图功能,但可能不如其他专门针对数据可视化的库(如 Seaborn)那么美观和易用。

      使用 Seaborn 库绘制箱线图。Seaborn 是一个基于 Matplotlib 的数据可视化库,它提供了更高级的绘图功能,如更美观的样式、颜色映射等。使用 Seaborn 绘制箱线图可以使图形更加美观和易于理解。

     总结:如果你需要一个简单的箱线图,可以使用Matplotlib ;如果你希望获得更好的视觉效果和更丰富的功能,可以使用 Seaborn。

下面来介绍一下使用Seaborn如何绘制箱线图

(一)基础箱线图

代码(有注释):

#导入库
import matplotlib.pyplot as plt
import seaborn as sns

# 示例数据
data = [50, 60, 70, 80, 90, 100, 66, 85, 90, 79, 85, 140,-5,5]
plt.figure(figsize=(15,6))#创建图形,设置图形的尺寸
sns.set(font='SimHei')#设置显示中文字符,解决Seaborn中文显示问题

sns.boxplot(data)#用于绘制箱线图的数据为data

plt.tick_params(labelsize=20) #刻度字体大小20

plt.show()#画图

结果:

       从上面的箱线图我们可以看到,有三个离群点,其中两个在最下值下方,有一个超过了最大值。

     上面的箱线图是呈水平绘制的,如果想让它旋转90°,竖直呈现呢?代码如下:

代码(有注释):

#导入库
import matplotlib.pyplot as plt
import seaborn as sns

# 示例数据
data = [50, 60, 70, 80, 90, 100, 66, 85, 90, 79, 85, 140,-5,5]
plt.figure(figsize=(15,6))#创建图形,设置图形的尺寸
sns.set(font='SimHei')#设置显示中文字符,解决Seaborn中文显示问题

sns.boxplot(y=data)#用于绘制箱线图的数据为data

plt.tick_params(labelsize=20) #刻度字体大小20
plt.xlabel("2023年",fontsize=18)
plt.ylabel("分数",fontsize=18)
plt.show()#画图

这里代码只做了一个小调整,原先是sns.boxplot(data),现在把它改为sns.boxplot(y=data)即可。

结果:

     这样箱线图就是我们想要的竖直呈现了

     但是这个箱线图的宽度太宽了,如果想调整一下宽度,并且将表示中位数的这条线改为其它的颜色(如红色),并在图中表示出均值位置,怎样设置呢?

     请看下边

(二)调整箱线图参数设置

代码:

#导入库
import matplotlib.pyplot as plt
import seaborn as sns
# 示例数据
data = [50, 60, 70, 80, 90, 100, 66, 85, 90, 79, 85, 140,-5,5]
plt.figure(figsize=(5,5))
sns.set(font='SimHei')#设置显示中文字符,解决Seaborn中文显示问题
# # 设置风格
# sns.set(style="whitegrid")
#medianprops={'color': 'red'}设置中位线为红色,showmeans=True控制使得否显示均值
sns.boxplot(y=data,width=0.3,medianprops={'color': 'red'},showmeans=True,
           meanprops={'markerfacecolor': 'yellow', 'markeredgecolor': 'black'})
plt.xlabel("2023",fontsize=18)
plt.ylabel("分数",fontsize=18)
plt.tick_params(labelsize=15) #刻度字体大小20
plt.show()

解释:

①如上的代码,在下面的部分进行了改动,其中

sns.boxplot(y=data,width=0.3,medianprops={'color': 'red'},showmeans=True,
           meanprops={'markerfacecolor': 'yellow', 'markeredgecolor': 'black'})

(1)width=0.3:调整箱线图的宽度,如下箱线图明显比原始箱线图窄了一些,美观了一些

(2)medianprops={'color': 'red'}:将表示中位数的线调成了红色,小伙伴可以自己调一下其他颜色试试

(3)showmeans=True:代表在箱线图中显示均值,其中均值是用一个小三角形来表示(如下图)

(4)meanprops={'markerfacecolor': 'yellow', 'markeredgecolor': 'green'}:表示均值的小三角形,内部用yellow黄色填充,外部轮廓是black,黑色

②同时也调整了图形的大小(长和宽),如下:

plt.figure(figsize=(5,5))

结果:

 (三)绘制多组数据的箱线图

    (1)目的:

    同时绘制如下多组数据的箱线图

    (2)数据:

    数据有两列,

    第一列是"年份",有三年,分别是2021、2022、2023年

    第二列是”分数“

年份分数
2021150
202160
202170
202180
202190
2021100
202156
202154
202185
202195
202162
2021-5
202110
202195
202185
202250
202260
202270
202280
202290
2022100
2022-1
202254
202285
202295
202262
2022100
202210
202295
202285
202380
202360
202370
202380
202390
2023100
202356
202354
202385
202395
202362
2023120
202310
202395
202385
    (3)代码:
#导入库
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

#导入数据
data=pd.read_excel("C:\\Users\\86159\Desktop\\CSDN\\箱线图数据.xlsx")

#创建图例
plt.figure(figsize=(15,6))

#设置显示中文字符,解决Seaborn中文显示问题
sns.set(font='SimHei')

#medianprops={'color': 'red'}设置中位线为红色,showmeans=True控制使得否显示均值
sns.boxplot(x=data["年份"],y=data["分数"],width=0.5,medianprops={'color': 'red'},showmeans=True,
           meanprops={'markerfacecolor': 'yellow', 'markeredgecolor': 'red'})
#X轴标题
plt.xlabel("年份",fontsize=18)

#Y轴标签
plt.ylabel("总分",fontsize=18)

plt.tick_params(labelsize=15) #刻度字体大小20

#画图
plt.show()
  (4)解释:

  导入的数据有两列,

  第一列是"年份",有三年,分别是2021、2022、2023年

  第二列是”分数“

  代码有改动的部分如下:x=data["年份"],y=data["分数"],其它和原先设置的一样

sns.boxplot(x=data["年份"],y=data["分数"],width=0.5,medianprops={'color': 'red'},showmeans=True,
           meanprops={'markerfacecolor': 'yellow', 'markeredgecolor': 'red'})
  (5)结果:

       可以看到利用箱线图来判断离群点的话,2021年有两个离群点,2022年有一个离群点,2023年有一个离群点

补充:这组数据里有2021、2022、2023三年数据,如果只想画其中一年的箱线图,如2021年怎么办?如下:

#导入库
import matplotlib.pyplot as plt
import seaborn as sns


plt.figure(figsize=(15,6))#创建图例
sns.set(font='SimHei')#设置显示中文字符,解决Seaborn中文显示问题

sns.boxplot(x=data[data["年份"]==2021]["年份"],y=data[data["年份"]==2021]["分数"],width=0.5,medianprops={'color': 'red'},showmeans=True,
           meanprops={'markerfacecolor': 'yellow', 'markeredgecolor': 'red'})

plt.xlabel("年份",fontsize=18)
plt.ylabel("总分",fontsize=18)
plt.tick_params(labelsize=15) #刻度字体大小20
plt.show()

(四)找离群点的具体位置

思路:

求Z-score分数,设置一个阈值,超过阈值的Z-score分数对应的原始数据为异常值。

代码:
#导入库
import pandas as pd
import numpy as np
from scipy import stats

# 计算Z分数
z_scores = np.abs(stats.zscore(data["分数"]))

# 设置离群点阈值
threshold = 2

# 找到离群点的位置
outliers = data[(z_scores > threshold)]
print(outliers)
结果:

   下图就是输出的判断为缺失值的数据

这样计算出来的离群点即包括了超过最大值的离群点,又包括了超过最小值的离群点,

是因为在计算Z分数时使用了绝对值函数(np.abs)。这意味着离群点的Z分数会被转换为正数,因此大于阈值的离群点也会被包含在内。

       注:设置不同的阈值threshold,输出的离群点个数就会有所不同,这里阈值threshold=2,小伙伴可以自己改一下阈值,看一下结果。

从上图我们可以看出,一共输出了六个离群点,

2021年3个(箱线图中呈现了2个离群点,多了一个离群点),

2022年2个(箱线图中呈现了1个离群点,多了一个离群点),

2023年1个(符合上面的箱线图结果)。

如果就想准确找到箱线图中对应的离群点位置呢?请看下边

2021年:

import pandas as pd
import numpy as np
from scipy import stats


# 计算Z分数
z_scores = np.abs(stats.zscore(data[data["年份"]==2021]["分数"]))

# 设置离群点阈值
threshold = 2

# 找到离群点的位置
outliers = data[data["年份"]==2021][(z_scores > threshold)]
print(outliers)

其中data[data["年份"]==2021]就是整体数据中2021部分的数据

结果,如下,正好是对应2021年箱线图的两个离群点

2022年:

import pandas as pd
import numpy as np
from scipy import stats


# 计算Z分数
z_scores = np.abs(stats.zscore(data[data["年份"]==2022]["分数"]))

# 设置离群点阈值
threshold = 2

# 找到离群点的位置
outliers = data[data["年份"]==2022][(z_scores > threshold)]
print(outliers)

其中data[data["年份"]==2022]就是整体数据中2022部分的数据

结果,如下,正好是对应2022年箱线图的一个离群点

(五)随机生成一组离群点数据

# 生成一组有离群点的数据
np.random.seed(0)
data = np.concatenate([np.random.normal(0, 1, 50), [10, -10, 20]])

这两行代码的意思是将两个数组合并成一个。

首先,`np.random.normal(0, 1, 50)` 生成了一个包含50个服从均值为0、标准差为1的正态分布随机数的数组。

然后,`[10, -10, 20]` 是一个包含三个元素的列表。

最后,`np.concatenate([np.random.normal(0, 1, 50), [10, -10, 20]])` 使用 `np.concatenate()` 函数将这两个数组合并成一个。

最终得到的是由53个元素的数据,其中10,-10,20为离群点。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值