Exemple #1
0
    def sample_prior(self, proj_2_prob=False):
        """
        Samples Probability matrix from the prior

        Parameters
        ----------
        proj_2_prob: Bool: if TRUE  returns the projection to the probability simplex

        Returns
        -------
            x - Dict: keys: mu, Sigma, Psi, Pi (optional)
            mu: [MxK_prime] Normal sample from the prior
            Sigma: [MxM] Inverse Wishart sample from the prior
            Psi: [MxK_prime] Normal sample from the prior distribution
            Pi: [M x K] Probability matrix over K categories
        """
        Psi = []
        Sigma = invwishart.rvs(self.hyper['nu_0'], inv(self.hyper['W_0']))
        mu = np.zeros((self.M, self.K_prime))
        for k in range(self.K_prime):
            mu[:,
               k] = multivariate_normal(self.hyper['mu_0'][:, k],
                                        1 / self.hyper['lambda_0'][k] * Sigma)
            Psi.append(multivariate_normal(mu[:, k], Sigma))

        # Pi = stick_breaking(np.array(Psi))

        if proj_2_prob:
            Pi = stick_breaking(np.array(Psi))
            x = {'Psi': Psi, 'Pi': Pi, 'mu': mu, 'Sigma': Sigma}
        else:
            x = {'Psi': Psi, 'mu': mu, 'Sigma': Sigma}

        return x
Exemple #2
0
def PGinfer(data, mu, Sigma, nonInformative, nSamples, nBurnin):
    """
    Helper function for inference of correlated probabilities
    Parameters
    ----------
    data - [M x K] - counts of K categories for a set of M histograms
    nSamples - Number of posterior samples
    mu - [MxK-1] Mean parameter for the prior variables in the normal sigmoid multinomial model
    Sigma- [MxM] Covariance parameter for the prior variables in the normal sigmoid multinomial model

    Returns
    -------
    nSamples of the [MxK] probability matrices
    """
    nDists, nCats = data.shape
    PgMultObj = PgMultNormal(M=nDists,
                             K_prime=nCats - 1,
                             mu=mu,
                             Sigma=Sigma,
                             nonInformative=nonInformative)
    samples = PgMultObj.sample_posterior(nSamples,
                                         data,
                                         disp=False,
                                         burnin=nBurnin)
    Psi = samples['Psi']
    Pi_samples = np.array([stick_breaking(sample) for sample in Psi])
    return Pi_samples
Exemple #3
0
    def sample_prior(self, proj_2_prob=False):
        """
        Samples Probability matrix from the prior

        Parameters
        ----------
        proj_2_prob: Bool: if TRUE  returns the projection to the probability simplex

        Returns
        -------
            x - Dict: keys: Psi, Pi (optional)
            Psi: [MxK_prime] Normal sample from the prior distribution
            Pi: [M x K] Probability matrix over K categories
        """

        Psi = np.array([
            multivariate_normal(self.hyper['mu'][:, k], self.hyper['Sigma'])
            for k in range(self.K_prime)
        ]).T
        if proj_2_prob:
            Pi = stick_breaking(Psi)
            x = {'Psi': Psi, 'Pi': Pi}
        else:
            x = {'Psi': Psi}

        return x
    def mean(self):
        """

        Returns
        -------
        the stickbreaking transformation of the posterior mean of the transition model
        """
        if not self.isFitted:
            self.fit()

        T = np.zeros_like(self.data)
        for action in range(self.nActions):
            Pi = stick_breaking(self.lambda_[action])  # np.array(stick_breaking(samples['Psi'][-1]))
            T[:, :, action] = Pi.T
        return T
Exemple #5
0
    def sample_var_posterior(self, N_samples, proj_2_prob=False):
        """
        Creates N samples from the variational posterior
        Parameters
        ----------
        N_samples - number of posterior samples
        proj_2_prob: Bool: if TRUE  returns the projection to the probability simplex

        Returns
        -------

        """
        # container for the posterior samples
        if proj_2_prob:
            post_samples = {'Pi': [], 'Psi': []}
        else:
            post_samples = {'Psi': []}

        Psi_sam = np.zeros((N_samples, self.M, self.K_prime))
        if self.hyper['nonInformative']:
            Psi_sam = self.var_param['V_diag'][None, :, :] * np.random.randn(N_samples, self.M, self.K_prime) + \
                      self.var_param['lambda_'][None, :, :]
        else:

            # Precompute cholesky if not already calculated
            if self.var_param['V_cho'] is None:
                V_cho = np.zeros_like(self.var_param['V'])
                for k in range(self.K_prime):
                    V_cho[:, :, k] = cholesky(self.var_param['V'][:, :, k])
                self.var_param['V_cho'] = V_cho

            # sample using cholesky
            for n in range(N_samples):
                for k in range(self.K_prime):
                    Psi_sam[n, :, k] = cholesky_normal(
                        self.var_param['lambda_'][:, k],
                        U=self.var_param['V_cho'][:, :, k])

        post_samples['Psi'] = [sam for sam in Psi_sam]
        if proj_2_prob:
            post_samples['Pi'] = [
                stick_breaking(sam.copy()) for sam in post_samples['Psi']
            ]

        return post_samples
Exemple #6
0
    def gibbs_step(self, X=None, Psi_init=None, proj_2_prob=False):
        """
        calculates one gibbs step
        Parameters
        ----------
        proj_2_prob: Bool: if TRUE  returns the projection to the probability simplex
        X: [MxK] data matrix if None previously saved training data is used
        Psi_init: [MxK_prime] starting value of the Gibbs sampler for the normal distributed variables
            (if None last value is used)

        Returns
        -------
        x - Dict: keys: Psi, omega Pi (optional)
        Psi: [MxK_prime] One normal sample from the posterior distribution
        omega: [MxK_prime] One PG sample from the posterior distribution
        Pi: [M x K] One sample from the probability matrix over K categories
        """

        if X is not None:
            self.X_train = X
        if Psi_init is not None:
            self.Psi_init = Psi_init

        # --------------- update polya-gamma variables --------------- #
        # polya-gamma auxiliary variable
        omega_sam = poly_gamma_rand(self._N_mat, self.Psi_init)

        # --------------- update latent Gaussian variables --------------- #
        # sample new latent Gaussian variables
        Psi_sam = self.sample_Psi(self._kappa,
                                  omega_sam,
                                  self.hyper['mu'],
                                  self.hyper['Sigma'],
                                  Sigma_inv=self.hyper['Sigma_inv'],
                                  nonInformative=self.hyper['nonInformative'])

        self.Psi_init = Psi_sam

        if proj_2_prob:
            Pi = stick_breaking(Psi_sam)
            x = {'Psi': Psi_sam, 'omega': omega_sam, 'Pi': Pi}
        else:
            x = {'Psi': Psi_sam, 'omega': omega_sam}

        return x
Exemple #7
0
    def mean_variational_posterior(self, proj_2_prob=False):
        """
        Returns the mean of the variational posterior
        Parameters
        ----------
         proj_2_prob: Bool: if TRUE  returns the projection to the probability simplex

        Returns
        -------
        mean - dictonary containing the variational mean
        """
        if proj_2_prob:
            mean = {'Pi': None, 'Psi': None}
        else:
            mean = {'Psi': None}

        mean['Psi'] = self.var_param['lambda_']
        if proj_2_prob:
            mean['Pi'] = stick_breaking(self.var_param['lambda_'])
        return mean
Exemple #8
0
    def sample_posterior(self,
                         N_samples,
                         X,
                         Psi_init=None,
                         burnin=0,
                         thinning=0,
                         disp=True,
                         proj_2_prob=False):
        """
        Samples N_samples from the Posterior given data X
        Parameters
        ----------
        N_samples: Number of samples to draw from the posterior
        X: [M x K] Count data used to do posterior inference
        Psi_init: initial value for the gibbs sampler
        burnin: int number of burnin samples
        thinning: number of discarded values in the chain between two samples
        disp: output steps of the MCMC sampler in the console
        proj_2_prob: Bool: if TRUE  returns the projection to the probability simplex

        Returns
        -------
        post_samples - Dict: keys: Psi, omega, mu, Sigma, Pi (optional)
        Psi: List of posterior samples for the Gaussians
        omega: List of posterior samples for the Poly Gamma variables
        Sigma: List of posterior samples for covariance matrix
        mu: List of posterior samples for the means
        Pi: List of posterior samples for the probability matrix over K categories
        """

        # container for the posterior samples
        post_samples = {
            'Pi': [],
            'Psi': [],
            'omega': [],
            'mu': [],
            'Sigma': []
        }

        # initialize latent Gaussian random variables
        if Psi_init is not None:
            self.Psi_init = Psi_init

        self.X_train = X  # Save input and compute sufficient stats

        # generate Gibbs samples
        enough_samples = False
        n = 0
        while not enough_samples:
            n += 1
            # Print results
            if disp:
                print(tabulate([[n]], headers=['MCMC sampling step']))

            sam = self.gibbs_step()
            # add samples to list
            if n > burnin and np.mod(n, thinning + 1) == 0:
                if proj_2_prob:
                    post_samples['Pi'].append(stick_breaking(
                        sam['Psi'].copy()))

                post_samples['Psi'].append(sam['Psi'].copy())
                post_samples['omega'].append(sam['omega'].copy())
                post_samples['mu'].append(sam['mu'].copy())
                post_samples['Sigma'].append(sam['Sigma'].copy())

            if post_samples['Psi'].__len__() == N_samples:
                enough_samples = True

        return post_samples
Exemple #9
0
    def gibbs_step(self, X=None, Psi_init=None, proj_2_prob=False):
        """
        calculates one gibbs step
        Parameters
        ----------
        X: [MxK] data matrix if None previously saved training data is used
        Psi_init: [MxK_prime] starting value of the Gibbs sampler for the normal distributed variables
            (if None last value is used)
        proj_2_prob: Bool: if TRUE  returns the projection to the probability simplex


        Returns
        -------
        x - Dict: keys: Psi, omega, mu, Sigma, Pi (optional)
        Psi: [MxK_prime] One normal sample from the posterior distribution
        omega: [MxK_prime] One PG sample from the posterior distribution
        mu: [MxK_prime] One mean parameter sample from the posterior distribution
        Sigma: [MxM] One covariance parameter sample from the posterior distribution
        Pi: [M x K] One sample from the probability matrix over K categories
        """
        if X is not None:
            self.X_train = X
        if Psi_init is not None:
            self.Psi_init = Psi_init

        # --------------- update Gaussian covariance matrix --------------- #
        # posterior covariance hyperparameter
        Psi_centered = self.Psi_init - self.hyper['mu_0']
        W_bar = self.hyper['W_0'] + (self._lambda_ratio *
                                     Psi_centered) @ Psi_centered.T

        # sample new covariance matrix
        Sigma_sam = invwishart.rvs(self._nu_bar, inv(W_bar))

        # --------------- update Gaussian means --------------- #
        # posterior mean hyperparameters
        mu_bar = (self.hyper['mu_0'] * self.hyper['lambda_0'] +
                  self.Psi_init) / self._lambda_bar

        # sample new mean values
        mu_sam = np.zeros((self.M, self.K_prime))
        U = cholesky(Sigma_sam)
        for k in range(self.K_prime):
            mu_sam[:,
                   k] = cholesky_normal(mu_bar[:, k],
                                        U=1 / np.sqrt(self._lambda_bar[k]) * U)

        # --------------- update polya-gamma variables --------------- #
        # polya-gamma auxiliary variable
        omega_sam = poly_gamma_rand(self._N_mat, self.Psi_init)

        # --------------- update latent Gaussian variables --------------- #
        # sample new latent Gaussian variables
        Psi_sam = self.sample_Psi(self._kappa, omega_sam, mu_sam, Sigma_sam)

        self.Psi_init = Psi_sam

        if proj_2_prob:
            Pi = stick_breaking(Psi_sam)
            x = {
                'Psi': Psi_sam,
                'omega': omega_sam,
                'Pi': Pi,
                'mu': mu_sam,
                'Sigma': Sigma_sam
            }
        else:
            x = {
                'Psi': Psi_sam,
                'omega': omega_sam,
                'mu': mu_sam,
                'Sigma': Sigma_sam
            }

        return x  # Psi_sam, omega_sam, mu_sam, Sigma_sam