用matplotlib画直方图(histogram)

2020年8月25日 / 30次阅读 / Last Modified 2020年8月27日
Matplotlib

在matplotlib中,ax.plot函数是用来画曲线的,而ax.hist函数则用来画直方图(histogram)。

下面我们用python代码换一个直方图,10000个符合正态分布的随机数,将他们按照直方图画出来:

import numpy as np
import matplotlib.pyplot as plt


x = np.random.randn(10000)

fig = plt.figure()
ax = fig.add_subplot()
ax.hist(x, bins=50, color='blue', alpha=0.7)

plt.show()
  • 注意ax.hist函数,数据的输入只有x,x可以是一个sequence,也可以是matrix;
  • bins控制直方图中等宽分组的数量,默认为10,不过应该很少用默认值吧;
  • alpha控制直方图颜色的透明度。(plot等其它函数中,也有这个参数)
正态分布直方图
正态分布直方图

这个直方图怎么看,y轴表示数据出现的频率或次数,x轴是按bins参数输入进行分组。直方图,可以理解为由一系列高度不等的纵向条柱来表示数据分布特征的统计报告图,它是对原始数据进行压缩的结果。

直方图分组的区间

我没有找到特别权威的说明,不过,通过阅读matplotlib官方教材能够发现,bins的值如果是一个整数,x轴的区间就进行等宽划分;bins只也可以是一个sequence对象,用来进行不等宽划分x轴。

不管怎么分x轴的区间,每一个分组,都是左封闭右开放,只有最后一个分组,是左右都封闭的!(想一想这样是合理的,左边不封闭,最左边的那个分组就没法处理了)

>>> plt.hist((1,2,3,4,5,6,7,8,2), bins=(1,2,3,4,5,6,8))
(array([1., 2., 1., 1., 1., 3.]), array([1, 2, 3, 4, 5, 6, 8]), <BarContainer ob
ject of 6 artists>)

对(1,2,3,4,5,6,7,8,2)话直方图,但是bins=(1,2,3,4,5,6,8),即6-8为一个大分组,有3个数字落在这个区间,数据中出现了两次2,第1个分组是[1,2),不包含2,2因此包含在第2个分组中[2,3)。这样画出来的直方图如下:

bins实现非等宽划分组
bins实现非等宽划分组

上面这个图其实看着不是很好看,全都粘在一起了,我们可以通过rwidth参数(float,分组区间大小的百分比)来控制各个bar之间的间隔,注意此时图像上的位置,已经不再是真实的分组区间,x轴的刻度也可以用xticks函数来精确控制:

>>> plt.hist((1,2,3,4,5,6,7,8,2), bins=(1,2,3,4,5,6,8), rwidth=0.9, color='purpl
e', alpha=0.5)
(array([1., 2., 1., 1., 1., 3.]), array([1, 2, 3, 4, 5, 6, 8]), <BarContainer ob
ject of 6 artists>)
>>> plt.xticks(range(1,10,1))

效果如下:

美化后的直方图
美化后的直方图

当bins参数为一个sequence时,实际上就是给dataset指定了一个range,即bins所括起来的区间不需要与dataset的区间一致。当bins是一个int时,我们可以用range参数来指定有效区间,将不在区间范围内的outliers排除在直方图的统计中。

输入数据为matrix时的直方图

输入数据x如果是一个matrix,matplotlib会把它的每一个列向量当做一个dataset来画直方图,然后将多个直方图并排在一起放在一个图中。此时,分组在x轴上的分割就不是精确的了(就像使用了rwidth参数):

>>> plt.hist(((1,2,3,4,5,1,2,3,4,5,1,1,2,2,3,4,5,5),(1,2,3,4,5),(1,2,3,3,3)), bi
ns=4)
(array([[4., 4., 3., 7.],
       [1., 1., 1., 2.],
       [1., 1., 3., 0.]]), array([1., 2., 3., 4., 5.]), <a list of 3 BarContaine
r objects>)

从返回值可以看出,分组为array([1., 2., 3., 4., 5.]),但为了作图,多个柱形公用一个区间,他们只能在这个区间内进行某种排列,两边还要留点空余出来:

多个dataset时的直方图
多个dataset时的直方图

根据需要,我们可以此时将多个直方图的bar堆叠起来(stack),使用stacked=True参数,配合rwidth,代码和效果如下:

>>> plt.hist(((1,2,3,4,5,1,2,3,4,5,1,1,2,2,3,4,5,5),(1,2,3,4,5),(1,2,3,3,3)), bi
ns=4, stacked=True, rwidth=0.9)
(array([[4., 4., 3., 7.],
       [5., 5., 4., 9.],
       [6., 6., 7., 9.]]), array([1., 2., 3., 4., 5.]), <a list of 3 BarContaine
r objects>)
>>> plt.yticks(range(0,10,1))
直方图stacked效果
直方图stacked效果

概率分布直方图

直方图的y轴可以是频次,也可以是概率,用density=True参数,就可以得到一个概率分布直方图:

>>> x = np.random.randn(1000)
>>> plt.hist(x, bins=30, rwidth=0.9, density=True)
概率分布直方图
概率分布直方图

给直方图配上Label

没有label的图是不完整的,下面代码演示给4组放在一起的直方图添加label的方法:

>>> x = np.random.randn(10000,4)
>>> plt.hist(x, bins=20, rwidth=0.8, label=('A','B','C','D'))
(array([[1.000e+00, 1.000e+00, 4.000e+00, 1.300e+01, 4.000e+01, 1.310e+02,
        3.390e+02, 6.940e+02, 1.142e+03, 1.516e+03, 1.698e+03, 1.569e+03,
        1.261e+03, 8.170e+02, 4.640e+02, 1.990e+02, 8.200e+01, 2.200e+01,
        6.000e+00, 1.000e+00],
       [0.000e+00, 1.000e+00, 1.000e+00, 1.400e+01, 4.200e+01, 1.440e+02,
        3.290e+02, 6.630e+02, 1.159e+03, 1.467e+03, 1.688e+03, 1.581e+03,
        1.289e+03, 8.620e+02, 4.950e+02, 1.650e+02, 6.600e+01, 2.500e+01,
        8.000e+00, 1.000e+00],
       [0.000e+00, 0.000e+00, 2.000e+00, 1.200e+01, 4.300e+01, 1.520e+02,
        3.230e+02, 6.110e+02, 1.089e+03, 1.516e+03, 1.689e+03, 1.659e+03,
        1.274e+03, 8.360e+02, 4.450e+02, 2.150e+02, 9.500e+01, 3.100e+01,
        8.000e+00, 0.000e+00],
       [0.000e+00, 0.000e+00, 4.000e+00, 1.600e+01, 5.300e+01, 1.510e+02,
        3.430e+02, 6.490e+02, 1.039e+03, 1.518e+03, 1.765e+03, 1.581e+03,
        1.281e+03, 8.510e+02, 4.510e+02, 1.850e+02, 8.100e+01, 2.800e+01,
        3.000e+00, 1.000e+00]]), array([-4.65961655, -4.22442284, -3.78922913, -
3.35403542, -2.91884171,
       -2.483648  , -2.04845429, -1.61326058, -1.17806686, -0.74287315,
       -0.30767944,  0.12751427,  0.56270798,  0.99790169,  1.4330954 ,
        1.86828911,  2.30348282,  2.73867653,  3.17387024,  3.60906395,
        4.04425766]), <a list of 4 BarContainer objects>)
>>> plt.legend()
<matplotlib.legend.Legend object at 0x000000000AF7BF08>
>>> plt.show()
给直方图配上Label
给直方图配上Label

-- EOF --

本文链接:https://www.pynote.net/archives/2386

留言区

《用matplotlib画直方图(histogram)》有5条留言

电子邮件地址不会被公开。 必填项已用*标注

  • 麦新杰

    method of left inclusion. [回复]

  • 麦新杰

    组距的确定很有学问,有很多以不同人名命名的方法,但是从常识角度看:组距要符合数据特征,还要让人容易理解。 [回复]

  • 麦新杰

    plt.hist函数的官方页面:https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist.html#matplotlib.pyplot.hist [回复]

  • 麦新杰

    次数分布表画直方图 [回复]

    • 麦新杰

      bar chart是不是更合适一点,x轴只是分类的情况。 [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top