Я вхожу в модели пространства состояний и их оценку в пакете python statsmodels
. Я получил пример из руководства пользователя для работы, но не смог получить разумные результаты для своего собственного примера, и я не совсем понимаю, почему.
Я хочу оценить AR (1) с изменяющимися во времени коэффициентами, то есть y_t = a_t + b_t*y_{t-1} + e_t
(уравнение измерения), где вектор коэффициентов alpha_t := (a_t,b_t)'
следует за VAR (1) (уравнение перехода).
Здесь симуляция
import statsmodels.api as sm
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sn
# simulate states
T = 500 # nobs
A = np.diag([0.8,0.8]) # transition matrix
c = np.array([4,0.1]) # state intercept
Q = np.eye(2)
Q[1,1] /= 1000 # cov of state error
# draw state variable errors
v = np.random.multivariate_normal([0,0],Q,size=(T,))
init = np.array([20,0.5])
alpha = np.vstack([init[None,:],np.zeros((T,2))])
for i in range(T):
alpha[i+1,:] = c + A@alpha[i,:] + v[i,:]
# plot processes
fig, ax = plt.subplots(2,2,figsize=(17,8))
for i in range(2):
ax[i,0].plot(alpha[1:,i], label=r'$\alpha_{i}$'.format(i=i+1))
ax[i,0].legend(loc=1)
ax[i,1].plot(v[1:,i], label=r'$v_{i}$'.format(i=i+1))
ax[i,1].legend(loc=1)
plt.show()
# simulate y_t
e = np.random.randn(T)*5
y = np.append(40,np.zeros(T))
for i in range(T):
y[i+1] = alpha[i+1,0] + alpha[i+1,1]*y[i] + e[i]
# plot y_t
fig, ax = plt.subplots(1,1,figsize=(12,5))
ax.plot(y)
ax.set_title(r'$y_t$')
plt.show()
Я пытался выбрать параметры так, чтобы y_t
вел себя стабильно, но я думаю, что это не гарантировано, поэтому лучше составьте график процессов перед оценкой.
Вот как я представляю модель в statsmodels:
class ARVarCoefModel(sm.tsa.statespace.MLEModel):
param_names = ['sigma2.e','c0','c1','a11','a22','sigma2.v1','sigma2.v2'] # for output readability
start_params = [25,4,0.1,0.8,0.8,1,0.001] # initiate estimation at true parameters
def __init__(self, endog, design_mat):
k_states = k_posdef = design_mat.shape[1]
super().__init__(endog, k_states=k_states, k_posdef=k_posdef,
initialization='approximate_diffuse',loglikelihood_burn=k_states) #approximate_diffuse
self['design'] = exog.T[None,:,:]
self['selection'] = np.eye(2)
self.diag_idx = np.diag_indices(k_states)
# variance must be positive; keep transition matrix params between (0,1)
def transform_params(self,params):
constrained = params.copy()
constrained[0] = constrained[0]**2
constrained[3] = 1/(1+np.exp(constrained[3]))
constrained[4] = 1/(1+np.exp(constrained[4]))
constrained[5] = constrained[5]**2
constrained[6] = constrained[6]**2
return constrained
def untransform_params(self,params):
unconstrained = params.copy()
unconstrained[0] = unconstrained[0]**0.5
unconstrained[3] = np.log(1/unconstrained[3] -1)
unconstrained[4] = np.log(1/unconstrained[4] -1)
unconstrained[5] = unconstrained[5]**0.5
unconstrained[6] = unconstrained[6]**0.5
return unconstrained
def update(self,params, **kwargs):
params = super().update(params, **kwargs)
self['obs_cov',0,0] = params[0]
self['state_intercept'] = params[1:3]
self[('transition',) + self.diag_idx] = params[3:5]
self[('state_cov',) + self.diag_idx] = params[5:]
Теперь оцените
endog = y[1:]
exog = np.hstack([np.ones((len(endog),1)),y[:-1,None]])
model = ARVarCoefModel(endog,exog)
model.fit(method='bfgs',maxiter=1000)
Независимо от того, как часто я запускаю симуляцию, какой метод оптимизации я использую, оптимизация сходится, но результаты имеют мало смысла. По какой-то причине (или, может быть, это совпадение) параметры a11
и sigma2.v11
резко занижены (относительно близки к нулю).
Сглаженные состояния также не приближаются к тому, какими они должны быть:
fig, ax = plt.subplots(2,1,figsize=(14,7))
for i in range(2):
ax[i].plot(alpha[1:,i],label=r'$\alpha_{}$'.format(i+1))
ax[i].plot(res.smoothed_state[i,1:],'g--',label=r'$\hat \alpha_{}$ (smoothed)'.format(i+1))
ax[i].legend()
plt.show()
У меня нет практического опыта работы с моделями пространства состояний в этой более общей форме, поэтому, возможно, я выбрал плохой пример и это просто некорректная задача. Но я бы подумал, что это должен быть довольно стандартный пример (подобный практический пример я видел в Lutkepohl (2005) «Новое введение в анализ множественных временных рядов», глава 18.5, которую мне не удалось воспроизвести). Поэтому я надеюсь, что просто делаю что-то не так, представляя модель в statsmodels
. (Кстати, это версия 0.9.0
; Python 3.6.5)