代码之家  ›  专栏  ›  技术社区  ›  Victor

为什么它是松软的。统计数据。gaussian\u kde()比seaborn慢。相同数据的kde\u plot()?

  •  5
  • Victor  · 技术社区  · 6 年前

    在python 3.7中,我有一个形状为(234900)的numpy数组。此数组是一个坐标列表,其中索引0表示X轴,索引1表示y轴。

    当我使用seaborn时。kde\u plot()为了可视化这些数据的分布,我可以在i5第7代上运行时,在大约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)
    
    2 回复  |  直到 6 年前
        1
  •  10
  •   ImportanceOfBeingErnest    6 年前

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

    scipy代码类似于问题中显示的代码。它使用 scipy.stats.gaussian_kde 。statsmodels代码使用 statsmodels.nonparametric.api.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)
    
        2
  •  -3
  •   Victor    6 年前

    似乎seaborn只是从我的数据中抽取了一个样本。由于尺寸较小,因此可以少量完成。另一方面,SciPy在处理过程中使用每一个点。因此,随着我使用的数据集的大小,这需要更长的时间。