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
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)
# Plotting the Rt values
import matplotlib.pyplot as plt
plt.step(np.arange(len(sim_data)), sim_data, where="post")
plt.xlabel("Days")
plt.ylabel("Rt")
plt.title("Simulated Rt values")
# Adding bands to mark weeks
for i in range(0, 30, 7):
plt.axvline(i, color="black", linestyle="--", alpha=0.5)
plt.show()
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(
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)
# Plotting the effect values
import matplotlib.pyplot as plt
plt.step(np.arange(len(sim_data)), sim_data, where="post")
plt.xlabel("Days")
plt.ylabel("Effect size")
plt.title("Simulated Day of Week Effect values")
# Adding bands to mark weeks
for i in range(0, 30, 7):
plt.axvline(i, color="black", linestyle="--", alpha=0.5)
plt.show()