对于相同的数据,为什么 scipy.stats.gaussian_kde() 比 seaborn.kde_plot() 慢?

2024-02-06

在 python 3.7 中,我有这个 numpy 数组,其形状=(2, 34900)。该数组是一个坐标列表,其中索引 0 表示 X 轴,索引 1 表示 y 轴。

当我使用 seaborn.kde_plot() 来可视化该数据的分布时,在 i5 第七代上运行时,我能够在大约 5-15 秒内获得结果。

但是当我尝试运行以下代码时:

#Find the kernel for 
k = scipy.stats.kde.gaussian_kde(data, bw_method=.3)
#Define the grid
xi, yi = np.mgrid[0:1:2000*1j, 0:1:2000*1j]
#apply the function
zi = k(np.vstack([xi.flatten(), yi.flatten()]))

它找到该数据的高斯核并将其应用于我定义的网格,这需要更多时间。我无法运行完整的数组,但在大小为 140 的切片上运行时,大约需要 40 秒才能完成。

140 大小的切片确实产生了一个有趣的结果,我可以使用它来可视化plt.pcolormesh().

我的问题是我在这里缺少什么。如果我正确理解发生了什么,我正在使用scipy.stats.kde.gaussian_kde()创建由数据定义的函数的估计。然后我将该函数应用于 2D 空间并获取它的 Z 分量作为结果。然后我绘制 Z 分量。但这个过程与seaborn.kde_plot()这使得代码需要更长的时间。

Scipy 的实现只是通过每个点来执行此操作:

for i in range(self.n):
    diff = self.dataset[:, i, newaxis] - points
    tdiff = dot(self.inv_cov, diff)
    energy = sum(diff*tdiff,axis=0) / 2.0
    result = result + exp(-energy)

Seaborn 通常有两种方法来计算二元 kde。如果可用,它使用statsmodels,如果不是,则回落到scipy.

scipy 代码与问题中显示的类似。它用scipy.stats.gaussian_kde https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.gaussian_kde.html#scipy.stats.gaussian_kde。 statsmodels 代码使用statsmodels.nonparametric.api.KDEMultivariate http://www.statsmodels.org/dev/generated/statsmodels.nonparametric.kernel_density.KDEMultivariate.html#statsmodels.nonparametric.kernel_density.KDEMultivariate.

然而,为了公平比较,我们需要对两种方法采用相同的网格大小。 Seaborn 的标准网格大小是 100 点。

import numpy as np; np.random.seed(42)
import seaborn.distributions as sd

N = 34900
x = np.random.randn(N)
y = np.random.randn(N)
bw="scott"
gridsize=100
cut=3
clip = [(-np.inf, np.inf), (-np.inf, np.inf)]

f = lambda x,y : sd._statsmodels_bivariate_kde(x, y, bw, gridsize, cut, clip)
g = lambda x,y : sd._scipy_bivariate_kde(x, y, bw, gridsize, cut, clip)

如果我们对这两个函数进行计时,

# statsmodels
%timeit f(x,y)  # 1 loop, best of 3: 16.4 s per loop
# scipy
%timeit g(x,y)  # 1 loop, best of 3: 8.67 s per loop

因此,Scipy 的速度是 statsmodels(seaborn 默认值)的两倍。问题中的代码花费这么长时间的原因是使用大小为 2000 的网格而不是大小为 100 的网格。

看到这些结果,人们实际上会想使用 scipy 而不是 statsmodels。不幸的是它不允许选择使用哪一个。因此需要手动设置相应的标志。

import seaborn.distributions as sd
sd._has_statsmodels = False
# plot kdeplot with scipy.stats.kde.gaussian_kde
sns.kdeplot(x,y)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对于相同的数据,为什么 scipy.stats.gaussian_kde() 比 seaborn.kde_plot() 慢? 的相关文章

随机推荐