def _verify_initial_state_prior(self, initial_state_prior, xtx, xty, sdy): if initial_state_prior is None: try: beta_hat = np.linalg.solve(xtx, xty) if not np.all(np.finite(beta_hat)): raise Exception("Least squares initializer failed.") self._initial_state_prior = R.MvnPrior( beta_hat, sdy * sdy * np.linalg.inv(xtx)) except Exception: self._initial_state_prior = R.MvnPrior( np.zeros(self.xdim), sdy * sdy * np.diag(1.0 / np.diagonal(xtx))) elif isinstance(initial_state_prior, R.NormalPrior): mean = np.full(initial_state_prior.mean, self.xdim) var = np.full(initial_state_prior.sd**2, self.xdim) self._initial_state_prior = R.MvnPrior(mean, np.diag(var)) elif isinstance(initial_state_prior, list) and all( [isinstance(x, R.NormalPrior) for x in initial_state_prior]): mean = np.array([x.mean for x in initial_state_prior]) var = np.array([x.sd**2 for x in initial_state_prior]) self._initial_state_prior = R.MvnPrior(mean, np.diag(var)) else: if not isinstance(initial_state_prior, R.MvnPrior): raise Exception("Unrecognized type for initial_state_prior.") self._initial_state_prior = initial_state_prior return self._initial_state_prior
def _default_initial_state_prior(self, sdy): """ The default prior to use for the initial state vector. """ dim = self.nseasons - 1 return R.MvnPrior(np.zeros(dim), np.diag(np.full(dim, float(sdy))))
def _validate_initial_distribution(self, initial_state_prior, sdy): if initial_state_prior is None: dim = self.state_dimension initial_state_prior = R.MvnPrior(np.zeros(dim), np.eye(dim) * sdy) if not isinstance(initial_state_prior, R.MvnPrior): raise Exception("Wrong type for initial_state_prior.") if initial_state_prior.dim != self.state_dimension: raise Exception( f"Initial_state_prior dimension was {initial_state_prior.dim}." f" State dimension is {self.state_dimension}.") self._initial_state_prior = initial_state_prior
def _default_initial_state_prior(self, sdy): dim = 2 * self._nseasons mean = np.zeros(dim) variance = np.diag(np.ones(dim) * sdy) return R.MvnPrior(mean, variance)
def __init__(self, y, nseasons: int, initial_state_prior=None, level_precision_priors=None, slope_precision_priors=None, sdy: float = None): """ Args: y: The time series to be modeled. This can be "None" if 'sdy' is supplied. nseasons: The number of seasons in a cycle. initial_state_prior: An R.NormalPrior object describing the initial distribution of the state at time 0. If None then a default prior will be assumed. level_precision_priors: A list of R.SdPrior objects describing the prior distribution on the innovation standard deviations for the level portion of the model. There is one such prior for each season in the cycle. slope_precision_priors: A list of R.SdPrior objects describing the prior distribution on the innovation standard deviations for the slope portion of the model. There is one such prior for each season in the cycle. sdy: The standard deviation of the time series to be modeled. This is not needed if 'y' is supplied, or if all the prior distributions are explicity supplied. """ self._nseasons = int(nseasons) if nseasons <= 1: raise Exception("Seasonal models require at least 2 seasons.") if initial_state_prior is None: if sdy is None: sdy = self._compute_sdy(y, "initial_state_prior") initial_state_prior = self._default_initial_state_prior(sdy) if isinstance(initial_state_prior, R.NormalPrior): dim = 2 * self._nseasons mu = np.zeros(dim) sigma = initial_state_prior.sd Sigma = np.diag(np.ones(dim) * sigma**2) self._initial_state_prior = R.MvnPrior(mu, Sigma) else: self._initial_state_prior = initial_state_prior assert isinstance(self._initial_state_prior, R.MvnPrior) if level_precision_priors is None: if sdy is None: sdy = self._compute_sdy(y, "level_precision_priors") self._level_precision_priors = [ R.SdPrior(sdy / 100, .1, upper_limit=sdy) for i in range(self.nseasons) ] else: self._level_precision_priors = level_precision_priors msg = "level_precision_priors must be a list of R.SdPrior objects" if not isinstance(self._level_precision_priors, list): raise Exception(msg) for x in self._level_precision_priors: if not isinstance(x, R.SdPrior): raise Exception(msg) if slope_precision_priors is None: if sdy is None: sdy = self._compute_sdy(y, "slope_precision_priors") self._slope_precision_priors = [ R.SdPrior(sdy / 100, .1, upper_limit=sdy) for i in range(self.nseasons) ] else: self._slope_precision_priors = slope_precision_priors msg = "slope_precision_priors must be a list of R.SdPrior objects" if not isinstance(self._slope_precision_priors, list): raise Exception(msg) for x in self._slope_precision_priors: if not isinstance(x, R.SdPrior): raise Exception(msg) self._build_model() self._state_contribution = None
def __init__(self, y, nseasons: int, season_duration: int = 1, initial_state_prior=None, innovation_sd_prior: R.SdPrior = None, sdy: float = None): """ Args: y: The time series being modeled. This can be omitted if either (a) initial_state_prior and sdy and initial_y are passed, or (b) sdy and initial_y are passed. nseasons: The number of seasons in a cycle. season_duration: The number of time periods each season. See below. initial_state_prior: A multivariate normal distribution of dimension nseasons - 1. This is a distribution on the seasonal value at time 0 and on the nseasons-2 previous values. If None is passed then a default prior will be assumed. innovation_sd_prior: Prior distribution on the standard deviation of the innovation terms. If None, then a default prior will be assumed. sdy: The standard deviation of the time series being modeled. Details: """ self._nseasons = nseasons self._season_duration = season_duration if initial_state_prior is None: if sdy is None: if y is None: raise Exception("One of 'y', 'sdy', or " "'initial_state_prior' must be supplied.") sdy = np.nanstd(y, ddof=1) initial_state_prior = self._default_initial_state_prior(sdy) if isinstance(initial_state_prior, R.NormalPrior): dim = nseasons - 1 mu = initial_state_prior.mean sigma = initial_state_prior.sd initial_state_prior = R.MvnPrior( mu=np.fill(dim, mu), Sigma=np.diag(np.fill(dim, sigma * sigma))) if not isinstance(initial_state_prior, R.MvnPrior): raise Exception("Unexpected type for 'initial_state_prior'. " "Acceptable types include R.NormalPrior or " "R.MvnPrior.") self._initial_state_prior = initial_state_prior if innovation_sd_prior is None: if sdy is None: if y is None: raise Exception("One of 'y', 'sdy', or " "'innovation_sd_prior' must be supplied.") sdy = np.nanstd(y, ddof=1) innovation_sd_prior = self._default_sigma_prior(sdy) if not isinstance(innovation_sd_prior, R.SdPrior): raise Exception("Expected an R.SdPrior for innovation_sd_prior.") self._innovation_sd_prior = innovation_sd_prior self._build_model() self._state_contribution = None