# Incorrect inference of hidden states in state space models

**URL:** <https://discourse.pymc.io/t/incorrect-inference-of-hidden-states-in-state-space-models/12804>\
**Category:** v5\
**Tags:** modeling\
**Created:** [August 25, 2023, 9:01pm UTC](https://discourse.pymc.io/t/incorrect-inference-of-hidden-states-in-state-space-models/12804 "2023-08-25T21:01:58Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dushyant](https://avatars.discourse-cdn.com/v4/letter/d/e480ec/32.png) [@dushyant](https://discourse.pymc.io/u/dushyant)\
**Post date:** [August 25, 2023, 9:01pm UTC](https://discourse.pymc.io/t/incorrect-inference-of-hidden-states-in-state-space-models/12804/1 "2023-08-25T21:01:58Z")

</div>

I am using state space models for time series modeling using the following model

X\_t = X\_{t-1} + c + N(0,\sigma^2) \\ y^i \sim Poisson(f(z^i,X\_t))

For modeling state space I am using scan function

```
x0_ar = pm.Normal("xo_ar", 0, sigma=1, initval = init_ar, shape=(latent_factors), rng=rng)
sigmas_Q_ar = pm.InverseGamma('sigmas_Q_ar', alpha=3,beta=0.5, shape= (latent_factors), rng=rng)
Q_ar = pt.diag(sigmas_Q_ar) 

def step_simple(x, A, Q, bais_latent):
    innov = pm.MvNormal.dist(mu=0.0, tau=Q)    
    next_x = pm.math.dot(A,x) + innov + bais_latent

    return next_x, collect_default_updates( [next_x]) 

ar_states_pt, ar_updates = pytensor.scan(step_simple, 
                                          outputs_info=[x0_ar], 
                                          non_sequences=[A_ar, Q_ar, bais_latent],
                                          n_steps=T, 
                                          strict=True)
assert(ar_updates)

model_minibatch.register_rv(ar_states_pt, name='ar_states_pt', initval=pt.zeros((T, latent_factors)))
ar_states = pm.Deterministic("ar", pt.concatenate([x0_ar.reshape((1,latent_factors)), ar_states_pt], axis=0))

```

ar\_states goes as input to f function. When I run the inference using ADVI, the estimates of ar\_states do not follow the state space dynamics and they just fit the training data in whatever way. Am I missing anything in the training process? How to make sure that the ar\_states follow the dynamics. Any suggestion @jessegrabowski?

Edit:1 Even when A is 0, the states are very well-fitting data. I would expect them to follow the distribution of noise+bias\_latent, why is that?  
Edit2: Out of T time points, I have data for T/2, so the model is inferring states super well for T/2 time points, but for rest of them, the values hover around the initial of the registered variable when A is an identity matrix. Below is an example where A is an identity matrix, so the time series should use just the previous time point and add some noise to it, but it is fitting to the data for half of the points and for rest it is converging towards initial of the registered random variable.

 ![example](https://canada1.discourse-cdn.com/flex036/uploads/pymc3/original/2X/5/5862c54cd00d44032e26db4954ca7dd8965e194b.jpeg)

---

<div class="post-metadata">

**Author:** ![jessegrabowski](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.pymc.io/jessegrabowski/32/5010_2.png) [@jessegrabowski](https://discourse.pymc.io/u/jessegrabowski)\
**Post date:** [August 26, 2023, 8:21pm UTC](https://discourse.pymc.io/t/incorrect-inference-of-hidden-states-in-state-space-models/12804/2 "2023-08-26T20:21:48Z")

</div>

Your model just defines a prior over the sequence, but the posterior is free to be whatever it wants to be. You are just defining a random walk with drift, so each subsequent point is regularized towards the previous one, but if the innovation sigma is sufficiently large this doesn’t matter

---

<div class="post-metadata">

**Author:** ![dushyant](https://avatars.discourse-cdn.com/v4/letter/d/e480ec/32.png) [@dushyant](https://discourse.pymc.io/u/dushyant)\
**Post date:** [August 27, 2023, 4:40am UTC](https://discourse.pymc.io/t/incorrect-inference-of-hidden-states-in-state-space-models/12804/3 "2023-08-27T04:40:31Z")

</div>

Thanks a lot for the response! Oh yes, that makes sense. So let’s say I generate the data using the below dynamics

X\_t = AX\_{t-1} + N(0,\sigma^2)

but in the PyMC, I define the model to be a random walk. So the posterior estimates would be super accurate even though the model I have specified is inaccurate, is my understanding right? Is there a way to infer that my model specification is bad? One way would be to say in the model that X\_t is not a random variable, but a deterministic one given the initial state and \sigma^2, then I can estimate how far off are these deterministic states from the true value, does that make sense?

---

<div class="post-metadata">

**Author:** ![jessegrabowski](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.pymc.io/jessegrabowski/32/5010_2.png) [@jessegrabowski](https://discourse.pymc.io/u/jessegrabowski)\
**Post date:** [August 29, 2023, 7:44pm UTC](https://discourse.pymc.io/t/incorrect-inference-of-hidden-states-in-state-space-models/12804/4 "2023-08-29T19:44:45Z")

</div>

I guess what do you mean by “super accurate”? The error bars in the plot you posted are quite wide.

The usual tools apply for model validation: posterior predictive checks and whatnot. PSIS-LOO is also still valid-ish, see [here](https://avehtari.github.io/modelselection/CV-FAQ.html#9_Can_cross-validation_be_used_for_time_series). I tried to implement a time-series LOO [here](https://github.com/arviz-devs/arviz/issues/2068), but I never finished it. Help wanted!

If your model isn’t too large, more traditional cross-validation adapted to time series data – sliding window or expanding window – are good. Scikit-learn has tools for doing that. That’s equivalent to making a “porcupine plot” like I show in [this notebook](https://github.com/pymc-devs/pymc-experimental/blob/main/notebooks/SARMA%20Example.ipynb). This is an example of “dynamic forecasting”, which is just rolling the transition equation forward from a fixed point, and compute the cumulative error. Here’s [a statsmodels example](https://www.statsmodels.org/dev/examples/notebooks/generated/statespace_sarimax_stata.html#ARIMA-Postestimation:-Example-1---Dynamic-Forecasting).

Note that my porcupine plot is fake in the sense that I don’t re-fit the model before making each forecast trajectory, so there is data leakage. This is also true if you compute the LOO using `az.loo` or `az.compare`, but these can still be useful quantities for model comparison, as the LOO FAQ link above notes.

---

<div class="post-metadata">

**Author:** ![dushyant](https://avatars.discourse-cdn.com/v4/letter/d/e480ec/32.png) [@dushyant](https://discourse.pymc.io/u/dushyant)\
**Post date:** [August 30, 2023, 12:45am UTC](https://discourse.pymc.io/t/incorrect-inference-of-hidden-states-in-state-space-models/12804/5 "2023-08-30T00:45:43Z")

</div>

Thanks a lot! The links you shared are very useful.
