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
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))
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
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)
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
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