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