Matplotlib 如何高效计算不规则分布数据点的密度

Matplotlib 如何高效计算不规则分布数据点的密度

引言

在数据可视化中,常常需要绘制某一区域内的点密度图。在matplotlib库中,提供了hexbinimshow等关于绘制点密度图的函数,但是这些函数只能处理等间距分布的数据点。当数据点是不规则分布的时候,我们需要先计算点密度,然后再使用这些函数进行绘制。本文将介绍如何高效计算不规则分布数据点的密度。

阅读更多:Matplotlib 教程

密度估计方法

在计算点密度之前,我们需要先介绍几种密度估计方法。

核密度估计

核密度估计法是通过将每个数据点看成分布函数的一个质点,求解所有质点处的核密度函数。核密度函数是关于空间坐标x的非负实值函数K_{h}(·)和数据点{x_{1},x_{2},…,x_{n}}的加权和:

{\displaystyle \hat{f}(x)=\frac{1}{nh}\sum_{i=1}^{n}K_{h}(x-x_{i})}

其中n是数据点的总数,h是要选择的平滑参数,K_{h}表示关于平滑参数h的核函数。

核密度函数有多种核函数的选择方法,如高斯核函数、矩形核函数、三角核函数等等。

以高斯核函数为例,高斯核函数定义如下:

{\displaystyle K_{h}(x)=\frac{1}{\sqrt{2\pi}h}e^{-\frac{x^{2}}{2h^{2}}}}

其中,\sqrt{2\pi}h为高斯核函数的归一化常数。

2D 直方图

2D直方图法是将坐标系的区域等分成小格子,统计每个格子中数据点个数。通过统计每个格子中的数据点数量,可以计算出点密度。这种方法需要手动指定格子的大小,如果格子太小则噪音会很明显,如果格子太大则流畅性与细节会丢失。

当我们使用matplotlib库中的hexbinhist2d函数时,就应用了2D直方图方法。

计算不规则分布的点密度

在这篇文章中,我们将介绍两种计算不规则分布点密度的方法。

Kernel Density Estimation (KDE)方法

KDE方法是以核密度函数为基础,通过学习数据点的分布规律来估计数据的概率密度。在python中,scipy库中的kde类实现了KDE方法,可通过输入x, y坐标得到估测密度。例如:

from scipy.stats import gaussian_kde
import numpy as np

x = np.random.normal(size=1000) #生成一组随机数据点
y = np.random.normal(size=1000)
k = gaussian_kde(np.vstack([x, y])) #生成估测数据密度的KDE类实例
xi, yi = np.mgrid[x.min():x.max():100j, y.min():y.max():100j] #生成x,y坐标网格矩阵
zi = k(np.vstack([xi.flatten(), yi.flatten()])).reshape(xi.shape) #计算该坐标矩阵的估测密度矩阵

gaussian_kde函数需要传入的参数是一个二维数据矩阵。

x:第一维数据

y:第二维数据,如果不传入则使用第一维数据

bw_method:字符串或浮点数,表示带宽计算方法。若传入scaled,则带宽为默认值的0.75倍;若传入为None,则使用默认带宽;若传入浮点数,则使用该值作为带宽。

在上述代码中,我们生成了一组随机数据点,并使用vstack函数将它们转换为二维矩阵。然后我们创建了一个gaussian_kde类实例,并将矩阵传入实例中。接着,我们生成了一个二维坐标网格矩阵,并通过reshape函数将估测密度向量变形成与坐标网格矩阵相同的形状。至此,我们成功地计算了这些随机数据点的密度估计值。

我们可以使用imshow函数将估测密度矩阵绘制出来,使用colorbar函数添加颜色条:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.imshow(zi, cmap='Blues', extent=[x.min(), x.max(), y.min(), y.max()], aspect='auto')
ax.set_xlim([x.min(), x.max()])
ax.set_ylim([y.min(), y.max()])
plt.colorbar()
plt.show()

在横轴、纵轴上应该显示的实际坐标值,我们可以通过传递extent参数来设置。而aspect='auto'则可以保留绘图的比例。

2D直方图法

在2D直方图法中,我们需要将坐标系的区域等分成小格子,统计每个格子中数据点的数量,并使用imshow函数绘制。下面展示了如何使用histogram2d函数计算2D直方图:

import numpy as np

x = np.random.normal(size=1000) #生成一组随机数据点
y = np.random.normal(size=1000)
heatmap, xedges, yedges = np.histogram2d(x, y, bins=50) #生成数据点的直方图矩阵
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]] #直方图矩阵覆盖的区域
plt.clf()
plt.imshow(heatmap.T, extent=extent, origin='lower') #用imshow绘制直方图
plt.colorbar()
plt.show()

histogram2d函数需要传入的参数是:

x:第一维数据

y:第二维数据

bins:每个维度的直方图箱数

在上述代码中,我们生成了一组随机数据点,并使用histogram2d函数计算了点密度。直方图矩阵被保存在变量heatmap中,xedgesyedges则表示每个箱的坐标轴刻度。extent变量表示直方图矩阵覆盖的坐标范围。最后,我们使用imshow函数将直方图绘制出来。

比较两种方法

我们使用相同的随机数据点进行比较:

import numpy as np
from scipy.stats import gaussian_kde
import matplotlib.pyplot as plt

np.random.seed(0)
x = np.random.normal(size=1000)
y = np.random.normal(size=1000)

k = gaussian_kde(np.vstack([x, y]))
xi, yi = np.mgrid[x.min():x.max():100j, y.min():y.max():100j]
zi = k(np.vstack([xi.flatten(), yi.flatten()])).reshape(xi.shape)

heatmap, xedges, yedges = np.histogram2d(x, y, bins=100)

fig, axes = plt.subplots(1, 2, figsize=(10,5))
axes[0].imshow(zi, cmap='Blues', extent=[x.min(), x.max(), y.min(), y.max()], aspect='auto')
axes[0].set_xlim([x.min(), x.max()])
axes[0].set_ylim([y.min(), y.max()])
axes[0].set_title('KDE Method')
axes[1].imshow(heatmap.T, extent=[x.min(), x.max(), y.min(), y.max()], origin='lower')
axes[1].set_title('2D Hist Method')
plt.show()

我们生成一组一千个数据点,并使用上文介绍的KDE方法和2D直方图方法计算两种不规则分布数据点的密度。然后我们使用imshow函数在一张图中将它们绘制了出来。

从图中可以看出,KDE方法的绘图更加流畅而且细节更丰富,但计算时间也更长。而2D直方图方法则计算较快,但因为分辨率较低,显示不完整的细节。

总结

本文介绍了两种计算不规则分布数据点密度的方法:核密度估计法(KDE)和2D直方图法。KDE方法是通过学习数据点的分布规律来估计数据的概率密度。2D直方图法则是将坐标系的区域等分成小格子,统计每个格子中数据点的数量。虽然KDE方法的绘图更加流畅细节更丰富,但它的计算时间也更长;而2D直方图方法则计算较快,但因为分辨率较低,不会显示完整的细节。在实际应用中,我们可以根据具体情况选择合适的方法来计算点密度。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程