Periodic effects and broadcasting
A common practice in time series forecasting is featuring periodic
effects such as day of the week or weekend effects. The
arrayutils.PeriodicBroadcaster class provides this functionality. This
tutorial shows how to use this to model both repeating elements of a
sequence and repeating a sequence as a whole (tiling).
Repeated units
The RtPeriodicDiff and RtWeeklyDiff classes use
PeriodicBroadcaster to repeat each vector element for \(\mathcal{R}(t)\)
values held constant within a period.
import jax.numpy as jnp
import numpy as np
import numpyro
import pandas as pd
import plotnine as p9
from _tutorial_theme import theme_tutorial
from pyrenew import process, deterministic
# The random process for Rt
rt_proc = process.RtWeeklyDiffARProcess(
name="rt_weekly_diff",
offset=0,
log_rt_rv=deterministic.DeterministicVariable(
name="log_rt", value=jnp.array([0.1, 0.2])
),
autoreg_rv=deterministic.DeterministicVariable(
name="autoreg", value=jnp.array([0.7])
),
periodic_diff_sd_rv=deterministic.DeterministicVariable(
name="periodic_diff_sd", value=jnp.array([0.1])
),
)
with numpyro.handlers.seed(rng_seed=20):
sim_data = rt_proc(duration=30)
rt_df = pd.DataFrame(
{"day": np.arange(len(sim_data)), "rt": np.array(sim_data)}
)
week_breaks = pd.DataFrame({"x": np.arange(0, 30, 7)})
(
p9.ggplot(rt_df, p9.aes(x="day", y="rt"))
+ p9.geom_step(color="steelblue", size=1)
+ p9.geom_vline(
p9.aes(xintercept="x"), data=week_breaks, linetype="dashed", alpha=0.5
)
+ p9.labs(x="Days", y="Rt", title="Simulated Rt values")
+ theme_tutorial
)

The implementation of the RtWeeklyDiffARProcess (which is an instance
of RtPeriodicDiffARProcess), uses repeat_until_n to repeat values:
repeat_until_n(..., period_size=7). The RtWeeklyDiff class is a
particular case of RtPeriodicDiff with a period size of seven.
Repeated sequences (tiling)
By specifying broadcast_type = "tile", the PeriodicBroadcaster
repeats the sequence as a whole. The DayOfWeekEffect class is a
particular case of PeriodicEffect with a period size of seven. We
sample from a scaled Dirchlet distribution such that the sum of the
samples is 7:
import numpyro.distributions as dist
from pyrenew import transformation, randomvariable
# Building the transformed prior: Dirichlet * 7
mysimplex = dist.TransformedDistribution(
dist.Dirichlet(concentration=jnp.ones(7)),
transformation.AffineTransform(loc=0, scale=7.0),
)
# Constructing the day of week effect
dayofweek = process.DayOfWeekEffect(
name="dayofweek",
offset=0,
quantity_to_broadcast=randomvariable.DistributionalVariable(
name="simp", distribution=mysimplex
),
)
We use the sample method to generate samples from the day of week
effect:
with numpyro.handlers.seed(rng_seed=20):
sim_data = dayofweek(duration=30)
dow_df = pd.DataFrame(
{"day": np.arange(len(sim_data)), "effect": np.array(sim_data)}
)
week_breaks = pd.DataFrame({"x": np.arange(0, 30, 7)})
(
p9.ggplot(dow_df, p9.aes(x="day", y="effect"))
+ p9.geom_step(color="steelblue", size=1)
+ p9.geom_vline(
p9.aes(xintercept="x"), data=week_breaks, linetype="dashed", alpha=0.5
)
+ p9.labs(
x="Days", y="Effect size", title="Simulated Day of Week Effect values"
)
+ theme_tutorial
)
