Esempio n. 1
0
    def random(self, *phi, plates=None):
        """
        Draw a random sample from the distribution.
        """
        # Convert natural parameters to transition probabilities
        p0 = np.exp(phi[0] - misc.logsumexp(phi[0], axis=-1, keepdims=True))
        P = np.exp(phi[1] - misc.logsumexp(phi[1], axis=-1, keepdims=True))
        # Explicit broadcasting
        P = P * np.ones(plates)[..., None, None, None]
        # Allocate memory
        Z = np.zeros(plates + (self.N, ), dtype=np.int)
        # Draw initial state
        Z[..., 0] = random.categorical(p0, size=plates)
        # Create [0,1,2,...,len(plate_axis)] indices for each plate axis and
        # make them broadcast properly
        nplates = len(plates)
        plates_ind = [
            np.arange(plate)[(Ellipsis, ) + (nplates - i - 1) * (None, )]
            for (i, plate) in enumerate(plates)
        ]
        plates_ind = tuple(plates_ind)
        # Draw next states iteratively
        for n in range(self.N - 1):
            # Select the transition probabilities for the current state but take
            # into account the plates.  This leads to complex NumPy
            # indexing.. :)
            time_ind = min(n, np.shape(P)[-3] - 1)
            ind = plates_ind + (time_ind, Z[..., n], Ellipsis)
            p = P[ind]
            # Draw next state
            z = random.categorical(P[ind])
            Z[..., n + 1] = z

        return Z
    def random(self, *phi, plates=None):
        """
        Draw a random sample from the distribution.
        """
        # Convert natural parameters to transition probabilities
        p0 = np.exp(phi[0] - misc.logsumexp(phi[0], axis=-1, keepdims=True))
        P = np.exp(phi[1] - misc.logsumexp(phi[1], axis=-1, keepdims=True))
        # Explicit broadcasting
        P = P * np.ones(plates)[..., None, None, None]
        # Allocate memory
        Z = np.zeros(plates + (self.N,), dtype=np.int)
        # Draw initial state
        Z[..., 0] = random.categorical(p0, size=plates)
        # Create [0,1,2,...,len(plate_axis)] indices for each plate axis and
        # make them broadcast properly
        nplates = len(plates)
        plates_ind = [np.arange(plate)[(Ellipsis,) + (nplates - i - 1) * (None,)] for (i, plate) in enumerate(plates)]
        plates_ind = tuple(plates_ind)
        # Draw next states iteratively
        for n in range(self.N - 1):
            # Select the transition probabilities for the current state but take
            # into account the plates.  This leads to complex NumPy
            # indexing.. :)
            time_ind = min(n, np.shape(P)[-3] - 1)
            ind = plates_ind + (time_ind, Z[..., n], Ellipsis)
            p = P[ind]
            # Draw next state
            z = random.categorical(P[ind])
            Z[..., n + 1] = z

        return Z
Esempio n. 3
0
 def __str__(self):
     """
     Print the distribution using standard parameterization.
     """
     logsum_p = misc.logsumexp(self.phi[0], axis=-1, keepdims=True)
     p = np.exp(self.phi[0] - logsum_p)
     p /= np.sum(p, axis=-1, keepdims=True)
     return ("%s ~ Multinomial(p)\n" "  p = \n" "%s\n" % (self.name, p))
Esempio n. 4
0
 def __str__(self):
     """
     Print the distribution using standard parameterization.
     """
     logsum_p = misc.logsumexp(self.phi[0], axis=-1, keepdims=True)
     p = np.exp(self.phi[0] - logsum_p)
     p /= np.sum(p, axis=-1, keepdims=True)
     return ("%s ~ Multinomial(p)\n"
             "  p = \n"
             "%s\n"
             % (self.name, p))
Esempio n. 5
0
 def show(self):
     """
     Print the distribution using standard parameterization.
     """
     logsum_p = misc.logsumexp(self.phi[0], axis=-1, keepdims=True)
     p = np.exp(self.phi[0] - logsum_p)
     p /= np.sum(p, axis=-1, keepdims=True)
     print("%s ~ Multinomial(p)" % self.name)
     print("  p = ")
     print(p)
     return
Esempio n. 6
0
 def compute_moments_and_cgf(self, phi, mask=True):
     """
     Compute the moments and :math:`g(\phi)`.
     """
     # Compute the normalized probabilities in a numerically stable way
     logsum_p = misc.logsumexp(phi[0], axis=-1, keepdims=True)
     logp = phi[0] - logsum_p
     p = np.exp(logp)
     # Because of small numerical inaccuracy, normalize the probabilities
     # again for more accurate results
     N = np.expand_dims(self.N, -1)
     u0 = N * p / np.sum(p, axis=-1, keepdims=True)
     u = [u0]
     g = -np.squeeze(N * logsum_p, axis=-1)
     return (u, g)
Esempio n. 7
0
 def compute_moments_and_cgf(self, phi, mask=True):
     """
     Compute the moments and :math:`g(\phi)`.
     """
     # Compute the normalized probabilities in a numerically stable way
     logsum_p = misc.logsumexp(phi[0], axis=-1, keepdims=True)
     logp = phi[0] - logsum_p
     p = np.exp(logp)
     # Because of small numerical inaccuracy, normalize the probabilities
     # again for more accurate results
     N = np.expand_dims(self.N, -1)
     u0 = N * p / np.sum(p, axis=-1, keepdims=True)
     u = [u0]
     g = -np.squeeze(N * logsum_p, axis=-1)
     return (u, g)
Esempio n. 8
0
def gaussian_mixture_2d(X,
                        alpha=None,
                        scale=2,
                        fill=False,
                        axes=None,
                        **kwargs):
    """
    Plot Gaussian mixture as ellipses in 2-D

    Parameters
    ----------

    X : Mixture node

    alpha : Dirichlet-like node (optional)
       Probabilities for the clusters

    scale : float (optional)
       Scale for the covariance ellipses (by default, 2)
    """

    if axes is None:
        axes = plt.gca()

    mu_Lambda = X.parents[1]._convert(GaussianWishartMoments)

    (mu, _, Lambda, _) = mu_Lambda.get_moments()
    mu = np.linalg.solve(Lambda, mu)

    if len(mu_Lambda.plates) != 1:
        raise NotImplementedError("Not yet implemented for more plates")

    K = mu_Lambda.plates[0]

    width = np.zeros(K)
    height = np.zeros(K)
    angle = np.zeros(K)

    for k in range(K):
        m = mu[k]
        L = Lambda[k]
        (u, W) = scipy.linalg.eigh(L)
        u[0] = np.sqrt(1 / u[0])
        u[1] = np.sqrt(1 / u[1])
        width[k] = 2 * u[0]
        height[k] = 2 * u[1]
        angle[k] = np.arctan(W[0, 1] / W[0, 0])

    angle = 180 * angle / np.pi
    mode_height = 1 / (width * height)

    # Use cluster probabilities to adjust alpha channel
    if alpha is not None:
        # Compute the normalized probabilities in a numerically stable way
        logsum_p = misc.logsumexp(alpha.u[0], axis=-1, keepdims=True)
        logp = alpha.u[0] - logsum_p
        p = np.exp(logp)
        # Visibility is based on cluster mode peak height
        visibility = mode_height * p
        visibility /= np.amax(visibility)
    else:
        visibility = np.ones(K)

    for k in range(K):
        ell = mpl.patches.Ellipse(mu[k],
                                  scale * width[k],
                                  scale * height[k],
                                  angle=(180 + angle[k]),
                                  fill=fill,
                                  alpha=visibility[k],
                                  **kwargs)
        axes.add_artist(ell)

    plt.axis('equal')

    # If observed, plot the data too
    if np.any(X.observed):
        mask = np.array(X.observed) * np.ones(X.plates, dtype=np.bool)
        y = X.u[0][mask]
        plt.plot(y[:, 0], y[:, 1], 'r.')

    return
Esempio n. 9
0
def gaussian_mixture_2d(X, alpha=None, scale=2, fill=False, axes=None, **kwargs):
    """
    Plot Gaussian mixture as ellipses in 2-D

    Parameters
    ----------

    X : Mixture node

    alpha : Dirichlet-like node (optional)
       Probabilities for the clusters

    scale : float (optional)
       Scale for the covariance ellipses (by default, 2)
    """
        
    if axes is None:
        axes = plt.gca()

    mu_Lambda = X._ensure_moments(X.parents[1], GaussianWishartMoments)

    (mu, _, Lambda, _) = mu_Lambda.get_moments()
    mu = np.linalg.solve(Lambda, mu)

    if len(mu_Lambda.plates) != 1:
        raise NotImplementedError("Not yet implemented for more plates")
    
    K = mu_Lambda.plates[0]

    width = np.zeros(K)
    height = np.zeros(K)
    angle = np.zeros(K)

    for k in range(K):
        m = mu[k]
        L = Lambda[k]
        (u, W) = scipy.linalg.eigh(L)
        u[0] = np.sqrt(1/u[0])
        u[1] = np.sqrt(1/u[1])
        width[k] = 2*u[0]
        height[k] = 2*u[1]
        angle[k] = np.arctan(W[0,1] / W[0,0])

    angle = 180 * angle / np.pi
    mode_height = 1 / (width * height)

    # Use cluster probabilities to adjust alpha channel
    if alpha is not None:
        # Compute the normalized probabilities in a numerically stable way
        logsum_p = misc.logsumexp(alpha.u[0], axis=-1, keepdims=True)
        logp = alpha.u[0] - logsum_p
        p = np.exp(logp)
        # Visibility is based on cluster mode peak height
        visibility = mode_height * p
        visibility /= np.amax(visibility)
    else:
        visibility = np.ones(K)

    for k in range(K):
        ell = mpl.patches.Ellipse(mu[k], scale*width[k], scale*height[k],
                                  angle=(180+angle[k]),
                                  fill=fill,
                                  alpha=visibility[k],
                                  **kwargs)
        axes.add_artist(ell)

    plt.axis('equal')

    # If observed, plot the data too
    if np.any(X.observed):
        mask = np.array(X.observed) * np.ones(X.plates, dtype=np.bool)
        y = X.u[0][mask]
        plt.plot(y[:,0], y[:,1], 'r.')

    return