Rによる インパルス応答の シミュレーション を試みます。
始めにサンプルデータを作成します。
サンプルデータは互いに影響し合う2つの時系列データ VAR(2) とします。
<- 20250527
seed set.seed(seed)
# 互いに影響し合う2つの時系列データの作成
# -------------------------------------------------
# データポイント数
<- 200
n_obs
# 誤差項(ホワイトノイズ)
# 平均0、標準偏差1の正規分布に従う乱数を生成
<- rnorm(n_obs, mean = 0, sd = 1)
e1 <- rnorm(n_obs, mean = 0, sd = 1)
e2
# 時系列データを格納するベクトルを初期化
<- numeric(n_obs)
y1 <- numeric(n_obs)
y2
# 初期値 (t=1, t=2)
# VAR(2)モデルとするため最初の2時点を作成します
# ここでは、最初の2点は0とします
1] <- 0
y1[2] <- 0
y1[1] <- 0
y2[2] <- 0
y2[
# VAR(2)モデルのパラメータ
# y1_t = c1 + a11_1*y1_{t-1} + a11_2*y1_{t-2} + a12_1*y2_{t-1} + a12_2*y2_{t-2} + e1_t
# y2_t = c2 + a21_1*y1_{t-1} + a21_2*y1_{t-2} + a22_1*y2_{t-1} + a22_2*y2_{t-2} + e2_t
# y1の式に対する係数
<- 0.6 # y1(t-1) が y1(t) に与える影響
phi11_lag1 <- 0.2 # y1(t-2) が y1(t) に与える影響
phi11_lag2 <- 0.3 # y2(t-1) が y1(t) に与える影響 (y2からy1への影響)
phi12_lag1 <- -0.1 # y2(t-2) が y1(t) に与える影響
phi12_lag2
# y2の式に対する係数
<- 0.4 # y1(t-1) が y2(t) に与える影響 (y1からy2への影響)
phi21_lag1 <- -0.2 # y1(t-2) が y2(t) に与える影響
phi21_lag2 <- 0.5 # y2(t-1) が y2(t) に与える影響
phi22_lag1 <- 0.1 # y2(t-2) が y2(t) に与える影響
phi22_lag2
# 定数項
<- 0.2
c1 <- -0.3
c2
# 時系列データの生成 (t=3 から n_obs まで)
for (t in 3:n_obs) {
<- c1 + phi11_lag1 * y1[t - 1] + phi11_lag2 * y1[t - 2] +
y1[t] * y2[t - 1] + phi12_lag2 * y2[t - 2] + e1[t]
phi12_lag1
<- c2 + phi21_lag1 * y1[t - 1] + phi21_lag2 * y1[t - 2] +
y2[t] * y2[t - 1] + phi22_lag2 * y2[t - 2] + e2[t]
phi22_lag1
}
# 生成したデータをデータフレームにまとめる
<- data.frame(y1 = y1, y2 = y2)
ts_data
print("作成した時系列データの最初の6行:")
print(head(ts_data))
plot.ts(ts_data)
[1] "作成した時系列データの最初の6行:"
y1 y2
1 0.0000000 0.0000000
2 0.0000000 0.0000000
3 1.7468294 -0.8894778
4 0.5633849 -0.6451556
5 0.8714418 -1.4436164
6 1.0934626 -1.6077774
続いて ラグ次数を2 とする VARモデル を作成します。
# VARモデルの作成 (ラグ次数 p=2)
# -------------------------------------------------
# 関数VARの引数は以下の通り
# -第1引数: 時系列データ (データフレームまたは行列)
# -p: ラグ次数
# -type: 定数項やトレンド項を含めるかどうかを指定
# "const": 定数項のみ
# "trend": トレンド項のみ
# "both": 定数項とトレンド項の両方
# "none": 定数項もトレンド項もなし
library(vars)
<- VAR(ts_data, p = 2, type = "const")
var_model
# VARモデルのラグ次数
<- var_model$p # p = 2
p
print("作成したVARモデル:")
var_model
[1] "作成したVARモデル:"
VAR Estimation Results:
=======================
Estimated coefficients for equation y1:
=======================================
Call:
y1 = y1.l1 + y2.l1 + y1.l2 + y2.l2 + const
y1.l1 y2.l1 y1.l2 y2.l2 const
0.55792508 0.33535811 0.20851247 -0.08006986 0.28429339
Estimated coefficients for equation y2:
=======================================
Call:
y2 = y1.l1 + y2.l1 + y1.l2 + y2.l2 + const
y1.l1 y2.l1 y1.l2 y2.l2 const
0.4636189 0.4196150 -0.2844179 0.0985776 -0.4263063
var_model から係数を抽出して、y1の 誤差項の標準偏差 を 手計算 で求めます。
# VARモデルからy1の式の推定係数を取得
# -------------------------------------------------
<- coef(var_model$varresult$y1)
equation_y1_coeffs
# 係数を個別の変数に格納
<- equation_y1_coeffs["y1.l1"]
coef_y1_lag1 <- equation_y1_coeffs["y1.l2"]
coef_y1_lag2 <- equation_y1_coeffs["y2.l1"]
coef_y2_lag1 <- equation_y1_coeffs["y2.l2"]
coef_y2_lag2 <- equation_y1_coeffs["const"]
coef_const_y1
# y1の予測値を計算
# -------------------------------------------------
# 予測値を格納するベクトル
<- numeric(n_obs)
y1_predicted 1:p] <- NA # 最初のp時点はラグデータがないためNA
y1_predicted[
# 元のデータ
<- ts_data$y1
y1_actual <- ts_data$y2
y2_actual
# ループで予測値を計算 (t = p+1 から n_obs まで)
for (t in (p + 1):n_obs) {
<- coef_const_y1 +
y1_predicted[t] * y1_actual[t - 1] +
coef_y1_lag1 * y1_actual[t - 2] +
coef_y1_lag2 * y2_actual[t - 1] +
coef_y2_lag1 * y2_actual[t - 2]
coef_y2_lag2
}
# y1の残差を計算
# -------------------------------------------------
# 残差を格納するベクトル
<- numeric(n_obs)
residuals_y1 1:p] <- NA # 最初のp時点はNA
residuals_y1[
# ループで残差を計算 (t = p+1 から n_obs まで)
for (t in (p + 1):n_obs) {
<- y1_actual[t] - y1_predicted[t]
residuals_y1[t]
}
# NAを除いた残差ベクトル
<- residuals_y1[!is.na(residuals_y1)]
valid_residuals_y1
# y1の残差の標準偏差を計算
# -------------------------------------------------
# 残差標準誤差 = sqrt(RSS / 自由度)
# RSS (Residual Sum of Squares)
<- sum(valid_residuals_y1^2)
rss_y1
# 自由度 (degrees of freedom)
# 有効な観測点の数 = n_obs - p
<- n_obs - p
n_effective_obs
# y1の式に含まれる推定パラメータの数 (y1.l1, y1.l2, y2.l1, y2.l2, const の5つ)
<- length(equation_y1_coeffs)
num_parameters_y1
<- n_effective_obs - num_parameters_y1
df_residuals_y1
# y1の残差の分散
<- rss_y1 / df_residuals_y1
variance_residuals_y1
# y1の残差の標準偏差
<- sqrt(variance_residuals_y1)
sd_residuals_y1
print(paste("y1の誤差項の標準偏差:", sd_residuals_y1))
[1] "y1の誤差項の標準偏差: 1.01912442882628"
参考として 関数summary {base} を利用して var_model から標準偏差を抽出します。
<- summary(var_model)
summary_var_model <- summary_var_model$varresult$y1$sigma
sd_residuals_y1_vars_pkg <- sqrt(diag(summary_var_model$covres))[1]
sd_residuals_y1_vars_pkg_cov print(paste("summaryから得られるy1の残差標準偏差 (直接的に抽出):", sd_residuals_y1_vars_pkg))
print(paste("summaryから得られるy1の残差標準偏差 (残差の分散共分散行列から算出):", sd_residuals_y1_vars_pkg_cov))
[1] "summaryから得られるy1の残差標準偏差 (直接的に抽出): 1.01912442882628"
[1] "summaryから得られるy1の残差標準偏差 (残差の分散共分散行列から算出): 1.01912442882628"
一致していることが確認できます。
確認した y1 の誤差項の1標準偏差分 を 初期ショック として、y1 および y2 の 0期目 と 1期先 の応答値を計算します。
# VARモデルからラグ1の係数行列 A_1 を作成
# -----------------------------------------------------------
# A_1 行列は (K x K) の行列で、
# A_1[i,j] は「j番目の変数の1期前の値が、i番目の現在の値に与える影響」を示す係数
# Y_t = A_1 * Y_{t-1} + ...
#
# (y1_t) = (a11 a12) * (y1_{t-1})
# (y2_t) (a21 a22) (y2_{t-1})
#
# a11 は y1 の式の y1.l1 の係数
# a12 は y1 の式の y2.l1 の係数
# a21 は y2 の式の y1.l1 の係数
# a22 は y2 の式の y2.l1 の係数
# 変数の数 (K) を取得
<- var_model$K
K_vars
# 各方程式の係数を取得
<- coef(var_model$varresult[[1]]) # y1 の方程式の係数
coeffs_eq1 <- coef(var_model$varresult[[2]]) # y2 の方程式の係数
coeffs_eq2
# ts_dataの列名を取得
<- colnames(var_model$y)
var_names
# ラグ1の係数名を作成
# 例: "y1.l1", "y2.l1"
<- paste0(var_names, ".l1")
lag1_coef_names
# A_1 行列の要素を抽出
# y1 の方程式から
<- coeffs_eq1[lag1_coef_names[1]] # y1.l1 の係数
a11 <- coeffs_eq1[lag1_coef_names[2]] # y2.l1 の係数
a12 # y2 の方程式から
<- coeffs_eq2[lag1_coef_names[1]] # y1.l1 の係数
a21 <- coeffs_eq2[lag1_coef_names[2]] # y2.l1 の係数
a22
# A_1 行列を構成
# A_1 = | a11 a12 |
# | a21 a22 |
<- matrix(c(a11, a12, a21, a22), nrow = K_vars, ncol = K_vars, byrow = TRUE)
A1_matrix
# 誤差項の分散共分散行列
<- summary(var_model)
summary_var_model <- summary_var_model$covres
Sigma_U
cat("--- 誤差項の分散共分散行列 Sigma_U ---\n")
print(Sigma_U)
cat("\n")
cat("--- 誤差項の分散共分散行列が対称行列であることを確認 ---\n")
isSymmetric(Sigma_U)
cat("\n")
# Cholesky分解: P P' = Sigma_U (Pは下三角行列)
# Rのchol()は上三角行列R (R'R = Sigma_U) を返すので、P = t(chol(Sigma_U))
cat("--- 固有値をチェックして正定値性(正定値行列)を確認 ---\n")
<- eigen(Sigma_U, only.values = TRUE)$values
eigen_values all(eigen_values > .Machine$double.eps^0.5)
cat("\n")
<- t(chol(Sigma_U))
P_cholesky cat("--- Cholesky分解の下三角行列 P ---\n")
print(P_cholesky)
cat("\n")
# y1への1標準偏差ショックに対する0期目の応答ベクトル
# Pの最初の列ベクトルが、y1へのショックに対する0期目の応答
# (var_modelの変数の順序が y1, y2 である前提)
<- P_cholesky[, 1, drop = FALSE] # K_vars x 1 の列行列として保持
Y0_response
cat("--- 0期目応答 (Y0_response) ---\n")
# 行名を設定
<- colnames(var_model$y)
var_names rownames(Y0_response) <- var_names
print(Y0_response)
cat("\n")
# 1期先の応答 (Y_1) の計算
# A1_matrix は (K_vars x K_vars)
# Y0_response は (K_vars x 1)
<- A1_matrix %*% Y0_response
Y1_response
cat("--- 1期先の応答 (Y1_response) ---\n")
rownames(Y1_response) <- var_names
print(Y1_response)
--- 誤差項の分散共分散行列 Sigma_U ---
y1 y2
y1 1.0386146 -0.1475606
y2 -0.1475606 1.1107130
--- 誤差項の分散共分散行列が対称行列であることを確認 ---
[1] TRUE
--- 固有値をチェックして正定値性(正定値行列)を確認 ---
[1] TRUE
--- Cholesky分解の下三角行列 P ---
y1 y2
y1 1.0191244 0.00000
y2 -0.1447915 1.04391
--- 0期目応答 (Y0_response) ---
y1
y1 1.0191244
y2 -0.1447915
--- 1期先の応答 (Y1_response) ---
y1
y1 0.5200381
y2 0.4117287
Rの 関数irf による結果と比較します。
irf(var_model,
impulse = "y1", # y1 の誤差項にショック
response = c("y1", "y2"), # y1 と y2 の応答を見る
n.ahead = 1, # 1期先まで計算 (結果は0期目と1期目を含む)
ortho = TRUE, # 直交化インパルス応答 (ショックは1標準偏差)
boot = FALSE, # ブートストラップ信頼区間は計算しない
cumulative = FALSE
# 各期の応答 (非累積) )
Impulse response coefficients
$y1
y1 y2
[1,] 1.0191244 -0.1447915
[2,] 0.5200381 0.4117287
一致しています。
同様に 2期先 の応答値を求めます。
# VARモデルからラグ2の係数行列 A_2 を作成
# -----------------------------------------------------------
# A_2 行列は (K x K) の行列で、
# A_2[i,j] は「j番目の変数の2期前の値が、i番目の現在の値に与える影響」を示す係数
# Y_t = ... + A_2 * Y_{t-2} + ...
#
# (y1_t) = ... + (a11_l2 a12_l2) * (y1_{t-2})
# (y2_t) (a21_l2 a22_l2) (y2_{t-2})
#
# a11_l2 は y1 の式の y1.l2 の係数
# a12_l2 は y1 の式の y2.l2 の係数
# a21_l2 は y2 の式の y1.l2 の係数
# a22_l2 は y2 の式の y2.l2 の係数
<- var_model$K
K_vars <- colnames(var_model$y)
var_names
# 改めて各方程式の係数を取得
<- coef(var_model$varresult[[var_names[1]]]) # y1 の方程式の係数
coeffs_eq1 <- coef(var_model$varresult[[var_names[2]]]) # y2 の方程式の係数
coeffs_eq2
# ラグ2の係数名を作成
<- paste0(var_names, ".l2")
lag2_coef_names
# A_2 行列の要素を抽出
# y1 の方程式から
<- coeffs_eq1[lag2_coef_names[1]] # y1.l2 の係数
a11_l2 <- coeffs_eq1[lag2_coef_names[2]] # y2.l2 の係数
a12_l2 # y2 の方程式から
<- coeffs_eq2[lag2_coef_names[1]] # y1.l2 の係数
a21_l2 <- coeffs_eq2[lag2_coef_names[2]] # y2.l2 の係数
a22_l2
# A_2 行列を構成
# A_2 = | a11_l2 a12_l2 |
# | a21_l2 a22_l2 |
<- matrix(c(a11_l2, a12_l2, a21_l2, a22_l2), nrow = K_vars, ncol = K_vars, byrow = TRUE)
A2_matrix
cat("--- 作成した A_2 行列 ---\n")
print(A2_matrix)
cat("\n")
# 2期先の応答 (Y_2) の計算
# -----------------------------------------------------------
# Y_2 = A_1 * Y_1 + A_2 * Y_0
# Y_1 は Y1_response
# Y_0 は Y0_response
# A1_matrix は (K_vars x K_vars)
# Y1_response は (K_vars x 1)
<- A1_matrix %*% Y1_response
term1_Y2
# A2_matrix は (K_vars x K_vars)
# Y0_response は (K_vars x 1)
<- A2_matrix %*% Y0_response
term2_Y2
<- term1_Y2 + term2_Y2
Y2_response
cat("--- 2期先の応答 (Y2_response) ---\n")
rownames(Y2_response) <- var_names
print(Y2_response)
--- 作成した A_2 行列 ---
[,1] [,2]
[1,] 0.2085125 -0.08006986
[2,] -0.2844179 0.09857760
--- 2期先の応答 (Y2_response) ---
y1
y1 0.6523124
y2 0.1097366
関数irf の結果と比較します。
irf(var_model,
impulse = var_names[1], # y1 の誤差項にショック
response = var_names, # y1 と y2 の応答を見る
n.ahead = 2, # 2期先まで計算 (結果は0, 1, 2期目を含む)
ortho = TRUE, # 直交化インパルス応答
boot = FALSE, # ブートストラップ信頼区間は計算しない
cumulative = FALSE
)
Impulse response coefficients
$y1
y1 y2
[1,] 1.0191244 -0.1447915
[2,] 0.5200381 0.4117287
[3,] 0.6523124 0.1097366
一致しています。
以上です。