# tfp.sts.LinearRegression

Formal representation of a linear regression from provided covariates.

Inherits From: `StructuralTimeSeries`

### Used in the notebooks

Used in the tutorials

This model defines a time series given by a linear combination of covariate time series provided in a design matrix:

``````observed_time_series = matmul(design_matrix, weights)
``````

The design matrix has shape `[num_timesteps, num_features]`. The weights are treated as an unknown random variable of size `[num_features]` (both components also support batch shape), and are integrated over using the same approximate inference tools as other model parameters, i.e., generally HMC or variational inference.

This component does not itself include observation noise; it defines a deterministic distribution with mass at the point `matmul(design_matrix, weights)`. In practice, it should be combined with observation noise from another component such as `tfp.sts.Sum`, as demonstrated below.

#### Examples

Given `series1`, `series2` as `Tensors` each of shape `[num_timesteps]` representing covariate time series, we create a regression model that conditions on these covariates:

``````regression = tfp.sts.LinearRegression(
design_matrix=tf.stack([series1, series2], axis=-1),
weights_prior=tfd.Normal(loc=0., scale=1.))
``````

Here we've also demonstrated specifying a custom prior, using an informative `Normal(0., 1.)` prior instead of the default weakly-informative prior.

As a more advanced application, we might use the design matrix to encode holiday effects. For example, suppose we are modeling data from the month of December. We can combine day-of-week seasonality with special effects for Christmas Eve (Dec 24), Christmas (Dec 25), and New Year's Eve (Dec 31), by constructing a design matrix with indicators for those dates.

``````holiday_indicators = np.zeros([31, 3])
holiday_indicators[23, 0] = 1  # Christmas Eve
holiday_indicators[24, 1] = 1  # Christmas Day
holiday_indicators[30, 2] = 1  # New Year's Eve

holidays = tfp.sts.LinearRegression(design_matrix=holiday_indicators,
name='holidays')
day_of_week = tfp.sts.Seasonal(num_seasons=7,
observed_time_series=observed_time_series,
name='day_of_week')
model = tfp.sts.Sum(components=[holidays, seasonal],
observed_time_series=observed_time_series)
``````

Note that the `Sum` component in the above model also incorporates observation noise, with prior scale heuristically inferred from `observed_time_series`.

In these examples, we've used a single design matrix, but batching is also supported. If the design matrix has batch shape, the default behavior constructs weights with matching batch shape, which will fit a separate regression for each design matrix. This can be overridden by passing an explicit weights prior with appropriate batch shape. For example, if each design matrix in a batch contains features with the same semantics (e.g., if they represent per-group or per-observation covariates), we might choose to share statistical strength by fitting a single weight vector that broadcasts across all design matrices:

``````design_matrix = get_batch_of_inputs()
design_matrix.shape  # => concat([batch_shape, [num_timesteps, num_features]])

# Construct a prior with batch shape `[]` and event shape `[num_features]`,
# so that it describes a single vector of weights.
weights_prior = tfd.Independent(
tfd.StudentT(df=5,
loc=tf.zeros([num_features]),
scale=tf.ones([num_features])),
reinterpreted_batch_ndims=1)
linear_regression = LinearRegression(design_matrix=design_matrix,
weights_prior=weights_prior)
``````

`design_matrix` float `Tensor` of shape ```concat([batch_shape, [num_timesteps, num_features]])```. This may also optionally be an instance of `tf.linalg.LinearOperator`.
`weights_prior` `tfd.Distribution` representing a prior over the regression weights. Must have event shape `[num_features]` and batch shape broadcastable to the design matrix's `batch_shape`. If `None`, defaults to `Sample(StudentT(df=5, loc=0., scale=10.), num_features])`, a weakly-informative prior loosely inspired by the Stan prior choice recommendations. Default value: `None`.
`name` the name of this model component. Default value: 'LinearRegression'.

`batch_shape` Static batch shape of models represented by this component.
`design_matrix` LinearOperator representing the design matrix.
`init_parameters` Parameters used to instantiate this `StructuralTimeSeries`.
`latent_size` Python `int` dimensionality of the latent space in this model.
`name` Name of this model component.
`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)`.

### `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. If not specified (either directly or by passing an `observed_time_series`), defaults to a one-to-one correspondence between trajectories and parameter settings (implicitly `trajectories_shape=()`). Default value: `None`.
`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

# Sample and plot 100 trajectories from the prior.
model = tfp.sts.LocalLinearTrendModel()
prior_samples = model.joint_distribution().sample()
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,
num_steps=200)
parameter_samples = surrogate_posterior.sample(50)

# No U-Turn Sampler.
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. (deprecated)

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 `NaN`s 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. (deprecated)

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 `Tensor`s, 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.

[{ "type": "thumb-down", "id": "missingTheInformationINeed", "label":"Missing the information I need" },{ "type": "thumb-down", "id": "tooComplicatedTooManySteps", "label":"Too complicated / too many steps" },{ "type": "thumb-down", "id": "outOfDate", "label":"Out of date" },{ "type": "thumb-down", "id": "samplesCodeIssue", "label":"Samples / code issue" },{ "type": "thumb-down", "id": "otherDown", "label":"Other" }]
[{ "type": "thumb-up", "id": "easyToUnderstand", "label":"Easy to understand" },{ "type": "thumb-up", "id": "solvedMyProblem", "label":"Solved my problem" },{ "type": "thumb-up", "id": "otherUp", "label":"Other" }]