Rの関数:ARMAtoMA {stats}

Rの関数から ARMAtoMA {stats} を確認します。

関数 ARMAtoMA とは

ARMAtoMA は、ARMA(自己回帰移動平均)モデルの係数を、無限次MA(移動平均)モデルの係数(\(\psi\) ウェイト)に変換する関数です。

これは、時系列分析においてインパルス応答関数(Impulse Response Function)を求めることと同義です。

すなわち、ある時点 \(t\) で外部からのインパルス(ホワイトノイズ \(Z_t\))が 1単位発生した際、それが将来(\(t+1, t+2, \dots\))の時系列データにどのような影響を及ぼしていくかを表す係数列を計算します。

具体的には、ARMAモデル \(\phi(B)X_t = \theta(B)Z_t\) を、無限MA表現 \(X_t = \psi(B)Z_t\) (ただし \(\psi(B) = \theta(B)/\phi(B)\))に変換し、その係数 \(\psi_1, \psi_2, \dots, \psi_m\) を導出します。

なお、\(\psi_0\) は常に \(1\) であるため、この関数はラグ1以降の係数を返します。

関数 ARMAtoMA の引数

args(ARMAtoMA)
function (ar = numeric(), ma = numeric(), lag.max) 
NULL
  1. ar

    • AR(自己回帰)項の係数ベクトル(\(\phi_1, \phi_2, \dots, \phi_p\))。
    • モデルの自己回帰部分を定義します。
    • デフォルト: numeric()(AR項なし)。
  2. ma

    • MA(移動平均)項の係数ベクトル(\(\theta_1, \theta_2, \dots, \theta_q\))。
    • モデルの移動平均部分を定義します。
    • デフォルト: numeric()(MA項なし)。
  3. lag.max

    • 計算するラグの最大値(整数)。
    • いくつの係数(\(\psi_1\) から \(\psi_{lag.max}\) まで)を計算するかを指定します。Cコード内の m に相当します。
    • 必須引数であり、デフォルト値はありません。正の整数を指定する必要があります。

シミュレーションコード

以下に、ARMAtoMA の機能を確認するためのシミュレーションコードを示します。

このシミュレーションでは、以下の手順を実行し、関数の挙動を検証します。

  1. ARMAモデルの設定:

    • 具体的なAR係数とMA係数を設定します。
  2. ARMAtoMAによる計算:

    • 関数を用いて理論的なインパルス応答(\(\psi\) ウェイト)を計算します。
  3. インパルス応答のシミュレーション:

    • 時刻 \(t=1\) だけ値が \(1\) で、それ以外は \(0\) であるような「インパルス」データを作成します。
    • このインパルスデータを、設定したARMAモデルのフィルタに通します(filter 関数を使用)。
      • 関数 filter は「入力データに対して、係数を掛け合わせながら足し合わせる計算(畳み込み、または再帰計算)」を行う関数です。
    • フィルタを通った後の出力結果が、ARMAtoMA で計算された係数と一致することを確認します。

これにより、ARMAtoMA が「インパルスが時間の経過とともにどう伝播するか」を計算していることを確認できます。

# パッケージの読み込み
library(ggplot2)

# 1. ARMAモデルのパラメータ設定
# モデル: X_t = 0.7 * X_{t-1} - 0.2 * X_{t-2} + Z_t + 0.5 * Z_{t-1}
# AR(2) + MA(1) = ARMA(2, 1) モデル
ar_coef <- c(0.7, -0.2)
ma_coef <- c(0.5)
max_lag <- 15

cat("--- モデル設定 ---\n")
cat(sprintf("AR係数 (phi)  : %s\n", paste(ar_coef, collapse = ", ")))
cat(sprintf("MA係数 (theta): %s\n", paste(ma_coef, collapse = ", ")))
cat(sprintf("計算ラグ数    : %d\n\n", max_lag))


# 2. ARMAtoMA を用いた係数計算
# これが理論的なインパルス応答係数(ラグ1~15)です
psi_weights <- ARMAtoMA(ar = ar_coef, ma = ma_coef, lag.max = max_lag)

cat("--- ARMAtoMAによる計算結果 (先頭5つを表示) ---\n")
print(head(psi_weights, 5))
cat("\n")


# 3. フィルタ関数を用いたシミュレーションによる検証
# インパルスデータの作成
# 時点1に「1」のインパルスを与え、その後は「0」が続くデータ
impulse_input <- c(1, rep(0, max_lag))

# 手順A: まずMA部分を適用 (Z_t + 0.5 * Z_{t-1})
# filter関数のsides=1は片側(過去のみ参照)フィルタを意味します
ma_filtered <- stats::filter(impulse_input,
  filter = c(1, ma_coef),
  method = "convolution", sides = 1
)
# NAを除去(最初の部分は計算できないためNAになりますが、ここでは先頭を補正)
# filterの挙動として、先頭の1はそのままで、次の項からMA係数が乗ります
# MA(1)なので、入力が(1,0,0...)なら、出力は(1, 0.5, 0...)となるはずです
# method="recursive"を使うARフィルタに入力する前の「MA変換済み入力」を作ります
ma_impulse <- c(1, ma_coef, rep(0, max_lag - length(ma_coef)))

# 手順B: 次にAR部分を適用 (再帰的フィルタ)
# これにより、無限に続く応答が生成されます
simulated_response <- stats::filter(ma_impulse,
  filter = ar_coef,
  method = "recursive"
)

# simulated_response の先頭はラグ0(値は1)なので、
# ARMAtoMAの結果(ラグ1以降)と比較するために2番目以降を取り出します
simulated_psi <- as.numeric(simulated_response)[2:(max_lag + 1)]

# 4. 結果の比較
df_compare <- data.frame(
  Lag = 1:max_lag,
  ARMAtoMA_Value = psi_weights,
  Simulated_Value = simulated_psi
)

cat("--- シミュレーション(フィルタ)結果との比較 (先頭5つを表示) ---\n")
print(head(df_compare, 5))
cat("\n係数は全て一致しているか : ", all.equal(target = df_compare$ARMAtoMA_Value, current = df_compare$Simulated_Value))

# 5. 可視化
# インパルス応答関数のプロット
p1 <- ggplot(df_compare, aes(x = Lag)) +
  # ゼロライン
  geom_hline(yintercept = 0, color = "gray50") +

  # ARMAtoMAの結果(赤い線と点)
  geom_line(aes(y = ARMAtoMA_Value, color = "ARMAtoMA (理論値)"),
    linewidth = 1
  ) +
  geom_point(aes(y = ARMAtoMA_Value, color = "ARMAtoMA (理論値)"),
    size = 3
  ) +

  # シミュレーション結果(青い×印)を重ねて表示
  geom_point(aes(y = Simulated_Value, color = "フィルタシミュレーション"),
    shape = 4, size = 5, stroke = 1.5
  ) +

  # 色の設定
  scale_color_manual(
    name = "",
    values = c(
      "ARMAtoMA (理論値)" = "firebrick",
      "フィルタシミュレーション" = "blue"
    )
  ) +

  # ラベル設定
  labs(
    title = "ARMA(2,1)モデルのインパルス応答関数",
    x = "ラグ (Lag)",
    y = "係数値 (psi weights)"
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")

print(p1)
--- モデル設定 ---
AR係数 (phi)  : 0.7, -0.2
MA係数 (theta): 0.5
計算ラグ数    : 15

--- ARMAtoMAによる計算結果 (先頭5つを表示) ---
[1]  1.20000  0.64000  0.20800  0.01760 -0.02928

--- シミュレーション(フィルタ)結果との比較 (先頭5つを表示) ---
  Lag ARMAtoMA_Value Simulated_Value
1   1        1.20000         1.20000
2   2        0.64000         0.64000
3   3        0.20800         0.20800
4   4        0.01760         0.01760
5   5       -0.02928        -0.02928

係数は全て一致しているか :  TRUE
Figure 1

Figure 1 からAR項の影響により、初期のインパルスが徐々に減衰していく様子が見て取れます。

ARMAモデルの係数(ar, ma)だけを見ても、「過去のショックが現在にどう影響するか」を直感的に理解するのは困難ですが、ARMAtoMAを用いて変換することで、ショックの伝播プロセスを可視化・定量化することができます。

参照資料

以上です。