白话解读matplotlib用法-直方图

白话解读matplotlib用法-直方图

前情提要

白话解读matplotlib用法-通用函数和柱状图

大家好,我是W

前言:昨天写了柱状图,今天就轮到直方图了,顺便再补充几个matplotlib的通用函数。接下来我们的学习顺序是补充matplotlib的常用函数、直方图、柱状图与直方图区别

补充matplotlib的常用函数

  1. 增加标签

     plt.xlabel("区域平均价格(单位:万元)") # 参数是字符串,输入想要显示的标签
     plt.ylabel("区域名称") # x和y区分x轴y轴
    
  2. 增加图片标题

     plt.title("xxx") # 同上
    
  3. 显示中文

     # windows下直接复制放在文件顶部就可以了,希望改字体可以自己改参数
     plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文
     plt.rcParams['axes.unicode_minus'] = False  # 显示负号
     
     # linux和mac可以参考
     https://blog.csdn.net/MAO_TOU/article/details/93998905
    

直方图

直方图介绍

直方图又称质量分布图,用于对连续变量概率分布的估计,由一系列高度不等的纵向柱子组成,x轴表示数据的类型,y轴表示分布的情况。直方图可以解析出数据的规则,能够直接地看到目标对象特性的分布情况。

使用场景

  1. 全国男生平均身高情况:身高区间做x轴,人数或比例做y轴。
  2. 某省劳动人口收入情况:金额区间做x轴,人数或比例做y轴。
  3. 考试成绩分布情况:成绩区间做x轴,人数或比例做y轴。

类似的情况还有许多,直方图可以帮助我们更直接的看出数据的分布情况,当我们需要将数据解析成区间和比例进行分析的时候可以使用直方图。

实例讲解(代码复制可用)

要花一个直方图其实很简单,只需要把数据集丢上去,设置好组数就可以了:

import matplotlib.pyplot as plt

# 未处理的数据集
# 某年电影时长统计
data = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130,
124,
101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111, 78, 132, 124, 113, 150, 110, 117,
86,
95, 144, 105, 126, 130, 126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136, 123, 117, 119, 105, 137,
123, 128, 125, 104, 109, 134, 125, 127, 105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114, 105,
115,
132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134, 156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110,
102,
123, 107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133, 112, 114, 122, 109, 106, 123, 116, 131,
127,
115, 118, 112, 135, 115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154, 136, 100, 118, 119, 133,
134,
106, 129, 126, 110, 111, 109, 141, 120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126, 114, 140,
103,
130, 141, 117, 106, 114, 121, 114, 133, 137, 92, 121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,
134,
106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110, 105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146,
133, 101, 131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111, 111, 133, 150]

# 打开画布
fig = plt.figure(figsize=(20, 8), dpi=80)
# x=:表示要放入的数据,类型列表
plt.hist(x=data)
plt.grid()
plt.show()

这时我们会发现直方图会自动将数据分为几个组,然后自动统计出来数据集在不同组的数量,这也是所需要的数据集必须是未处理的原因,若是手头上只有处理过的数据但是又要做成直方图的样子,就需要用柱状图处理了,简单说一下就是柱状图中将数据摆上去后调整柱子的宽度达到每个柱子贴合的样子。

但是,通过上图我们会发现一个致命的弱点,为什么我的x轴刻度跟柱子不对应呢?很显然我们没有设置xticks(这也是直方图最恶心,比较难的一个点),接下来我们设置xticks。

import matplotlib.pyplot as plt

# 未处理的数据集
data = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130,
    124,
    101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111, 78, 132, 124, 113, 150, 110, 117,
    86,
    95, 144, 105, 126, 130, 126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136, 123, 117, 119, 105, 137,
    123, 128, 125, 104, 109, 134, 125, 127, 105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114, 105,
    115,
    132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134, 156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110,
    102,
    123, 107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133, 112, 114, 122, 109, 106, 123, 116, 131,
    127,
    115, 118, 112, 135, 115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154, 136, 100, 118, 119, 133,
    134,
    106, 129, 126, 110, 111, 109, 141, 120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126, 114, 140,
    103,
    130, 141, 117, 106, 114, 121, 114, 133, 137, 92, 121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,
    134,
    106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110, 105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146,
    133, 101, 131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111, 111, 133, 150]

# 设置数据间隔
width = 3
# 通过数据集的最值计算出需要分的组数
bin_num = int(max(data) - min(data)) // width
# 计算出刻度列表 从最小值到最大值+width,每隔一个width给一个数
# [78, 81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, 156]
bins = [i for i in range(min(data), max(data) + width, width)]

# 打开画布
fig = plt.figure(figsize=(20, 8), dpi=80)

# x=:表示要放入的数据,类型列表
# bins=:表示直方图组间距离,即hist函数会按照你传入的bins列表去统计信息,并形成柱子渲染出来
# 比如上面的data列表会遍历出有多少个值在78~81之间,然后形成一个多高的柱子显示出来
plt.hist(x=data, bins=bins)

# 设置x轴刻度
# ticks=表示下标的位置 从多大的值开始,然后在x轴上计算出下一个点所在的位置然后打点
# 若大家的bins设置的不是均匀的 显示出来刻度的位置也不是均匀的 因为轴的刻度跟柱子是分离的
# 刻度会按照我们定义的刻度列表跟轴的距离打点(就好像在一条麻绳上打点,间距忽大忽小,我们人去打点的时候会以麻绳长度为参照系也忽大忽小的打点)
plt.xticks(ticks=bins)

plt.grid()
plt.show()

运行上面的代码我们可以看到下图:
在这里插入图片描述

我再详细解释一下上述这个代码:

width=3:就是设置直方图统计时的统计距离,每隔3统计一次,但是单单定义一个width在这里是没有作用的。
bin_num = int(max(data) - min(data)) // width:通过最大值和最小值的极差我们计算出应该要统计的组数,在这里打出来只是方便我们做判断

bins = [i for i in range(min(data), max(data) + width, width)]:生成一个刻度列表,这个刻度列表就是真真正正作用在柱子和刻度上的东西,从最小值开始,每隔width加一个数,加到最大值+width为止。为什么要加多一个width?因为若不加的话x轴最后一个柱子的落脚点没有刻度。

plt.hist(x=data, bins=bins):x表示要放入的数据,bins就是我们分组的情况,需要告诉hist函数知道我们怎么分的组,让他对数据进行分类统计时按照这个列表来

plt.xticks(ticks=bins):大家的老朋友了,直接把bins丢到ticks里面,他的刻度显示就会按照bins里的来。这里我们不需要设置label,因为直方图下面肯定是要数据的,需要让我们知道在多少范围内有多少数据,所以不需要设置label。

可能大家在刚才的设置还是有点不懂,接下来我们就开始乱调参数,来印证上面的说法对不对

import matplotlib.pyplot as plt

# 未处理的数据集
data = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130,
    124,
    101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111, 78, 132, 124, 113, 150, 110, 117,
    86,
    95, 144, 105, 126, 130, 126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136, 123, 117, 119, 105, 137,
    123, 128, 125, 104, 109, 134, 125, 127, 105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114, 105,
    115,
    132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134, 156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110,
    102,
    123, 107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133, 112, 114, 122, 109, 106, 123, 116, 131,
    127,
    115, 118, 112, 135, 115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154, 136, 100, 118, 119, 133,
    134,
    106, 129, 126, 110, 111, 109, 141, 120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126, 114, 140,
    103,
    130, 141, 117, 106, 114, 121, 114, 133, 137, 92, 121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,
    134,
    106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110, 105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146,
    133, 101, 131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111, 111, 133, 150]

width = 3
bin_num = int(max(data) - min(data)) // width

# 改变bins的长度,让其从0开始一直到max(data),这样显然列表长度变多了,但是组间距没有变
# 也就是说,我们把bins放入hist函数里时,告诉他你要从0到max(data)给我按width=3分组
# 每组有多少个给我算出来
bins = [i for i in range(0, max(data) + width, width)]

fig = plt.figure(figsize=(20, 8), dpi=80)

# 告诉hist我们的分组规则
plt.hist(x=data, bins=bins)

# 把我们的分组也给ticks刻度,让他画刻度的时候按照bins来
plt.xticks(ticks=bins)

plt.grid()
plt.show()

得出来的效果图:
在这里插入图片描述

可以看到柱子整体向右移动了,但是可以看到柱子的高度不变,这也印证了hist函数会根据所给的bins列表区间按照区间去统计个数,没有的当然就为空,没有柱子。

我们再调整一波bins列表,我们会觉得前面78~93太松散了,能不能把他作为一组统计起来。

import matplotlib.pyplot as plt

# 未处理的数据集
data = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130,
    124,
    101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111, 78, 132, 124, 113, 150, 110, 117,
    86,
    95, 144, 105, 126, 130, 126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136, 123, 117, 119, 105, 137,
    123, 128, 125, 104, 109, 134, 125, 127, 105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114, 105,
    115,
    132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134, 156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110,
    102,
    123, 107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133, 112, 114, 122, 109, 106, 123, 116, 131,
    127,
    115, 118, 112, 135, 115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154, 136, 100, 118, 119, 133,
    134,
    106, 129, 126, 110, 111, 109, 141, 120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126, 114, 140,
    103,
    130, 141, 117, 106, 114, 121, 114, 133, 137, 92, 121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,
    134,
    106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110, 105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146,
    133, 101, 131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111, 111, 133, 150]

width = 3
bin_num = int(max(data) - min(data)) // width

# bins = [i for i in range(0, max(data) + width, width)]
# 我们发现好像前面的太松散了,我们希望把78~93作为一个整体去统计
# 自定义数组,设定第一个间隔就是78~93
bins = [78, 93]
# 接下来把剩下数量的刻度加进去,依然是均匀的
# [78, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, 156, 159]
for i in range(1, bin_num - 3):
    bins.append(93 + i * width)

fig = plt.figure(figsize=(20, 8), dpi=80)
# 告诉hist我们的分组规则
plt.hist(x=data, bins=bins)
# 把我们的分组也给ticks刻度,让他画刻度的时候按照bins来
plt.xticks(ticks=bins)

plt.grid()
plt.show()

得到效果图:
在这里插入图片描述

打开图可能会吓一跳,怎么那么丑?其实仔细想想就释然了,hist函数按照我们的bins的规则,将78~93作为一个组,这个是做到了的,而且柱子的高度变了,显然变为9个了,所以是成功将原本几个区间的值统计起来了。

但是为什么会那么粗?间距不均匀?这是因为直方图柱子的面积也是有一定意义的。

直方图柱子的面积

柱子的面积越大,则这组数据的频数越大,只有当柱子的组间距宽度相等时,他的高才表示长方形的频数。

也就是说上述的柱子宽度不同,实际上是表示出这组数据的频数。

直方图和柱状图的区别

条形图(bar chart,bar plot,bar graph)用于描述那些已经用频数或频率汇总的定性变量。通常条形图的X轴代表定性变量的各个取值(eg 一等舱、二等舱、普通舱),而Y轴代表频率或频数。每一个变量都有一个条,这个条的长度和这个变量所对应的Y轴的频率或频数成比例。

直方图(histogram)实际上也是一种条形图,但是直方图用于描述定量变量。直方图的X轴代表将定量变量的数据划分为若干等宽度的区间(eg.将100个人按年龄划分,划分10个区间,则每10岁为一个区间)。与条形图不同,条形图中每个矩形在X轴上对应一个定性变量的取值,而直方图的每个矩形在X轴上对应定量变量数据的区间(集合)。直方图的每一个区间也都有一个条,这个条的长度与Y轴的频率和频数成比例。除此之外,由于是等宽度区间,所以不仅高度,而且各个区间的面积也与数据在相应区间的频数成比例。因此,矩形面积也与频率成比例。

总结就是,用于描述的变量不同;X轴代表的东西不同;矩形条长度、面积与Y轴的频率和频数的关系不同

作者:车路士
链接:https://www.zhihu.com/question/26894953/answer/606948860
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值