核密度估计(KDE对于这个问题)是一个更有效的工具。这个gaussian_kde估计方法可以被用来估计
    单元或多元数据的PDF。它在数据呈单峰的时候工作的最好,但也可以在多峰情况下工作。

    我们以一个最小数据集来观察gaussian_kde是如何工作的,以及带宽(bandwidth)的不同选择方式。
    PDF对应的数据被以蓝线的形式显示在图像的底端(被称为毯图(rug plot))

    我们看到在Scott规则以及Silverman规则下的结果几乎没有差异。以及带宽的选择相比较于
    数据的稀少显得太宽。我们可以定义我们的带宽函数以获得一个更少平滑的结果。

    1. ... """We use Scott's Rule, multiplied by a constant factor."""
    2. ... return np.power(obj.n, -1./(obj.d+4)) * fac
    3. >>> fig = plt.figure()
    4. >>> ax = fig.add_subplot(111)
    5. >>> ax.plot(x1, np.zeros(x1.shape), 'b+', ms=20) # rug plot
    6. >>> kde3 = stats.gaussian_kde(x1, bw_method=my_kde_bandwidth)
    7. >>> ax.plot(x_eval, kde3(x_eval), 'g-', label="With smaller BW")
    8. >>> plt.show()

    我们看到如果我们设置带宽为非常狭窄,则获得PDF的估计退化为围绕在数据点的简单的高斯和。

    我们现在使用更真实的例子,并且看看在两种带宽选择规则中的差异。这些规则被认为在
    正态分布上很好用,但即使是偏离正态的单峰分布上它也工作的很好。作为一个非正态分布,
    我们采用5自由度的t分布。

    核密度估计 - 图3

    下面我们看到这个一个宽一个窄的双峰分布。可以想到结果将难达到以十分近似,
    因为每个峰需要不同的带宽去拟合。

    1. >>> from functools import partial
    2. >>> loc2, scale2, size2 = (2, 0.2, 50)
    3. ... np.random.normal(loc=loc2, scale=scale2, size=size2)])
    4. >>> x_eval = np.linspace(x2.min() - 1, x2.max() + 1, 500)
    5. >>> kde = stats.gaussian_kde(x2)
    6. >>> kde2 = stats.gaussian_kde(x2, bw_method='silverman')
    7. >>> kde3 = stats.gaussian_kde(x2, bw_method=partial(my_kde_bandwidth, fac=0.2))
    8. >>> kde4 = stats.gaussian_kde(x2, bw_method=partial(my_kde_bandwidth, fac=0.5))
    9. >>> pdf = stats.norm.pdf
    10. >>> bimodal_pdf = pdf(x_eval, loc=loc1, scale=scale1) * float(size1) / x2.size + \
    11. ... pdf(x_eval, loc=loc2, scale=scale2) * float(size2) / x2.size
    12. >>> fig = plt.figure(figsize=(8, 6))
    13. >>> ax.plot(x2, np.zeros(x2.shape), 'b+', ms=12)
    14. >>> ax.plot(x_eval, kde(x_eval), 'k-', label="Scott's Rule")
    15. >>> ax.plot(x_eval, kde2(x_eval), 'b-', label="Silverman's Rule")
    16. >>> ax.plot(x_eval, kde3(x_eval), 'g-', label="Scott * 0.2")
    17. >>> ax.plot(x_eval, kde4(x_eval), 'c-', label="Scott * 0.5")
    18. >>> ax.plot(x_eval, bimodal_pdf, 'r--', label="Actual PDF")
    19. >>> ax.set_xlim([x_eval.min(), x_eval.max()])
    20. >>> ax.legend(loc=2)
    21. >>> ax.set_xlabel('x')
    22. >>> ax.set_ylabel('Density')
    23. >>> plt.show()

    正如预想的,KDE并没有很好的趋近正确的PDF,因为双峰分布的形状不同。通过使用默认带宽
    (Scott*0.5)我们可以做得更好,再使用更小的带宽将使平滑性受到影响。这里我们真正需要
    的是非均匀(自适应)带宽。

    多元估计

    通过gaussian_kde我们可以像单元估计那样进行多元估计。我们现在来解决二元情况,
    首先我们产生一些随机的二元数据。

    然后我们对这些数据使用KDE:

    1. >>> X, Y = np.mgrid[xmin:xmax:100j, ymin:ymax:100j]
    2. >>> positions = np.vstack([X.ravel(), Y.ravel()])
    3. >>> values = np.vstack([m1, m2])
    4. >>> Z = np.reshape(kernel.evaluate(positions).T, X.shape)

    最后我们把估计的双峰分布以colormap形式显示出来,并且在上面画出每个数据点。