1
$\begingroup$

As far as I see, the parameters of state space models will be automatically treated as time-invariant and I don't know how to specify a time-varying matrix in a state space model via statsmodels in Python. I have read the document, but still failed to find a way.

statsmodels document: https://www.statsmodels.org/stable/statespace.html

For example, for the simplest local level model

\begin{align*} X_{t+1} &= X_t + V_t \\ Y_t &= X_t + W_t \end{align*}

where $V$ and $W$ are white noises. When estimating this model, the initial state must be specified. However, if I assmue the initial state $X_1$ is an unknown constant (thus a parameter) that should also be estimated, then the model above can be formulated as

\begin{align*} X_{t+1} &= a_t + X_t + V_t \\ Y_t &= X_t + W_t \end{align*}

where for $j \ge 2$, $a_j=0$. And with this formulation, I can initially set $X_1 = 0$ and estimate $a_1$ as if it was the unknown constant $X_1$. Then $a_t$ is a time-varying parameter.

Note that in this simple model, the difficulty mentioned above can be circumvented by formulating as \begin{align*} X_{t+1} &= X_t + V_t \\ Y_t &= b_t + X_t + W_t \end{align*} set $X_1 = 0$, and estimate $b_t$ as an time-invariant parameter. But in general, I can not do so.

class LocalLevel(sm.tsa.statespace.MLEModel):

    def __init__(self, endog):
        super().__init__(endog, k_states=1)

        self['design', 0, 0] = 1.0
        self['transition', 0, 0] = 1.0
        self['selection', 0, 0] = 1.0

        self.initialize_known([0], [[0]])

    # Note the **kwargs argument must be included
    def update(self, params, transformed=True, **kwargs):
        params = super().update(params, transformed, **kwargs)
        self['obs_cov', 0, 0] = params[0]
        self['state_cov', 0, 0] = params[1]
        self['obs_intercept', 0, 0] = params[2]

    @property
    def start_params(self):
        return [1.0, 1.0, 0]

I wonder how can I set 'state_intercept' to be time-varying. It should be k_state * n_obs dimension, but I when I tried to set self['state_intercept'], I found it was treated automatically as k_state * 1 dimension, which is time-invariant.

$\endgroup$
1
  • $\begingroup$ I'm unable to add a comment, so just wanted to check the following: In the update function should it not be self['state_intercept',0,0]=params[2] instead of self['obs_intercept',0,0] since the first element of the state intercept is trying to be estimated here? $\endgroup$ Commented Aug 10, 2020 at 15:24

1 Answer 1

1
$\begingroup$

The solution is to define the matrix to be time-varying in the constructor:

self['state_intercept'] = np.zeros((self.k_states, self.nobs))

so the full code would be:

class LocalLevel(sm.tsa.statespace.MLEModel):

    def __init__(self, endog):
        super().__init__(endog, k_states=1)

        self['design', 0, 0] = 1.0
        self['transition', 0, 0] = 1.0
        self['selection', 0, 0] = 1.0
        self['state_intercept'] = np.zeros((self.k_states, self.nobs))

        self.initialize_known([0], [[0]])

    # Note the **kwargs argument must be included
    def update(self, params, transformed=True, **kwargs):
        params = super().update(params, transformed, **kwargs)
        self['obs_cov', 0, 0] = params[0]
        self['state_cov', 0, 0] = params[1]
        self['obs_intercept', 0, 0] = params[2]

    @property
    def start_params(self):
        return [1.0, 1.0, 0]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.