tfp.substrates.jax.sts.Seasonal

Formal representation of a seasonal effect model.

Inherits From: StructuralTimeSeries

Used in the notebooks

Used in the tutorials

A seasonal effect model posits a fixed set of recurring, discrete 'seasons', each of which is active for a fixed number of timesteps and, while active, contributes a different effect to the time series. These are generally not meteorological seasons, but represent regular recurring patterns such as hour-of-day or day-of-week effects. Each season lasts for a fixed number of timesteps. The effect of each season drifts from one occurrence to the next following a Gaussian random walk:

effects[season, occurrence[i]] = (
  effects[season, occurrence[i-1]] + Normal(loc=0., scale=drift_scale))

The drift_scale parameter governs the standard deviation of the random walk; for example, in a day-of-week model it governs the change in effect from this Monday to next Monday.

Examples

A seasonal effect model representing day-of-week seasonality on hourly data:

day_of_week = tfp.sts.Seasonal(num_seasons=7,
                               num_steps_per_season=24,
                               observed_time_series=y,
                               name='day_of_week')

A seasonal effect model representing month-of-year seasonality on daily data, with explicit priors:

month_of_year = tfp.sts.Seasonal(
  num_seasons=12,
  num_steps_per_season=[31, 28, 31, 30, 30, 31, 31, 31, 30, 31, 30, 31],
  drift_scale_prior=tfd.LogNormal(loc=-1., scale=0.1),
  initial_effect_prior=tfd.Normal(loc=0., scale=5.),
  name='month_of_year')

Note that this version works over time periods not involving a leap year. A general implementation of month-of-year seasonality would require additional logic:

num_days_per_month = np.array(
  [[31, 28, 31, 30, 30, 31, 31, 31, 30, 31, 30, 31],
   [31, 29, 31, 30, 30, 31, 31, 31, 30, 31, 30, 31],  # year with leap day
   [31, 28, 31, 30, 30, 31, 31, 31, 30, 31, 30, 31],
   [31, 28, 31, 30, 30, 31, 31, 31, 30, 31, 30, 31]])

month_of_year = tfp.sts.Seasonal(
  num_seasons=12,
  num_steps_per_season=num_days_per_month,
  drift_scale_prior=tfd.LogNormal(loc=-1., scale=0.1),
  initial_effect_prior=tfd.Normal(loc=0., scale=5.),
  name='month_of_year')

A model representing both day-of-week and hour-of-day seasonality, on hourly data:

day_of_week = tfp.sts.Seasonal(num_seasons=7,
                               num_steps_per_season=24,
                               observed_time_series=y,
                               name='day_of_week')
hour_of_day = tfp.sts.Seasonal(num_seasons=24,
                               num_steps_per_season=1,
                               observed_time_series=y,
                               name='hour_of_day')
model = tfp.sts.Sum(components=[day_of_week, hour_of_day],
                    observed_time_series=y)

num_seasons Scalar Python int number of seasons.
num_steps_per_season Python int number of steps in each season. This may be either a scalar (shape []), in which case all seasons have the same length, or a NumPy array of shape [num_seasons], in which seasons have different length, but remain constant around different cycles, or a NumPy array of shape [num_cycles, num_seasons], in which num_steps_per_season for each season also varies in different cycle (e.g., a 4 years cycle with leap day). Default value: 1.
allow_drift optional Python bool specifying whether the seasonal effects can drift over time. Setting this to False removes the drift_scale parameter from the model. This is mathematically equivalent to drift_scale_prior = tfd.Deterministic(0.), but removing drift directly is preferred because it avoids the use of a degenerate prior. Default value: True.
drift_scale_prior optional tfd.Distribution instance specifying a prior on the drift_scale parameter. If None, a heuristic default prior is constructed based on the provided observed_time_series. Default value: None.
initial_effect_prior optional tfd.Distribution instance specifying a normal prior on the initial effect of each season. This may be either a scalar tfd.Normal prior, in which case it applies independently to every season, or it may be multivariate normal (e.g., tfd.MultivariateNormalDiag) with event shape [num_seasons], in which case it specifies a joint prior across all seasons. If None, a heuristic default prior is constructed based on the provided observed_time_series. Default value: None.
constrain_mean_effect_to_zero if True, use a model parameterization that constrains the mean effect across all seasons to be zero. This constraint is generally helpful in identifying the contributions of different model components and can lead to more interpretable posterior decompositions. It may be undesirable if you plan to directly examine the latent space of the underlying state space model. Default value: True.
observed_time_series optional float Tensor of shape batch_shape + [T, 1] (omitting the trailing unit dimension is also supported when T > 1), specifying an observed time series. Any NaNs are interpreted as missing observations; missingness may be also be explicitly specified by passing a tfp.sts.MaskedTimeSeries instance. Any priors not explicitly set will be given default values according to the scale of the observed time series (or batch of time series). Default value: None.
name the name of this model component. Default value: 'Seasonal'.

allow_drift Whether the seasonal effects are allowed to drift over time.
batch_shape Static batch shape of models represented by this component.
constrain_mean_effect_to_zero Whether to constrain the mean effect to zero.
init_parameters Parameters used to instantiate this StructuralTimeSeries.
initial_state_prior Prior distribution on the initial latent state (level and scale).
latent_size Python int dimensionality of the latent space in this model.
name Name of this model component.
num_seasons Number of seasons.
num_steps_per_season Number of steps per season.
parameters List of Parameter(name, prior, bijector) namedtuples for this model.

Methods

batch_shape_tensor

View source

Runtime batch shape of models represented by this component.

Returns
batch_shape int Tensor giving the broadcast batch shape of all model parameters. This should match the batch shape of derived state space models, i.e., self.make_state_space_model(...).batch_shape_tensor().

copy

View source

Creates a deep copy.

Args
**override_parameters_kwargs String/value dictionary of initialization arguments to override with new values.

Returns
copy A new instance of type(self) initialized from the union of self.init_parameters and override_parameters_kwargs, i.e., dict(self.init_parameters, **override_parameters_kwargs).

experimental_resample_drift_scale

View source

Returns a posterior sample of drift scale given the latents and prior.

This is experimental, and compatibility may be broken in the future.

Args
latents A value convertible to a tensor of shape [batch shape, timeseries length, latent size].
sample_shape Shape of the sample.
seed The seed to sample with.

get_parameter

View source

Returns the parameter with the given name, or a KeyError.

joint_distribution

View source

Constructs the joint distribution over parameters and observed values.

Args
observed_time_series Optional observed time series to model, as a Tensor or tfp.sts.MaskedTimeSeries instance having shape concat([batch_shape, trajectories_shape, num_timesteps, 1]). If an observed time series is provided, the num_timesteps, trajectories_shape, and mask arguments are ignored, and an unnormalized (pinned) distribution over parameter values is returned. Default value: None.
num_timesteps scalar int Tensor number of timesteps to model. This must be specified either directly or by passing an observed_time_series. Default value: 0.
trajectories_shape int Tensor shape of sampled trajectories for each set of parameter values. Ignored if an observed_time_series is passed. Default value: ().
initial_step Optional scalar int Tensor specifying the starting timestep. Default value: 0.
mask Optional bool Tensor having shape concat([batch_shape, trajectories_shape, num_timesteps]), in which True entries indicate that the series value at the corresponding step is missing and should be ignored. This argument should be passed only if observed_time_series is not specified or does not already contain a missingness mask; it is an error to pass both this argument and an observed_time_series value containing a missingness mask. Default value: None.
experimental_parallelize If True, use parallel message passing algorithms from tfp.experimental.parallel_filter to perform time series operations in O(log num_timesteps) sequential steps. The overall FLOP and memory cost may be larger than for the sequential implementations by a constant factor. Default value: False.

Returns
joint_distribution joint distribution of model parameters and observed trajectories. If no observed_time_series was specified, this is an instance of tfd.JointDistributionNamedAutoBatched with a random variable for each model parameter (with names and order matching self.parameters), plus a final random variable observed_time_series representing a trajectory(ies) conditioned on the parameters. If observed_time_series was specified, the return value is given by joint_distribution.experimental_pin( observed_time_series=observed_time_series) where joint_distribution is as just described, so it defines an unnormalized posterior distribution over the parameters.

Example:

The joint distribution can generate prior samples of parameters and trajectories:

from matplotlib import pylab as plt
import tensorflow_probability as tfp; tfp = tfp.substrates.jax

# Sample and plot 100 trajectories from the prior.
model = tfp.sts.LocalLinearTrend()
prior_samples = model.joint_distribution(num_timesteps=200).sample([100])
plt.plot(
  tf.linalg.matrix_transpose(prior_samples['observed_time_series'][..., 0]))

It also integrates with TFP inference APIs, providing a more flexible alternative to the STS-specific fitting utilities.

jd = model.joint_distribution(observed_time_series)

# Variational inference.
surrogate_posterior = (
  tfp.experimental.vi.build_factored_surrogate_posterior(
    event_shape=jd.event_shape,
    bijector=jd.experimental_default_event_space_bijector()))
losses = tfp.vi.fit_surrogate_posterior(
  target_log_prob_fn=jd.unnormalized_log_prob,
  surrogate_posterior=surrogate_posterior,
  optimizer=tf.optimizers.Adam(0.1),
  num_steps=200)
parameter_samples = surrogate_posterior.sample(50)

# No U-Turn Sampler.
samples, kernel_results = tfp.experimental.mcmc.windowed_adaptive_nuts(
  n_draws=500, joint_dist=dist)

joint_log_prob

View source

Build the joint density log p(params) + log p(y|params) as a callable.

Args
observed_time_series Observed Tensor trajectories of shape sample_shape + batch_shape + [num_timesteps, 1] (the trailing 1 dimension is optional if num_timesteps > 1), where batch_shape should match self.batch_shape (the broadcast batch shape of all priors on parameters for this structural time series model). Any NaNs are interpreted as missing observations; missingness may be also be explicitly specified by passing a tfp.sts.MaskedTimeSeries instance.

Returns
log_joint_fn A function taking a Tensor argument for each model parameter, in canonical order, and returning a Tensor log probability of shape batch_shape. Note that, unlike tfp.Distributions log_prob methods, the log_joint sums over the sample_shape from y, so that sample_shape does not appear in the output log_prob. This corresponds to viewing multiple samples in y as iid observations from a single model, which is typically the desired behavior for parameter inference.

make_state_space_model

View source

Instantiate this model as a Distribution over specified num_timesteps.

Args
num_timesteps Python int number of timesteps to model.
param_vals a list of Tensor parameter values in order corresponding to self.parameters, or a dict mapping from parameter names to values.
initial_state_prior an optional Distribution instance overriding the default prior on the model's initial state. This is used in forecasting ("today's prior is yesterday's posterior").
initial_step optional int specifying the initial timestep to model. This is relevant when the model contains time-varying components, e.g., holidays or seasonality.
**linear_gaussian_ssm_kwargs Optional additional keyword arguments to to the base tfd.LinearGaussianStateSpaceModel constructor.

Returns
dist a LinearGaussianStateSpaceModel Distribution object.

prior_sample

View source

Sample from the joint prior over model parameters and trajectories.

Args
num_timesteps Scalar int Tensor number of timesteps to model.
initial_step Optional scalar int Tensor specifying the starting timestep. Default value: 0.
params_sample_shape Number of possible worlds to sample iid from the parameter prior, or more generally, Tensor int shape to fill with iid samples. Default value: [] (i.e., draw a single sample and don't expand the shape).
trajectories_sample_shape For each sampled set of parameters, number of trajectories to sample, or more generally, Tensor int shape to fill with iid samples. Default value: [] (i.e., draw a single sample and don't expand the shape).
seed PRNG seed; see tfp.random.sanitize_seed for details. Default value: None.

Returns
trajectories float Tensor of shape trajectories_sample_shape + params_sample_shape + [num_timesteps, 1] containing all sampled trajectories.
param_samples list of sampled parameter value Tensors, in order corresponding to self.parameters, each of shape params_sample_shape + prior.batch_shape + prior.event_shape.

__add__

View source

Models the sum of the series from the two components.