我发现很难理解 SciPy 手册中关于如何gaussian_kde
处理 2D 数据的描述。这是一个旨在补充@endolith 示例的解释。我将代码分为几个步骤,并带有注释来解释不太直观的部分。
一、进口:
import numpy as np
import scipy.stats as st
from matplotlib.pyplot import imshow, show
创建一些虚拟数据:这些是“X”和“Y”点坐标的一维数组。
np.random.seed(142) # for reproducibility
x = st.norm.rvs(loc=2, scale=1, size=2000)
y = st.norm.rvs(loc=0, scale=3, size=2000)
对于二维密度估计,gaussian_kde
必须使用包含“X”和“Y”数据集的两行数组来初始化对象。在 NumPy 术语中,我们“垂直堆叠它们”:
xy = np.vstack((x, y))
所以“X”数据在第一行xy[0,:]
,“Y”数据在第二行xy[1,:]
,xy.shape
是(2, 2000)
. 现在创建gaussian_kde
对象:
dens = st.gaussian_kde(xy)
我们将在二维网格上评估估计的二维密度 PDF。在 NumPy 中创建这样一个网格的方法不止一种。我在这里展示了一种不同于(但在功能上等同于)@endolith 的方法的方法:
gx, gy = np.mgrid[x.min():x.max():128j, y.min():y.max():128j]
gxy = np.dstack((gx, gy)) # shape is (128, 128, 2)
gxy
是一个 3-D 数组, 的[i,j]
第 - 个元素gxy
包含对应“X”和“Y”值的 2 元素列表:gxy[i, j]
的值为[ gx[i], gy[j] ]
.
我们必须在每个二维网格点上调用dens()
(或者是同一件事)。dens.pdf()
为此,NumPy 有一个非常优雅的函数:
z = np.apply_along_axis(dens, 2, gxy)
换句话说,可调用对象dens
(也可以)在 3-D 数组中dens.pdf
沿axis=2
(第三个轴)被调用,gxy
并且值应该作为 2-D 数组返回。唯一的问题是z
will的形状(128,128,1)
不是(128,128)
我所期望的。请注意,文档说:
out [返回值,LD] 的形状与 arr 的形状相同,除了沿轴维度。该轴被移除,并替换为与 func1d 的返回值形状相等的新维度。因此,如果 func1d 返回一个标量输出将比 arr 少一个维度。
很可能dens()
返回一个 1 长的元组,而不是我希望的标量。我没有进一步调查这个问题,因为这很容易解决:
z = z.reshape(128, 128)
之后我们可以生成图像:
imshow(z, aspect=gx.ptp() / gy.ptp())
show() # needed if you try this in PyCharm
这是图像。(请注意,我也实现了 @endolith 的版本,并且得到了一张与这个无法区分的图像。)
