Matplotlib 高效计算不规则点密度的方法

Matplotlib 高效计算不规则点密度的方法

在数据可视化中,点密度图是最常用的图形之一。然而,当数据点分布不均匀时,传统的点密度估计方法就会变得非常耗时,影响图表生成的效率,甚至无法正常生成图表。本文将介绍一种 Matplotlib 高效计算不规则点密度的方法,帮助我们在处理大量数据时,快速生成高效的密度图。

阅读更多:Matplotlib 教程

初识点密度图

什么是点密度图?

点密度图是一种通过在二维空间里绘制点来响应密度的图表,它将大量的点汇聚成一个图形来展示随机变量的走向和分布情况。点密度图能够很好的解决数据点重叠、数据分布不均、数据量较大等问题。

传统的点密度图生成方法

Matplotlib 中,我们可以使用其 hexbin() 方法或 scatter() 方法结合 matplotlib.colors 库中的 ListedColormap() 对象来生成点密度图。

hexbin() 方法能够自动划分 bins 区间,并将每个 bin 区间内的点的数量转化为颜色的深浅,并将其绘制到平面坐标中。

import matplotlib.pyplot as plt
import numpy as np

x, y = np.random.normal(size=(2, 20000))
plt.hexbin(x, y, gridsize=40, cmap='Blues')
plt.show()
Python

scatter() 方法结合 ListedColormap() 对象,将点的颜色与点所在区间内的点的数量所对应的颜色关联起来,从而生成点密度图。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap

x, y = np.random.normal(size=(2, 20000))
hb = plt.hexbin(x, y, gridsize=40, cmap='Blues')
cmap = ListedColormap(['white', 'cyan', 'lime', 'yellow', 'red'])
plt.scatter(x, y, c=hb.get_array(), cmap=cmap)
plt.colorbar(hb)
plt.show()
Python

这两种方法都能够很好的进行点密度估计,但是当数据点数量较大、越来越不规则时就会变得非常慢,并且在高维数据的情况下就会面临维度灾难。

Matplotlib高效计算不规则点密度的方法

Matplotlib 小知识

在介绍本文重点内容之前,先做一个小小的提醒。在进行数据可视化的实践当中,Matplotlib 的一些小技巧能够帮助我们大幅度提高绘图效率,例如:

  • 避免重复创建子图,使用 subplot2grid() 方法统一管理子图。
  • 使用类似 set_xscale() 之类的方法,来快速设置轴刻度。
  • 保留坐标轴、删除顶、右边框等。
  • 使用 set_yticklabels() 隐藏 Y 轴坐标标签 & 使用 text() 将坐标轴名称垂直显示。

具体实践可以参考代码:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap

x, y = np.random.normal(size=(2, 20000))
hb = plt.hexbin(x, y, grid### 高效计算不规则点密度
Python

在传统的点密度估计方法中,通常是将二维空间划分为一个一个的小方格,然后统计每个方格中数据点的数量。但是当数据点分布不均匀、不规则时,就会出现方格大小不一、方格间重叠等问题,从而导致点密度的计算变得极为繁琐且效率低下。

在解决这个问题的过程中,我们可以利用 KDE 方法。KDE(Kernel Density Estimation)又称核密度估计,是一种用来估计密度函数的非参数方法。其基本思想是在数据点的每个位置上摆上一个核函数,并对所有核函数进行平滑处理,最后得到一条连续的曲线,表示数据点的密度分布情况。

在 Matplotlib 中,我们可以使用 scipy.stats.gaussian_kde() 函数进行核密度估计,并利用 evaluate() 方法计算出每个位置的核密度值,从而得到点密度图。

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

x, y = np.random.normal(size=(2, 20000))
xy = np.vstack([x, y])
z = gaussian_kde(xy)(xy)  # 通过gaussian_kde函数计算核密度估计值
plt.scatter(x, y, c=z, s=50, edgecolor='')
plt.show()
Python

如上图所示,我们使用 gaussian_kde() 函数估计数据点的密度,并将其赋值给变量 z,最后使用 scatter() 方法结合 z 变量来绘制点密度图,并使用 s 参数来控制点的大小。

加速核密度估计

虽然我们已经成功地解决了密度计算不规则点密度图的问题,但是在实际使用中,当数据点数量非常大时,计算点密度图的效率还是会变得比较低。此时,我们可以使用几种方法来加速核密度估计。

1. Numba 加速

Numba 是一个基于 LLVM 的开源 JIT 编译器,可将 Python/NumPy 代码加速数十倍。下面是使用 Numba 加速核密度估计的示例代码:

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

@jit(nopython=True)  # 使用 Numba,加速计算效率
def kde_scipy(x, y, nbins=200j, r=0.25):
    X, Y = np.mgrid[1.1 * x.min():1.1 * x.max():nbins,
                    1.1 * y.min():1.1 * y.max():nbins]
    positions = np.vstack([X.ravel(), Y.ravel()])
    values = np.vstack([x, y])
    kernel = gaussian_kde(values, bw_method='silverman')
    Z = np.reshape(kernel(positions).T, X.shape)
    idxs = np.where(Z > Z.max() * r)
    return X[idxs], Y[idxs], Z[idxs]

x, y = np.random.normal(size=(2, 20000))
x, y, z = kde_scipy(x, y)
plt.scatter(x, y, c=z, s=50, edgecolor='')
plt.show()
Python

经过 Numba 加速后,程序的速度得到了显著的提升。

2. 直接利用灰度图

除了使用 Numba 加速,我们还可以直接计算出灰度图,并利用 Matplotlib 的 imshow()interpolation='nearest' 参数来直接绘制点密度图。

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

x, y = np.random.normal(size=(2, 20000))
xy = np.vstack([x, y])
z = gaussian_kde(xy)(xy)
_, _,z_bins = np.histogram2d(x, y, bins=100)[0]
plt.imshow(
    z_bins,
    cmap='Blues',
    interpolation='nearest',
    origin='lower',
    extent=[x.min(), x.max(), y.min(), y.max()],
)
plt.show()
Python

在以上代码中,我们使用 histogram2d() 方法来计算出灰度图,并且将 imshow() 方法的 interpolation='nearest' 参数设置为最邻近插值,从而得到了清晰的点密度图。

3. Pandas 加速

如果我们正在处理的数据是一个 Pandas 数据框,那么我们可以利用 Pandas 对数据框的高效计算能力来进一步加速核密度估计。下面是一个 Pandas 加速的核密度估计代码示例:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np

df = pd.DataFrame(np.random.normal(size=(20000, 2)), columns=['x', 'y'])
xmin, ymin = df.min(axis=0)
xmax, ymax = df.max(axis=0)
nbins = 300
f, ax = plt.subplots()
hb = ax.hexbin(
    df['x'],
    df['y'],
    gridsize=nbins,
    cmap='Blues', 
    norm=colors.LogNorm(),
    alpha=0.5,
    linewidths=0.2,
)
plt.colorbar(hb)
plt.show()
Python

使用 Pandas 来加速核密度估计的效果也是非常明显的。

总结

本文主要介绍了 Matplotlib 高效计算不规则点密度的方法。首先我们对点密度图进行了简单的介绍,并且讲解了传统方法的不足之处。接着我们介绍了核密度估计的基本原理,并通过代码示例演示了如何使用 gaussian_kde() 函数来进行核密度估计。最后,我们还介绍了加速计算的几种方法,包括使用 Numba 加速、直接利用灰度图和 Pandas 加速。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

登录

注册