个性化阅读
专注于IT技术分析

Matplotlib中的直方图

介绍

根据维基百科, 直方图是数字数据分布的精确图形表示。它是对连续变量(定量变量)的概率分布的估计, 最早由Karl Pearson提出。它是条形图的一种。要构建直方图, 第一步是将值范围” range”(即将值的整个范围划分为一系列间隔), 然后计算每个间隔中有多少个值。通常将bin指定为变量的连续, 不重叠的间隔。垃圾箱(间隔)必须相邻并且通常(但不必是)大小相等。

除了数值数据外, 直方图还可以用于可视化图像的分布, 因为图像不过是图像元素(像素)的组合, 范围从$ 0 $到$ 255 $。直方图的x轴表示bin的数量, 而y轴表示特定bin的频率。箱数是一个参数, 可以根据你希望如何可视化数据分布来进行更改。

例如:假设你要绘制像素值为$ 0 $到$ 255 $的RGB图像的直方图。该图像可以容纳的最大垃圾箱数为$ 255 $。如果将x_axis(bin的数量)保持为$ 255 $, 则y_axis将表示该图像中每个像素的频率。

直方图在本质上与条形图相似, 让我们看一下一个直方图的图形示例:

Matplotlib中的直方图

直方图是用于可视化和理解几乎每个人都可以直观理解的数值数据或图像数据的概率分布的绝佳工具。 Python具有许多用于构建和绘制直方图的选项。 Python几乎没有用于创建图形的内置库, 而其中一个这样的库是matplotlib。

在今天的教程中, 你将主要使用matplotlib在各种数据集上创建和可视化直方图。

因此, 事不宜迟, 让我们开始吧。

使用Numpy和Matplotlib绘制直方图

import numpy as np

为了重现性, 你将使用numpy的种子函数, 该函数每次执行时都会提供相同的输出。

你将绘制高斯(正态)分布的直方图, 其平均值为$ 0 $, 标准差为$ 1 $。

np.random.seed(100)
np_hist = np.random.normal(loc=0, scale=1, size=1000)
np_hist[:10]
array([-1.74976547, 0.3426804 , 1.1530358 , -0.25243604, 0.98132079, 0.51421884, 0.22117967, -1.07004333, -0.18949583, 0.25500144])

让我们验证上述分布的均值和标准差。

np_hist.mean(), np_hist.std()
(-0.016772157343909157, 1.0458427194167)

接下来, 你将使用numpy的直方图函数, 该函数将返回hist和bin_edges。

hist, bin_edges = np.histogram(np_hist)
hist
array([  7, 37, 111, 207, 275, 213, 105, 31, 10, 4])
bin_edges
array([-3.20995538, -2.50316588, -1.79637637, -1.08958687, -0.38279736, 0.32399215, 1.03078165, 1.73757116, 2.44436066, 3.15115017, 3.85793967])

接下来, 让我们使用matplotlib的plt.bar函数绘制直方图, 其中x轴和y轴分别为bin_edges和hist。

import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=[10, 8])

plt.bar(bin_edges[:-1], hist, width = 0.5, color='#0504aa', alpha=0.7)
plt.xlim(min(bin_edges), max(bin_edges))
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value', fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.title('Normal Distribution Histogram', fontsize=15)
plt.show()
Matplotlib中的直方图

让我们将bin_edges舍入为整数。

bin_edges = np.round(bin_edges, 0)
plt.figure(figsize=[10, 8])

plt.bar(bin_edges[:-1], hist, width = 0.5, color='#0504aa', alpha=0.7)
plt.xlim(min(bin_edges), max(bin_edges))
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value', fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.title('Normal Distribution Histogram', fontsize=15)
plt.show()
Matplotlib中的直方图

现在该图看起来好多了, 不是吗?

要了解hist和bin_edges, 我们来看一个示例:

你将定义一个具有任意值的数组, 并定义范围为$ 5 $的bin。

hist, bin_edges = np.histogram([1, 1, 2, 2, 2, 2, 3], bins=range(5))
hist
array([0, 2, 4, 1])

在上面的输出中, hist表示bin $ 0 $中有$ 0 $个项目, bin $ 1 $中有$ 2 $, bin $ 3 $中有$ 4 $, bin $ 4 $中有$ 1 $。

bin_edges
array([0, 1, 2, 3, 4])

同样, 上述bin_edges输出表示bin $ 0 $在$ [0, 1)$区间中, bin $ 1 $在$ [1, 2)$区间中, bin $ 2 $在$ [2, 3)区间中$, bin $ 3 $在区间$ [3, 4)$中。

仅使用Matplotlib绘制直方图

使用matplotlib绘制直方图简直是小菜一碟。你所要做的就是使用matplotlib的plt.hist()函数, 并将数据以及垃圾箱数和一些可选参数一起传入。

在plt.hist()中, 传递bins =’auto’给你”理想”数量的bin。这个想法是选择一个bin宽度, 该宽度可以最忠实地代表你的数据。

就这样。因此, 让我们绘制使用numpy构建的normal_distribution的直方图。

plt.figure(figsize=[10, 8])
n, bins, patches = plt.hist(x=np_hist, bins=8, color='#0504aa', alpha=0.7, rwidth=0.85)
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value', fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.title('Normal Distribution Histogram', fontsize=15)
plt.show()
Matplotlib中的直方图

一起绘制两个直方图

plt.figure(figsize=[10, 8])
x = 0.3*np.random.randn(1000)
y = 0.3*np.random.randn(1000)
n, bins, patches = plt.hist([x, y])
Matplotlib中的直方图

使用熊猫绘制虹膜数据的直方图

你将使用sklearn加载名为iris的数据集。在sklearn中, 你有一个称为数据集的库, 其中有可以动态加载的Iris数据集。因此, 让我们快速加载虹膜数据集。

from sklearn.datasets import load_iris
import pandas as pd
data = load_iris().data
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width']

接下来, 你将创建虹膜数据集的数据框。

dataset = pd.DataFrame(data, columns=names)
dataset.head()
sepal长度 sepal宽度 petal长度 petal宽度
0 5.1 3.5 1.4 0.2
1 4.9 3.0 1.4 0.2
2 4.7 3.2 1.3 0.2
3 4.6 3.1 1.5 0.2
4 5.0 3.6 1.4 0.2
dataset.columns[0]
'sepal-length'

最后, 你将使用熊猫内置函数.hist(), 它将为数据集中存在的所有特征绘制直方图。

那不是很好吗?

fig = plt.figure(figsize = (8, 8))
ax = fig.gca()
dataset.hist(ax=ax)
plt.show()
Matplotlib中的直方图

petal长度, petal宽度和sepal长度显示为单峰分布, 而sepal宽度则反映高斯曲线。所有这些都是有用的分析, 因为这样你就可以考虑使用一种适用于这种分布的算法。

用Matplotlib绘制直方图

plt.figure(figsize=[10, 10])
f, a = plt.subplots(2, 2)
a = a.ravel()
for idx, ax in enumerate(a):
    ax.hist(dataset.iloc[:, idx], bins='auto', color='#0504aa', alpha=0.7, rwidth=0.85)
    ax.set_title(dataset.columns[idx])
plt.tight_layout()
<Figure size 720x720 with 0 Axes>
Matplotlib中的直方图

绘制二进制和RGB图像的直方图

在本教程的最后一部分中, 你将可视化两个不同的域图像:二进制(文档)图像和自然图像。二进制图像是像素值大多为$ 0 $或$ 255 $的那些图像, 而彩色通道图像的像素值可以在$ 0 $到$ 255 $之间的任意范围内。

通过绘制图像强度值的直方图来分析像素分布是测量给定图像每个像素的出现的正确方法。对于8位灰度图像, 存在256个可能的强度值。因此, 要研究像素分布域中文档和自然图像之间的差异, 你将分别为文档和自然图像绘制两个直方图。考虑到可读文档具有稀疏性, 因此这些文档图像中像素的分布应大体上倾斜。

你将使用opencv模块加载两个图像, 通过在读取时传递参数$ 0 $将它们转换为灰度, 最后将它们调整为相同的大小。

import cv2
lena_rgb = cv2.imread('lena.png')
lena_gray = cv2.cvtColor(lena_rgb, cv2.COLOR_BGR2GRAY)
lena_gray.shape
(512, 512)
binary = cv2.imread('binary.png')
binary.shape
(1394, 2190, 3)
binary = cv2.resize(binary, (512, 512), cv2.INTER_CUBIC)
binary.shape
(512, 512, 3)
binary_gray = cv2.cvtColor(binary, cv2.COLOR_BGR2GRAY)
binary_gray.shape
(512, 512)

让我们可视化自然图像和文档图像。

plt.figure(figsize=[10, 10])

plt.subplot(121)
plt.imshow(lena_rgb[:, :, ::-1])
plt.title("Natural Image")

plt.subplot(122)
plt.imshow(binary[:, :, ::-1])
plt.title("Document Image")
plt.show()
Matplotlib中的直方图

注意:你将使用等于$ 255 $的bin, 因为图像中总共有$ 255 $像素, 并且你要可视化图像的每个像素值的频率, 范围从$ 0 $到$ 255 $。

hist, edges = np.histogram(binary_gray, bins=range(255))
plt.figure(figsize=[10, 8])

plt.bar(edges[:-1], hist, width = 0.8, color='#0504aa')
plt.xlim(min(edges), max(edges))
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value', fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.title('Document Image Histogram', fontsize=15)
plt.show()
Matplotlib中的直方图
hist, edges = np.histogram(lena_gray, bins=range(260))
plt.figure(figsize=[10, 8])

plt.bar(edges[:-1], hist, width = 0.5, color='#0504aa')
plt.xlim(min(edges), max(edges))
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Pixels', fontsize=15)
plt.ylabel('Frequency of Pixels', fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency', fontsize=15)
plt.title('Natural Image Histogram', fontsize=15)
plt.show()
Matplotlib中的直方图

从上面的图中可以看到, 自然图像分布在所有256个具有随机分布的强度上, 而文档图像显示为单峰分布, 并且大部分在像素值$ 0 $到$ 255 $之间倾斜。

总结

恭喜你完成了本教程。

本教程是如何在numpy和pandas的帮助下使用matplotlib创建直方图的一个很好的起点。

你还学习了如何利用直方图的功能来区分两个不同的图像域, 即文档和自然图像。

如果你想了解有关数据可视化技术的更多信息, 请考虑参加srcmini的”使用Python进行数据可视化”课程。

请随时在下面的评论部分中提出与本教程相关的任何问题。

赞(0)
未经允许不得转载:srcmini » Matplotlib中的直方图

评论 抢沙发

评论前必须登录!