[[statsmodels]]のARモデルのpredictメソッドのdynamicオプションについて。 --- [[Time Series Analysis in Python with statsmodels]] --- [Autoregressions — statsmodels](https://www.statsmodels.org/dev/examples/notebooks/generated/autoregressions.html#Forecasting) > Forecasts are produced using the predict method from a results instance. The default produces static forecasts which are one-step forecasts. Producing multi-step forecasts requires using dynamic=True. > 予測は、resultsインスタンスからpredictメソッドで生成されます。デフォルトでは、1ステップの予測である静的な予測が生成されます。多段階の予測を行うには、dynamic=Trueを使用する必要があります。 > この次のセルでは、サンプルの最後の24期間について、12段階の聞き取りによる予測を作成します。これにはループが必要です。 ```python import numpy as np start = ind_prod.index[-24] forecast_index = pd.date_range(start, freq=ind_prod.index.freq, periods=36) cols = ["-".join(str(val) for val in (idx.year, idx.month)) for idx in forecast_index] forecasts = pd.DataFrame(index=forecast_index, columns=cols) for i in range(1, 24): fcast = res_glob.predict( start=forecast_index[i], end=forecast_index[i + 12], dynamic=True ) forecasts.loc[fcast.index, cols[i]] = fcast _, ax = plt.subplots(figsize=(16, 10)) ind_prod.iloc[-24:].plot(ax=ax, color="black", linestyle="--") ax = forecasts.plot(ax=ax) ``` [statsmodels.tsa.ar_model.AutoReg.predict — statsmodels](https://www.statsmodels.org/v0.12.2/generated/statsmodels.tsa.ar_model.AutoReg.predict.html#statsmodels.tsa.ar_model.AutoReg.predict) > Integer offset relative to start at which to begin dynamic prediction. Prior to this observation, true endogenous values will be used for prediction; starting with this observation and continuing through the end of prediction, forecasted endogenous values will be used instead. Datetime-like objects are not interpreted as offsets. They are instead used to find the index location of dynamic which is then used to to compute the offset. 動的予測を開始する開始点からの相対的な整数オフセット。この観測の前に、真の内因性値が予測に使用される。この観測から始まり、予測の終わりまで、予測された内因性値が代わりに使用される。日時的なオブジェクトはオフセットとして解釈されない。代わりに、オフセットを計算するために使用されるdynamicのインデックス位置を見つけるために使用されます。 ## コードリーディング 以下statsmodels v0.12.2 **static prediction** ```python def _static_oos_predict(self, params, num_oos, exog_oos): new_x = self._setup_oos_forecast(num_oos, exog_oos) if self._maxlag == 0: return new_x @ params forecasts = np.empty(num_oos) nexog = 0 if self.exog is None else self.exog.shape[1] ar_offset = self._x.shape[1] - nexog - self._lags.shape[0] for i in range(num_oos): for j, lag in enumerate(self._lags): loc = i - lag val = self._y[loc] if loc < 0 else forecasts[loc] new_x[i, ar_offset + j] = val forecasts[i] = new_x[i : i + 1] @ params return forecasts def _static_predict(self, params, start, end, num_oos, exog, exog_oos): """ Path for static predictions Parameters ---------- start : int Index of first observation end : int Index of last in-sample observation. Inclusive, so start:end+1 in slice notation. num_oos : int Number of out-of-sample observations, so that the returned size is num_oos + (end - start + 1). exog : ndarray Array containing replacement exog values exog_oos : ndarray Containing forecast exog values """ hold_back = self._hold_back nobs = self.endog.shape[0] x = np.empty((0, self._x.shape[1])) if start <= nobs: is_loc = slice(start - hold_back, end + 1 - hold_back) x = self._x[is_loc] if exog is not None: x = x.copy() # Replace final columns x[:, -exog.shape[1] :] = exog[start : end + 1] in_sample = x @ params if num_oos == 0: # No out of sample return self._wrap_prediction(in_sample, start, end + 1) out_of_sample = self._static_oos_predict(params, num_oos, exog_oos) prediction = np.hstack((in_sample, out_of_sample)) return self._wrap_prediction(prediction, start, end + 1 + num_oos) ``` - 後半のループで、[[自己回帰モデル|ARモデル]]の$y_{t}$ (`forecasts[i]`)を順次計算している。 - `new_x[i : i + 1] @ params`は一次の線形結合の計算。 - AR係数(params)の値は変化しない。 - static_oos_predictは全然通っていないかも? - `in_sample = x @ params` だけ計算している。 **dynamic prediction** ```python def _setup_oos_forecast(self, add_forecasts, exog_oos): x = np.zeros((add_forecasts, self._x.shape[1])) oos_exog = self._deterministics.out_of_sample(steps=add_forecasts) n_deterministic = oos_exog.shape[1] x[:, :n_deterministic] = to_numpy(oos_exog) # skip the AR columns loc = n_deterministic + len(self._lags) if self.exog is not None: x[:, loc:] = exog_oos[:add_forecasts] return x def _dynamic_predict( self, params, start, end, dynamic, num_oos, exog, exog_oos ): """ :param params: :param start: :param end: :param dynamic: :param num_oos: :param exog: :param exog_oos: :return: """ reg = [] hold_back = self._hold_back if (start - hold_back) <= self.nobs: is_loc = slice(start - hold_back, end + 1 - hold_back) x = self._x[is_loc] if exog is not None: x = x.copy() # Replace final columns x[:, -exog.shape[1] :] = exog[start : end + 1] reg.append(x) if num_oos > 0: reg.append(self._setup_oos_forecast(num_oos, exog_oos)) reg = np.vstack(reg) det_col_idx = self._x.shape[1] - len(self._lags) det_col_idx -= 0 if self.exog is None else self.exog.shape[1] # + 1 is due t0 inclusiveness of predict functions adj_dynamic = dynamic - start + 1 forecasts = np.empty(reg.shape[0]) forecasts[:adj_dynamic] = reg[:adj_dynamic] @ params for h in range(adj_dynamic, reg.shape[0]): # Fill in regressor matrix for j, lag in enumerate(self._lags): fcast_loc = h - lag if fcast_loc >= 0: val = forecasts[fcast_loc] else: # If before the start of the forecasts, use actual values val = self.endog[start + fcast_loc] reg[h, det_col_idx + j] = val forecasts[h] = reg[h : h + 1] @ params return self._wrap_prediction(forecasts, start, end + 1 + num_oos) ``` - regはxのコピー - for ループ内でregは更新されているjj - xはactual valuesと同じ - adj_dynamic => 1 - det_col_idx -> 0 - 最初の`forecats[:adj_dybamic]` は実測値にAR係数をかけただけ。 - `forecasts = np.empty(reg.shape[0])` は初期化されていないのでxの値が入っている