箱线图是另一种体现数据分布的图形,通过该图可以得知数据的下须值(Q1-1.5IQR)、下四分位数(Q1)、中位数(Q2)、均值、上四分位数(Q3)和上须值(Q3+1.5IQR),更重要的是,箱线图还可以发现数据中的异常点。
箱线图的绘制仍然可以通过matplotlib模块、pandas模块和seaborn模块完成,下面将一一介绍各模块绘制条形图的过程。
首先介绍一下matplotlib模块中绘制箱线图的boxplot函数,有关该函数的语法和参数含义如下:
plt.boxplot(x, notch=None, sym=None, vert=None,
whis=None, positions=None, widths=None,
patch_artist=None, meanline=None, showmeans=None,
showcaps=None, showbox=None, showfliers=None,
boxprops=None, labels=None, flierprops=None,
medianprops=None, meanprops=None,
capprops=None, whiskerprops=None)
import pandas as pd
import matplotlib.pyplot as plt
# 读入数据
Sec_Buildings = pd.read_excel(r'不同行政区域的二手房信息.xlsx')
#设置绘图风格
plt.style.use('ggplot')
#处理中文乱码
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
#坐标轴负号的处理
plt.rcParams['axes.unicode_minus']=False
# 绘制箱线图
plt.boxplot(x = Sec_Buildings.price_unit, # 指定绘图数据
patch_artist=True, # 要求用自定义颜色填充盒形图,默认白色填充
showmeans=True, # 以点的形式显示均值
boxprops = {
'color':'black','facecolor':'steelblue'}, # 设置箱体属性,如边框色和填充色
# 设置异常点属性,如点的形状、填充色和点的大小
flierprops = {
'marker':'o','markerfacecolor':'red', 'markersize':3},
# 设置均值点的属性,如点的形状、填充色和点的大小
meanprops = {
'marker':'D','markerfacecolor':'blue', 'markersize':4},
# 设置中位数线的属性,如线的类型和颜色
medianprops = {
'linestyle':'--','color':'orange'},
labels = [''] # 删除x轴的刻度标签,否则图形显示刻度标签为1
)
# 添加图形标题
plt.title('二手房单价分布的箱线图')
# 显示图形
plt.show()
如上图所示,图中的上下两条横线代表上下须、箱体的上下两条横线代表上下四分位数、箱体中的虚线代表中位数、箱体中的点则为均值、上下须两端的点代表异常值。通过图中均值和中位数的对比就可以得知数据微微右偏(判断标准:如果数据近似正态分布,则众数=中位数=均值;如果数据右偏,则众数<中位数<均值;如果数值左偏,则众数>中位数>均值)。 如上绘制的是二手房整体单价的箱线图,这样的箱线图可能并不常见,更多的是分组箱线图,即二手房的单价按照其他分组变量(如行政区域、楼层、朝向等)进行对比分析。下面继续使用matplotlib模块对二手房的单价绘制分组箱线图,代码如下:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 读入数据
Sec_Buildings = pd.read_excel(r'不同行政区域的二手房信息.xlsx')
#设置绘图风格
plt.style.use('ggplot')
#处理中文乱码
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
#坐标轴负号的处理
plt.rcParams['axes.unicode_minus']=False
# 二手房在各行政区域的平均单价
group_region = Sec_Buildings.groupby('region')
avg_price = group_region.aggregate({
'price_unit':np.mean}).sort_values('price_unit', ascending = False)
# print(avg_price)
# print(avg_price.index)
# 通过循环,将不同行政区域的二手房存储到列表中
region_price = []
for region in avg_price.index:
region_price.append(Sec_Buildings.price_unit[Sec_Buildings.region == region])
# 绘制分组箱线图
plt.boxplot(x = region_price, # 指定绘图数据
patch_artist=True, # 要求用自定义颜色填充盒形图,默认白色填充
labels = avg_price.index, # 添加x轴的刻度标签
showmeans=True, # 以点的形式显示均值
boxprops = {
'color':'black', 'facecolor':'steelblue'}, # 设置箱体属性,如边框色和填充色
flierprops = {
'marker':'o','markerfacecolor':'red', 'markersize':3}, # 设置异常点属性,如点的形状、填充色和点的大小
meanprops = {
'marker':'D','markerfacecolor':'blue', 'markersize':4}, # 设置均值点的属性,如点的形状、填充色和点的大小
medianprops = {
'linestyle':'--','color':'orange'} # 设置中位数线的属性,如线的类型和颜色
)
# 添加y轴标签
plt.ylabel('单价(元)')
# 添加标题
plt.title('不同行政区域的二手房单价对比')
# 显示图形
plt.show()
print(avg_price)
print(avg_price.index)
price_unit
region
静安 92920.466667
黄浦 88764.663220
徐汇 75758.458631
长宁 70295.307244
虹口 67264.039347
杨浦 65549.499725
闸北 64985.371483
普陀 60977.385854
浦东 60513.039575
闵行 53667.534058
宝山 49971.513572
松江 41779.174870
嘉定 41596.720917
青浦 39349.514793
奉贤 30576.963314
金山 22521.181818
崇明 19181.250000
Index(['静安', '黄浦', '徐汇', '长宁', '虹口', '杨浦', '闸北', '普陀', '浦东', '闵行', '宝山', '松江',
'嘉定', '青浦', '奉贤', '金山', '崇明'],
dtype='object', name='region')
应用matplotlib模块绘制如上所示的分组箱线图会相对烦琐一些,由于boxplot函数每次只能绘制一个箱线图,为了能够实现多个箱线图的绘制,对数据稍微做了一些变动,即将每个行政区域下的二手房单价汇总到一个列表中,然后基于这个大列表应用boxplot函数。在绘图过程中,首先做了一个“手脚”,那就是统计各行政区域二手房的平均单价,并降序排序,这样做的目的就是让分组箱线图能够降序呈现。
虽然pandas模块中的plot方法可以绘制分组箱线图,但是该方法是基于数据框执行的,并且数据框的每一列对应一个箱线图。对于二手房数据集来说,应用plot方法绘制分组箱线图不太合适,因为每一个行政区的二手房数量不一致,将导致无法重构一个新的数据框用于绘图。
如果读者觉得matplotlib模块绘制分组箱线图比较麻烦,可以使用seaborn模块中的boxplot函数。下面不妨先了解一下该函数的参数含义:
sns.boxplot(x=None, y=None, hue=None, data=None, order=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, notch=False, ax=None, **kwargs)
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
# 读入数据
Sec_Buildings = pd.read_excel(r'不同行政区域的二手房信息.xlsx')
#设置绘图风格
plt.style.use('ggplot')
#处理中文乱码
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
#坐标轴负号的处理
plt.rcParams['axes.unicode_minus']=False
# 二手房在各行政区域的平均单价
group_region = Sec_Buildings.groupby('region')
avg_price = group_region.aggregate({
'price_unit':np.mean}).sort_values('price_unit', ascending = False)
# 通过循环,将不同行政区域的二手房存储到列表中
region_price = []
for region in avg_price.index:
region_price.append(Sec_Buildings.price_unit[Sec_Buildings.region == region])
# 绘制分组箱线图
sns.boxplot(x = 'region', #箱线图的x轴数据
y = 'price_unit', #箱线图的y轴数据
data = Sec_Buildings, #用于绘图的数据集
order = avg_price.index, #传递一个字符串列表,用于分类变量的排序
showmeans=True, #以点的形式显示均值
color = 'steelblue', #指定所有箱线图的填充色
flierprops = {
'marker':'o','markerfacecolor':'red', 'markersize':3}, # 设置异常点属性,如点的形状、填充色和点的大小
meanprops = {
'marker':'D','markerfacecolor':'blue', 'markersize':4}, # 设置均值点的属性,如点的形状、填充色和点的大小
medianprops = {
'linestyle':'--','color':'orange'} # 设置中位数线的属性,如线的类型和颜色
)
# 更改x轴和y轴标签
plt.xlabel('区域')
plt.ylabel('单价(元)')
# 添加标题
plt.title('不同行政区域的二手房单价对比')
#控制横纵坐标的值域
plt.axis([-1,17,0,210000])
# 显示图形
plt.show()
不加控制横纵坐标的值域的图为:
加了控制横纵坐标的值域的图为:
通过如上代码,同样可以得到完全一致的分组箱线图。这里建议读者不要直接学习和使用pandas模块和seaborn模块绘制统计图形,而是先把matplotlib模块摸透,因为Python的核心绘图模块是matplotlib。