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)