对于初学python绘图的小伙伴来说,彻底弄清hist直方图绘制需要花费较多时间。
本文旨在让你花最少的时间,彻底弄懂hist函数原理和绘制方法。
本文目录
一、什么是直方图?
直方图分为频数直方图和频率直方图,为理解什么是直方图,大家可先熟悉如下专有名词。
频数分布直方图:在统计数据时,按照频数分布表,在平面直角坐标系中,横轴标出每个组的端点,纵轴表示频数,每个矩形的高代表对应的频数。
频率分布直方图:在统计数据时,按照频数分布表,在平面直角坐标系中,横轴标出每个组的端点,纵轴表示频率除以组距的值,每个矩形的高代表频率和组距的商。
频数:落在各组样本数据的个数。
频率:频数除以样本总个数。
组距:直方图中柱子的宽度,可自定义,也可用数据的最大值减去最小值再除以柱子的个数。
二、matplotlib.pyplot.hist参数详解
在python中用matplotlib.pyplot.hist函数绘制直方图,本小节详细阐述该函数的常用参数。
你可以大致浏览一遍,再结合第三个模块的案例彻底弄懂这些参数。
hist(x, bins=None, range=None, density=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, *, data=None, **kwargs)
x:数组序列,待绘制直方图的原始数据。
bins:整数值或数组序列,默认为None。若为整数值,则为频数分布直方图柱子个数,且柱宽=(x.max()-x.min())/bins。
若为数值序列,则该序列给出每个柱子的范围值,除最后一个柱子外,其他柱子的取值范围均为左闭右开,若数值序列的最大值小于原始数据的最大值,存在数据丢失。
range:元组或None,默认为None。若为元组,则range用于剔除原始数据中较小和较大的离群值,给出绘制直方图的全局范围。若为None,则不剔除。
若bins取值为数组序列,则range无效。
density:布尔值,默认为False。若为True,则绘制频率分布直方图,若为False,则绘制频数分布直方图。
weights:与x形状相同的权重数组。将x中的每个元素乘以对应权重值再计数。如果normed或density取值为True,则会对权重进行归一化处理。这个参数可用于绘制已合并数据的直方图。
cumulative:布尔值,默认为False。若为True,当density为False时直方图显示累计频数,当density为True时直方图显示累计频率。
bottom:数值或数组序列,默认为None。若为数值,则直方图的柱子相对于y=0向上/向下偏移相同的量。若为数组序列,则根据数组元素取值每根柱子偏移相应的量。
histtype:{'bar', 'barstacked', 'step', 'stepfilled'},默认为'bar'。
'bar'是传统的条形直方图,'barstacked'是堆叠的条形直方图,'step'是未填充的阶梯直方图,只有外边框,'stepfilled'是有填充的阶梯直方图。
当histtype取值为'step'或'stepfilled'时,rwidth设置失效,即柱子中无间隔,默认连接在一起。
align:{'left', 'mid', 'right'},默认为'mid'。
'left'表示柱子的中心位于bins的左边缘, 'mid'表示柱子的中心位于bins的中间,'right'表示柱子的中心位于bins的右边缘。
orientation:{'horizontal', 'vertical'},默认为'vertical'。'horizontal'表示柱子水平排列, 'vertical'表示柱子垂直排列。
rwidth:数值,默认为None。表示柱子的宽度占bins对应宽的比例,比如取值为0.9时,柱子的宽度为bins对应宽乘以0.9,柱子之间有空隙。
log:布尔值,默认为False。若为True,则纵坐标用科学计数法表示。
color:字符串(具体颜色)或数组(元素为颜色),默认为None。
label:字符串,默认为None。有多个数据集时,用label做标注区分。
stacked:布尔值,默认为False。当图中有多个数据集时使用该参数,若取值为True,则输出数据集累计堆叠的结果,若取值为False,则多个数据集柱子并排排列。
三、实例理解
本小节用一些模拟的公司薪资数据,建立直方图,方便大家理解上一章中常用参数。
1 bins参数理解
首先来看下只有薪资数据(x)和直方图分割区间(bins)两个参数的绘图代码。
import numpy as np
import pandas as pd
from scipy import stats
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决标题中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决标题中文显示问题
salary = [2500, 3100, 3300, 3500, 4000, 5400, 5600, 6700, 7600, 7800, 8700, 9800, 10400]
#公司员工薪资数据
fig = plt.figure()
ax = fig.add_subplot(111)
#创建图形框架
numBins = [0,4000,6000,10000]
#直方图的分割区间
ax.hist(salary, numBins)
plt.title(u'公司员工薪水直方图')
#绘制标题
plt.xlabel(u'薪资区间')
#横坐标标题
plt.ylabel(u'人数')
#纵坐标标题
plt.show()
从salary中知,总计有13个薪水数据,但是numBins的最大值为10000,所以salary中的10400取不到,绘图时只使用了前12个数值,这在绘图时需特别注意。
由于bins的取值是左闭右开,统计salary中[0, 4000)的个数为4,[4000, 6000)的个数为3,[6000, 10000)的个数为5。
得到结果:
2 rwidth参数理解
rwidth:柱子的宽度占bins对应宽的比例,比如取值为0.9时,柱子的宽度为bins对应宽乘以0.9,柱子之间有空隙。
只在第一小节代码的基础上调整rwidth的值为0.9,具体如下:
#rwidth参数理解
import numpy as np
import pandas as pd
from scipy import stats
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决标题中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决标题中文显示问题
salary = [2500, 3100, 3300, 3500, 4000, 5400, 5600, 6700, 7600, 7800, 8700, 9800, 10400]
#公司员工薪资数据
fig = plt.figure()
ax = fig.add_subplot(111)
#创建图形
numBins = [0,4000,6000,10000]
#直方图的分割区间
ax.hist(salary, numBins, rwidth=0.9)
plt.title(u'公司员工薪水直方图')
#绘制标题
plt.xlabel(u'薪资区间')
#横坐标标题
plt.ylabel(u'人数')
#纵坐标标题
plt.show()
得到结果:
可以发现每个柱子由原来的满格画,变成了现在的留一点空隙,比如0到4000这个区间,前后都留了一点空隙。
3 density参数理解
density:布尔值,默认为False。若为True,则绘制频率分布直方图,若为False,则绘制频数分布直方图。
只在第二小节代码的基础上调整density的值True,具体如下:
#density的值True
import numpy as np
import pandas as pd
from scipy import stats
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决标题中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决标题中文显示问题
salary = [2500, 3100, 3300, 3500, 4000, 5400, 5600, 6700, 7600, 7800, 8700, 9800, 10400]
#公司员工薪资数据
fig = plt.figure()
ax = fig.add_subplot(111)
#创建图形
numBins = [0,4000,6000,10000]
#直方图的分割区间
ax.hist(salary, numBins, rwidth=0.9, density=True)
plt.title(u'公司员工薪水直方图')
#绘制标题
plt.xlabel(u'薪资区间')
#横坐标标题
plt.ylabel(u'人数')
#纵坐标标题
plt.show()
得到结果:
可以发现纵坐标由原来的频数变成了频率。
4 cumulative参数理解
cumulative:布尔值,默认为False。若为True,当density为False时直方图显示累计频数,当density为True时直方图显示累计频率。
只在第二小节代码的基础上调整cumulative的值为True,具体如下:
#cumulative的值True
import numpy as np
import pandas as pd
from scipy import stats
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决标题中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决标题中文显示问题
salary = [2500, 3100, 3300, 3500, 4000, 5400, 5600, 6700, 7600, 7800, 8700, 9800, 10400]
#公司员工薪资数据
fig = plt.figure()
ax = fig.add_subplot(111)
#创建图形
numBins = [0,4000,6000,10000]
#直方图的分割区间
ax.hist(salary, numBins, rwidth=0.9, cumulative=True)
plt.title(u'公司员工薪水直方图')
#绘制标题
plt.xlabel(u'薪资区间')
#横坐标标题
plt.ylabel(u'人数')
#纵坐标标题
plt.show()
得到结果:
可以发现直方图绘制的是每个区间对应累计的薪资人数。
5 orientation参数理解
orientation:{'horizontal', 'vertical'},默认为'vertical'。'horizontal'表示柱子水平排列, 'vertical'表示柱子垂直排列。
只在上小节代码的基础上调整orientation的值为horizontal,具体如下:
#orientation值为horizontal
import numpy as np
import pandas as pd
from scipy import stats
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决标题中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决标题中文显示问题
salary = [2500, 3100, 3300, 3500, 4000, 5400, 5600, 6700, 7600, 7800, 8700, 9800, 10400]
#公司员工薪资数据
fig = plt.figure()
ax = fig.add_subplot(111)
#创建图形
numBins = [0,4000,6000,10000]
#直方图的分割区间
ax.hist(salary, numBins, rwidth=0.9, cumulative=True, orientation='horizontal')
plt.title(u'公司员工薪水直方图')
#绘制标题
plt.xlabel(u'薪资区间')
#横坐标标题
plt.ylabel(u'人数')
#纵坐标标题
plt.show()
得到结果:
可以发现直方图柱子呈水平排列。
6 color参数理解
color:字符串(具体颜色)或数组(元素为颜色),默认为None。
只在第四小节代码的基础上调整color值为yellow,具体如下:
#cumulative的值True
import numpy as np
import pandas as pd
from scipy import stats
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决标题中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决标题中文显示问题
salary = [2500, 3100, 3300, 3500, 4000, 5400, 5600, 6700, 7600, 7800, 8700, 9800, 10400]
#公司员工薪资数据
fig = plt.figure()
ax = fig.add_subplot(111)
#创建图形
numBins = [0,4000,6000,10000]
#直方图的分割区间
ax.hist(salary, numBins, rwidth=0.9, color='yellow')
plt.title(u'公司员工薪水直方图')
#绘制标题
plt.xlabel(u'薪资区间')
#横坐标标题
plt.ylabel(u'人数')
#纵坐标标题
plt.show()
得到结果:
可以发现直方图柱子由原来的蓝色变成了现在的黄色。
以上为直方图中常用参数的理解,如果小伙伴对于直方图中其它参数也想了解,可根据第二章的说明自行调试代码进行理解。