More Related Content
Similar to Pythonでカスタム状態空間モデル (20)
Pythonでカスタム状態空間モデル
- 10. 実装開始
テスト用のデータを生成。
def gen_data_for_model1():
nobs = 1000
rs = np.random.RandomState(seed=93572)
Ht = 5
Tt = 1.001
A = 0.1
B = -0.007
Qt = 0.01
var_z = 0.1
et = rs.normal(scale=Ht**0.5, size=nobs)
z = np.cumsum(rs.normal(size=nobs, scale=var_z**0.05))
Et = rs.normal(scale=Qt**0.5, size=nobs)
xt_1 = 50
x = []
for i in range(nobs):
xt = Tt * xt_1
x.append(xt)
xt_1 = xt
xt = np.array(x)
xt = xt + A * np.exp(B/z) + Et
yt = xt + et
return yt, xt, z
yt, xt, z = gen_data_for_model1()
_ = plt.plot(yt,color = "r")
_ = plt.plot(xt, color="b")
- 14. モデルの定義
class custom(sm.tsa.statespace.MLEModel):
param_names = ['T', 'A', 'B', 'Ht', 'Qt']
start_params = [1., 1., 0., 1., 1]
def __init__(self, endog, exog):
exog = np.squeeze(exog) # 外生変数は1つのため次元削減
# endog:観測データ(y)、exog:外生変数(z)、k_state=1:状態プロセスの次元
super().__init__(endog, exog=exog, k_states=1, initialization='diffuse')
self.k_exog = 1 # 外生変数の次元は1である
# Z(design matrix)は単位行列である
self['design', 0, 0] = 1.
# R(selection matrix)は単位行列である
self['selection', 0, 0] = 1.
# c_t(state_intercept)は時変数であると定義
self['state_intercept'] = np.zeros((1, self.nobs))
def clone(self, endog, exog, **kwargs):
# 時変状態空間行列を含むカスタムモデルであることを定義
return self._clone_from_init_kwds(endog, exog=exog, **kwargs)
- 15. モデルの定義
def transform_params(self, params):
# 分散は正数である必要があるので一旦2乗する
params[3:] = params[3:]**2
return params
def untransform_params(self, params):
# R2乗したものを1/2乗して元の大きさに戻す(平方根)
params[3:] = params[3:]**0.5
return params
def update(self, params, **kwargs):
# 更新するための定義
params = super().update(params, **kwargs)
# T = T:0番目のパラメータをtransition matrixに代入
self['transition', 0, 0] = params[0]
# c_t = A * exp(B / z_t):1,2番目のパラメータをstate_interceprに代入
self['state_intercept', 0, :] = params[1] * np.exp(params[2] / self.exog)
# Ht:3番目のパラメータを観測ノイズの分散に代入
self['obs_cov', 0, 0] = params[3]
# Qt:4番目のパラメータを状態ノイズの分散に代入
self['state_cov', 0, 0] = params[4]
参考文献
・statsmodelsのMLEModelの説明ページ
・statsmodelsのカスタムモデルの説明ページ
- 18. 推定と予測
推定と予測
predict = res.get_prediction()
forecast = res.get_forecast(df.index[-1], exog = df_train['z'].values)
・予測する場合は、どの時点まで予測するかを指定する必要があります。(今回は
df.index[-1]で指定)
・外生変数をモデルに使用する場合は、予測の時に「 exog=」の引数でデータを指定
する必要があります。今回は全てがダミーデータですが、実際に予測で使用する場合
は、過去のデータなどからダミーデータを作成する必要があります。
・データの間隔が不均一なデータは予測に使えません。
(同じく外生変数を使った SARIMAXなども同じことが言えます)
- 19. 推定と予測
可視化
fig, ax = plt.subplots()
y = df['y']
# Plot the results
y.plot(ax=ax,label='y')
predict.predicted_mean.plot(label='x')
predict_ci = predict.conf_int(alpha=0.05)
predict_index = predict_ci.index
ax.fill_between(predict_index[2:], predict_ci.iloc[2:, 0], predict_ci.iloc[2:, 1], alpha=0.1)
forecast.predicted_mean.plot(ax=ax, style='r', label='forecast')
forecast_ci = forecast.conf_int()
forecast_index = forecast_ci.index
ax.fill_between(forecast_index, forecast_ci.iloc[:, 0], forecast_ci.iloc[:, 1], alpha=0.1)
# Cleanup the image
legend = ax.legend(loc='best');
fig.savefig('custom_statespace.png')