Updating occurs after observing a new value, $y_t$. The update function accepts $y_t$ and the predictors $X_t$. It will update the state vector from $\theta_t$ into $\theta_{t+1}$, producing the new mean $a_{t+1}$ and variance matrix $R_{t+1}$. In a normal DLM, the updating also impacts the mean of the observation variance, $s_{t+1}$. The coefficients can be accessed with mod.get_coef
, or more directly as mod.a
, mod.R
, and for a normal DLM, mod.s
.
To give the more formal Bayesian interpretation of these steps:
- At time $t$, we know the prior moments of the state vector $\theta_t | \mathcal{D_t} \sim [a_t, R_t]$, where $\mathcal{D_t}$ is all of the observations up to time $t$.
- We then observe $y_t$, and incorporate the new information to give the posterior: $\theta_t | \mathcal{D_t}, y_t \sim [m_t, C_t]$.
- Finally, we discount the old information, to give us our new priors for the next time step: $\theta_{t+1} | \mathcal{D_{t+1}} \sim [a_{t+1}, R_{t+1}]$.
If you are interested in the posterior moments of $\theta_t | \mathcal{D_t}, y_t$ before the discounting is applied, then you can access mod.m
and mod.C
, although these are rarely used.
Again, these functions do not need to be accessed independently from a model. Every model in PyBATS has a mod.update(y, X)
method, which will call the appropriate update function.
This update method works for Poisson and Bernoulli DGLMs. Below are very simple tests which:
- Manually define a DGLM with an intercept and 2 regression predictors
- Define a new $y_t, X_t$
- Update the model, given $y_t, X_t$
- Check that the posterior mean $a_t$ and variance $R_t$ of the state vector is correct
import numpy as np
from pybats.dglm import dlm, pois_dglm, bern_dglm, bin_dglm
from pybats.analysis import analysis
a0 = np.array([1, 1, 1])
R0 = np.eye(3)
mod_p = pois_dglm(a0, R0, ntrend=1, nregn=2, deltrend=1, delregn=.9)
mod_bern = bern_dglm(a0, R0, ntrend=1, nregn=2, deltrend=1, delregn=.9)
# New data:
y = 5
X = np.array([1,2])
# Test the Poisson DGLM
mod_p.update(y=y, X=X)
ans = np.array([[0.59974735],
[0.59974735],
[0.1994947 ]])
assert (np.equal(np.round(ans, 5), np.round(mod_p.a, 5)).all())
ans = np.array([-0.16107008, 0.93214436])
assert (np.equal(np.round(ans, 5), np.round(mod_p.R[0:2, 1], 5)).all())
# Test the Bernoulli DGLM
mod_bern.update(y=1, X=X)
ans = np.array([[1.02626224],
[1.02626224],
[1.05252447]])
assert (np.equal(np.round(ans, 5), np.round(mod_bern.a, 5)).all())
ans = np.array([-1.00331466e-04, 1.11099963])
assert (np.equal(np.round(ans, 5), np.round(mod_bern.R[0:2, 1], 5)).all())
This update method works for normal DLMs. Here is a similar updating test, calling the method as mod_n.update
:
mod_n = dlm(a0, R0, ntrend=1, nregn=2, deltrend=1, delregn=.9)
# Test the normal DLM
mod_n.update(y = y, X=X)
ans = np.array([[1.14285714],
[1.14285714],
[1.28571429]])
assert(np.equal(np.round(ans, 5), np.round(mod_n.a, 5)).all())
ans = np.array([-0.08163265, 0.54421769])
assert(np.equal(np.round(ans, 5), np.round(mod_n.R[0:2,1], 5)).all())
This update method works for binomial DGLMs. Here is a similar updating test, calling the method as mod_b.update
. Note that for a binomial DGLM, we must specify the number of trials, $n_t$.
mod_b = bin_dglm(a0, R0, ntrend=1, nregn=2, deltrend=1, delregn=.9)
# New data - the number of trials
n = 10
# Test the Binomial DGLM
mod_b.update(y=y, X=X, n=n)
ans = np.array([[ 0.46543905],
[ 0.46543905],
[-0.0691219 ]])
assert (np.equal(np.round(ans, 5), np.round(mod_b.a, 5)).all())
ans = np.array([-0.15854342, 0.93495175])
assert (np.equal(np.round(ans, 5), np.round(mod_b.R[0:2, 1], 5)).all())