Exemple #1
0
    def predict(self, Xnew, point=None, diag=False, pred_noise=False, given=None):
        R"""
        Return the mean vector and covariance matrix of the conditional
        distribution as numpy arrays, given a `point`, such as the MAP
        estimate or a sample from a `trace`.

        Parameters
        ----------
        Xnew : array-like
            Function input values.  If one-dimensional, must be a column
            vector with shape `(n, 1)`.
        point : pymc3.model.Point
            A specific point to condition on.
        diag : bool
            If `True`, return the diagonal instead of the full covariance
            matrix.  Default is `False`.
        pred_noise : bool
            Whether or not observation noise is included in the conditional.
            Default is `False`.
        given : dict
            Same as `conditional` method.
        """
        if given is None:
            given = {}

        mu, cov = self.predictt(Xnew, diag, pred_noise, given)
        return draw_values([mu, cov], point=point)
Exemple #2
0
    def astep(self, q0, logp):
        """q0: current state
        logp: log probability function
        """

        # Draw from the normal prior by multiplying the Cholesky decomposition
        # of the covariance with draws from a standard normal
        chol = draw_values([self.prior_chol])[0]
        nu = np.dot(chol, nr.randn(chol.shape[0]))
        y = logp(q0) - nr.standard_exponential()

        # Draw initial proposal and propose a candidate point
        theta = nr.uniform(0, 2 * np.pi)
        theta_max = theta
        theta_min = theta - 2 * np.pi
        q_new = q0 * np.cos(theta) + nu * np.sin(theta)

        while logp(q_new) <= y:
            # Shrink the bracket and propose a new point
            if theta < 0:
                theta_min = theta
            else:
                theta_max = theta
            theta = nr.uniform(theta_min, theta_max)
            q_new = q0 * np.cos(theta) + nu * np.sin(theta)

        return q_new
Exemple #3
0
    def predict(self,
                Xnew,
                point=None,
                diag=False,
                pred_noise=False,
                given=None):
        R"""
        Return the mean vector and covariance matrix of the conditional
        distribution as numpy arrays, given a `point`, such as the MAP
        estimate or a sample from a `trace`.

        Parameters
        ----------
        Xnew : array-like
            Function input values.  If one-dimensional, must be a column
            vector with shape `(n, 1)`.
        point : pymc3.model.Point
            A specific point to condition on.
        diag : bool
            If `True`, return the diagonal instead of the full covariance
            matrix.  Default is `False`.
        pred_noise : bool
            Whether or not observation noise is included in the conditional.
            Default is `False`.
        given : dict
            Same as `conditional` method.
        """
        if given is None:
            given = {}

        mu, cov = self.predictt(Xnew, diag, pred_noise, given)
        return draw_values([mu, cov], point=point)
    def __init__(self, *args, **kwargs):
        add_citations_to_model(self.__citations__, kwargs.get("model", None))

        # Make sure that the shape is compatible
        shape = kwargs.get("shape", 2)
        try:
            if list(shape)[0] != 2:
                raise ValueError("the first dimension should be exactly 2")
        except TypeError:
            if shape != 2:
                raise ValueError("the first dimension should be exactly 2")

        self.min_radius = kwargs.pop("min_radius", 0)
        self.max_radius = kwargs.pop("max_radius", 1)
        transform = tr.radius_impact(self.min_radius, self.max_radius)
        kwargs["shape"] = shape
        kwargs["transform"] = transform

        super(RadiusImpact, self).__init__(*args, **kwargs)

        # Work out some reasonable starting values for the parameters
        default = np.zeros(shape)
        mn, mx = draw_values([self.min_radius - 0., self.max_radius - 0.])
        default[0] = 0.5 * (mn + mx)
        default[1] = 0.5
        self._default = default
    def random(self, point=None, size=None):
        """Random sample, used in `pm.sample_posterior_predictive()`."""

        a_const, a_init, a_ar, a_packed_chol, a_chol, a_cov = draw_values(
            [
                self.t_const,
                self.t_init,
                self.t_ar,
                self.packed_chol,
                self.chol,
                self.cov,
            ],
            point=point,
            size=size,
        )
        T = int(self.shape[0])

        def gen_1():
            my_varx_gen = VARXGenerator(
                endog=self.n_endog,
                lag_endog=self.n_lag_endog,
                coef_ar=a_ar,
                coef_covariance=a_cov,
                coef_const=a_const,
                # This seems correct - order is 'oldest' to 'newest':
                coef_initial_values=a_init,
                # Ignore nonstationary since these are samples:
                check_kwargs=dict(action_nonstationary="ignore"),
            )
            srs = my_varx_gen.generate(T)["output"].values
            return srs

        # TODO: what to do with `size`?
        random_samples = gen_1()
        return random_samples
Exemple #6
0
 def random(self, point=None, size=None):
     (ror, ) = draw_values([self.ror], point=point, size=size)
     return generate_samples(
         self._random,
         dist_shape=self.shape,
         broadcast_shape=self.shape,
         size=size,
     )
 def random(self, point=None, size=None):
     mn, mx = draw_values([self.min_radius - 0., self.max_radius - 0.],
                          point=point)
     return generate_samples(self._random,
                             mn,
                             mx,
                             dist_shape=self.shape,
                             broadcast_shape=self.shape,
                             size=size)
Exemple #8
0
    def _draw_from_parents(self, parent, point=None, size=None):
        """
        A wrapper over PyMC3's distribution.draw_values() method that
        generalizes drawing random samples from the parents of this
        distribution to cases where the parents can be PyMC3 RVs or python
        vars (ints, floats, numpy arrays, etc).

        :param parent: parent RV (or python var)

        :param point: value of this RV at which to draw samples.
                      (Recommendation: Use default None)

        :param size: number of samples requested (defaults to 1)

        :return: a set of random samples from each parent (RV or python var)
        of this RV
        """

        if size is None:
            size = 1

        # static or dynamic?
        if self._is_dynamic_parent(parent):
            p = parent["node"]
        elif self._is_static_parent(parent):
            p = parent

        # if this is just the previous timeslice value of this node,
        # then fill in with self.testval (which is also the initial value)
        # and tile to get the correct dimension
        if self._is_me(parent):
            val = self.testval[np.newaxis, :]
            val = np.repeat(val, size, axis=0)

        # if this is a numpy array, return the array broadcasted to one
        # dimension higher. The new dimension is now the 0th dimension and is
        # the number of samples requested, i.e., size
        elif isinstance(p, np.ndarray):
            val = p[np.newaxis, :]
            val = np.repeat(val, size, axis=0)

        # for all other cases, uses pymc3's internal draw_values API
        else:
            val = draw_values([p], point=point, size=size)[0]

        return val
Exemple #9
0
    def forward_val(self, x, point=None):
        p = x[0]
        b = x[1]
        pl, Ar, dr = draw_values([self.min_radius-0., self.Ar-0., self.dr-0.],
                                 point=point)

        m = b <= 1
        r = np.empty_like(x)
        r[0, m] = (b[m] / (1 + pl) - 1) * (1 - Ar) + 1
        r[1, m] = (p[m] - pl) / dr

        arg = p[~m] - b[~m] - dr + 1
        q1 = (arg / dr) ** 2
        q2 = (pl - b[~m] + 1) / arg
        r[0, ~m] = q1 * Ar
        r[1, ~m] = q2

        return np.log(r) - np.log(1 - r)
Exemple #10
0
    def __init__(self, vars, proposal="uniform", order="random", model=None):

        model = pm.modelcontext(model)
        vars = pm.inputvars(vars)

        dimcats = []
        # The above variable is a list of pairs (aggregate dimension, number
        # of categories). For example, if vars = [x, y] with x being a 2-D
        # variable with M categories and y being a 3-D variable with N
        # categories, we will have dimcats = [(0, M), (1, M), (2, N), (3, N), (4, N)].
        for v in vars:
            distr = getattr(v.distribution, "parent_dist", v.distribution)
            if isinstance(distr, pm.Categorical):
                k = draw_values([distr.k])[0]
            elif isinstance(distr, pm.Bernoulli) or (v.dtype in pm.bool_types):
                k = 2
            else:
                raise ValueError(
                    "All variables must be categorical or binary" +
                    "for CategoricalGibbsMetropolis")
            start = len(dimcats)
            dimcats += [(dim, k) for dim in range(start, start + v.dsize)]

        if order == "random":
            self.shuffle_dims = True
            self.dimcats = dimcats
        else:
            if sorted(order) != list(range(len(dimcats))):
                raise ValueError("Argument 'order' has to be a permutation")
            self.shuffle_dims = False
            self.dimcats = [dimcats[j] for j in order]

        if proposal == "uniform":
            self.astep = self.astep_unif
        elif proposal == "proportional":
            # Use the optimized "Metropolized Gibbs Sampler" described in Liu96.
            self.astep = self.astep_prop
        else:
            raise ValueError(
                "Argument 'proposal' should either be 'uniform' or 'proportional'"
            )

        super().__init__(vars, [model.fastlogp])
Exemple #11
0
    def random(self, point=None, size=None):
        """
        Draw random values from HyperGeometric distribution.

        Parameters
        ----------
        point : dict, optional
            Dict of variable values on which random values are to be
            conditioned (uses default point if not specified).
        size : int, optional
            Desired size of random sample (returns one sample if not
            specified).

        Returns
        -------
        array
        """
        N, n, k = draw_values([self.N, self.n, self.k], point=point, size=size)
        return generate_samples(np.random.hypergeometric,
                                N,
                                n,
                                k,
                                dist_shape=self.shape,
                                size=size)
Exemple #12
0
    def sample(self,
               size=1,
               generate_linear=False,
               return_logprobs=False,
               random_state=None,
               dtype=None,
               **kwargs):
        """
        Generate random samples from the prior.

        .. note::

            Right now, generating samples with the prior values is slow (i.e.
            with ``return_logprobs=True``) because of pymc3 issues (see
            discussion here:
            https://discourse.pymc.io/t/draw-values-speed-scaling-with-transformed-variables/4076).
            This will hopefully be resolved in the future...

        Parameters
        ----------
        size : int (optional)
            The number of samples to generate.
        generate_linear : bool (optional)
            Also generate samples in the linear parameters.
        return_logprobs : bool (optional)
            Generate the log-prior probability at the position of each sample.
        **kwargs
            Additional keyword arguments are passed to the
            `~thejoker.JokerSamples` initializer.

        Returns
        -------
        samples : `thejoker.Jokersamples`
            The random samples.

        """
        from theano.gof.fg import MissingInputError
        from pymc3.distributions import draw_values
        import exoplanet.units as xu

        if dtype is None:
            dtype = np.float64

        sub_pars = {
            k: p
            for k, p in self.pars.items()
            if k in self._nonlinear_equiv_units or (
                (k in self._linear_equiv_units
                 or k in self._v0_offsets_equiv_units) and generate_linear)
        }

        if generate_linear:
            par_names = self.par_names
        else:
            par_names = list(self._nonlinear_equiv_units.keys())

        pars_list = list(sub_pars.values())

        # MAJOR HACK RELATED TO UPSTREAM ISSUES WITH pymc3:
        init_shapes = dict()
        for par in pars_list:
            if hasattr(par, 'distribution'):
                init_shapes[par.name] = par.distribution.shape
                par.distribution.shape = (size, )

        with random_state_context(random_state):
            samples_values = draw_values(pars_list)
        raw_samples = {
            p.name: samples.astype(dtype)
            for p, samples in zip(pars_list, samples_values)
        }

        if return_logprobs:
            logp = []
            for par in pars_list:
                try:
                    _logp = par.distribution.logp(raw_samples[par.name]).eval()
                except AttributeError:
                    logger.warning("Cannot auto-compute log-prior value for "
                                   f"parameter {par} because it is defined "
                                   "as a transformation from another "
                                   "variable.")
                    continue
                except MissingInputError:
                    logger.warning("Cannot auto-compute log-prior value for "
                                   f"parameter {par} because it depends on "
                                   "other variables.")
                    continue

                logp.append(_logp)
            log_prior = np.sum(logp, axis=0)

        # CONTINUED MAJOR HACK RELATED TO UPSTREAM ISSUES WITH pymc3:
        for par in pars_list:
            if hasattr(par, 'distribution'):
                par.distribution.shape = init_shapes[par.name]

        # Apply units if they are specified:
        prior_samples = JokerSamples(poly_trend=self.poly_trend,
                                     n_offsets=self.n_offsets,
                                     **kwargs)
        for name in par_names:
            p = sub_pars[name]
            unit = getattr(p, xu.UNIT_ATTR_NAME, u.one)

            if p.name not in prior_samples._valid_units.keys():
                continue

            prior_samples[p.name] = np.atleast_1d(raw_samples[p.name]) * unit

        if return_logprobs:
            prior_samples['ln_prior'] = log_prior

        # TODO: right now, elsewhere, we assume the log_prior is a single value
        # for each sample (i.e. the total prior value). In principle, we could
        # store all of the individual log-prior values (for each parameter),
        # like here:
        # log_prior = {k: np.atleast_1d(v)
        #              for k, v in log_prior.items()}
        # log_prior = Table(log_prior)[par_names]

        return prior_samples
Exemple #13
0
 def random(self, point=None, size=1):
     probs, = draw_values([self.probst], point=point, size=size)
     sample = multidim_choice(probs=probs, size=size)
     if size == 1:
         sample = sample[0]
     return sample
Exemple #14
0
 def forward_val(self, x, point=None):
     (opror, ) = draw_values([self.one_plus_ror - 0.0], point=point)
     return super(ImpactParameterTransform, self).forward_val(x / opror,
                                                              point=point)
 def random(self, point=None, size=None, repeat=None):
     mu = draw_values([self.mu], point=point)
     return generate_samples(self.zpt_cdf,
                             mu,
                             dist_shape=self.shape,
                             size=size)