contour 在尝试绘制多元高斯时抛出错误

contour throws an error trying to plot multivariate gaussian

我编写了一个小脚本来模拟 EM 算法并可视化其迭代步骤。然而,在第 5 次迭代之后,它在尝试绘制更新的估计双变量高斯分布时停止。

我怀疑我的协方差矩阵有问题,但我不太确定。如果我评论等高线图,脚本运行良好并且按预期工作(但当然最好遵循估计分布的演变)。任何帮助将不胜感激。

import numpy as np
import scipy.stats as sp
import matplotlib.pyplot as plt
from matplotlib.mlab import bivariate_normal


def expectationMaximization():
    # define multivariate gaussian distributions and generate observations
    u1 = [-1.5, -1.5]
    cov1 = [[0.2, 0.4],
            [0, 0.1]]

    u2 = [1, 1]
    cov2 = [[0.3, 0.4],
            [0, 0.3]]

    samples = 1000

    x1, y1 = np.random.multivariate_normal(u1, cov1, samples // 2).T
    x2, y2 = np.random.multivariate_normal(u2, cov2, samples // 2).T

    x = np.concatenate([x1, x2])
    y = np.concatenate([y1, y2])
    points = np.concatenate([np.column_stack((x1, y1)),
                             np.column_stack((x2, y2))])

    # initialization of classifier models
    uk1 = np.array([-1.5, 1])
    covk1 = np.array([[1, 0], [0, 1]])

    uk2 = np.array([1.5, -1])
    covk2 = np.array([[1, 0], [0, 1]])

    w = np.array([1., 1.])
    gamma = np.zeros((2, samples))

    # sim loop
    for idx in range(9):
        ##########################################################
        # expectation #
        ##########################################################
        # update gamma
        gamma[0] = (w[0] * sp.multivariate_normal.pdf(points, uk1, covk1) /
                    (w[0] * sp.multivariate_normal.pdf(points, uk1, covk1) +
                     w[1] * sp.multivariate_normal.pdf(points, uk2, covk2)))
        gamma[1] = (w[1] * sp.multivariate_normal.pdf(points, uk2, covk2) /
                    (w[0] * sp.multivariate_normal.pdf(points, uk1, covk1) +
                     w[1] * sp.multivariate_normal.pdf(points, uk2, covk2)))

        ##########################################################
        # plot #
        ##########################################################
        plt.subplot(3, 3, idx + 1)
        plt.title('Iteration {}'.format(idx + 1))
        axes = plt.gca()
        axes.set_xlim([-3, 3])
        axes.set_ylim([-3, 3])

        # setup grid for bivariate gaussian plot (only needed once)
        if idx < 1:
            xmin, xmax = axes.get_xlim()
            ymin, ymax = axes.get_ylim()
            delta = 0.1
            xticks = np.arange(xmin, xmax, delta)
            yticks = np.arange(ymin, ymax, delta)
            xmesh, ymesh = np.meshgrid(xticks, yticks)

        # update mesh values
        z1 = bivariate_normal(xmesh, ymesh, covk1[0, 0], covk1[1, 1],
                              uk1[0], uk1[1], covk1[0, 1])
        z2 = bivariate_normal(xmesh, ymesh, covk2[0, 0], covk2[1, 1],
                              uk2[0], uk2[1], covk2[0, 1])
        z = (z1 - z2) * 10

        # plot pdf map and sample points
        plt.contour(xmesh, ymesh, z)
        plt.scatter(x, y, c=(gamma[0] - gamma[1]) * 10)
        plt.grid(True)

        ##########################################################
        # maximization #
        ##########################################################
        # update means
        uk1[0] = sum(gamma[0] * x) / sum(gamma[0])
        uk1[1] = sum(gamma[0] * y) / sum(gamma[0])

        uk2[0] = sum(gamma[1] * x) / sum(gamma[1])
        uk2[1] = sum(gamma[1] * y) / sum(gamma[1])

        # update covariance matrices
        # calc all distances
        dist1 = points - uk1[None, :]
        dist2 = points - uk2[None, :]

        # calc all outer products
        matrixSchaar1 = np.einsum('...i,...j->...ij', dist1, dist1)
        matrixSchaar2 = np.einsum('...i,...j->...ij', dist2, dist2)

        # calculate sum product of matrices and gammas
        covk1 = ((matrixSchaar1 * gamma[0][:, None, None]).sum(axis=0) /
                 sum(gamma[0]))
        covk2 = ((matrixSchaar2 * gamma[1][:, None, None]).sum(axis=0) /
                 sum(gamma[1]))

        # update w
        w[0] = sum(gamma[0]) / len(gamma[0])
        w[1] = sum(gamma[1]) / len(gamma[1])


def main():
    expectationMaximization()
    plt.show()

if __name__ == "__main__":
    main()

回溯:

    /usr/lib64/python3.5/site-packages/matplotlib/mlab.py:1926: RuntimeWarning: invalid value encountered in sqrt
  denom = 2*np.pi*sigmax*sigmay*np.sqrt(1-rho**2)
Traceback (most recent call last):
  File "bsp4.py", line 120, in <module>
    main()
  File "bsp4.py", line 115, in main
    expectationMaximization()
  File "bsp4.py", line 76, in expectationMaximization
    plt.contour(xmesh, ymesh, z)
  File "/usr/lib64/python3.5/site-packages/matplotlib/pyplot.py", line 2766, in contour
    ret = ax.contour(*args, **kwargs)
  File "/usr/lib64/python3.5/site-packages/matplotlib/__init__.py", line 1815, in inner
    return func(ax, *args, **kwargs)
  File "/usr/lib64/python3.5/site-packages/matplotlib/axes/_axes.py", line 5644, in contour
    return mcontour.QuadContourSet(self, *args, **kwargs)
  File "/usr/lib64/python3.5/site-packages/matplotlib/contour.py", line 1424, in __init__
    ContourSet.__init__(self, ax, *args, **kwargs)
  File "/usr/lib64/python3.5/site-packages/matplotlib/contour.py", line 864, in __init__
    self._process_levels()
  File "/usr/lib64/python3.5/site-packages/matplotlib/contour.py", line 1202, in _process_levels
    self.vmin = np.amin(self.levels)
  File "/usr/lib64/python3.5/site-packages/numpy/core/fromnumeric.py", line 2359, in amin
    out=out, keepdims=keepdims)
  File "/usr/lib64/python3.5/site-packages/numpy/core/_methods.py", line 29, in _amin
    return umr_minimum(a, axis, None, out, keepdims)
ValueError: zero-size array to reduction operation minimum which has no identity

开始作为评论,但变得太长了...

你怀疑你的协变矩阵是对的。您的 bivariate_normal 分布,z1z2,在第 5 次或第 6 次迭代后始终变为 nan 数组。但是,我认为这并不一定意味着您的代码有缺陷,它可能只是一个不方便的数字问题(我对这里的理论一无所知)。

无论如何,您可以通过设置等高线图的级别

,使等高线在分解前达到第 i 次迭代
levels = np.linspace(z.min(), z.max(), 20)
plt.contour(xmesh, ymesh, z, levels=levels)

据我所知,ValueError 是由于等高线无法设置其最小值所致。

是时候感觉自己像个骗子了。

找到答案here

简而言之,bivariate_normal() 需要标准偏差值,而不是方差。

改正错误后,一切正常。