Rで偏自己相関関数

Rで 偏自己相関関数(Partial autocorrelation function) を試みます。

始めに AR(1) のサンプルデータを作成します。

seed <- 20250418
set.seed(seed)
n <- 200 # サンプルサイズ
phi1 <- 0.7 # AR(1)係数 |φ_1| < 1
noise_sd <- 1 # ノイズの標準偏差 σ_ε

# AR(1)プロセス: X_t = phi1 * X_{t-1} + epsilon_t
ar1_data <- numeric(n)

# 先頭のデータも定常分散から開始とする
# AR(1) プロセス(平均 0 と仮定)の分散 Var(X_t) は、時間(t)によらず一定の値 γ(0) をとる
# Var(X_t) = Var(φ_1 * X_{t-1} + ε_t) = φ_1^2 * Var(X_{t-1}) + Var(ε_t)
# ノイズ ε_t の分散を σ²_ε とする
# γ(0) = φ_1^2 * γ(0) + σ²_ε
# γ(0) - φ_1^2 * γ(0) = σ²_ε
# γ(0) * (1 - φ_1^2) = σ²_ε
# γ(0) = σ²_ε / (1 - φ_1^2)
# SD(X_t) = sqrt(γ(0)) = σ_ε / sqrt(1 - φ_1^2)
ar1_data[1] <- rnorm(1, mean = 0, sd = noise_sd / sqrt(1 - phi1^2))

for (t in 2:n) {
  ar1_data[t] <- phi1 * ar1_data[t - 1] + rnorm(1, mean = 0, sd = noise_sd)
}

plot(ar1_data, type = "l", main = "Generated AR(1) Data (phi=0.7)")
Figure 1

自己相関関数(ACF) を求める関数。

calculate_acf <- function(x, max_lag) {
  n <- length(x)

  x_mean <- mean(x)
  x_centered <- x - x_mean

  # 分散 (gamma(0)) の計算
  gamma0 <- sum(x_centered^2) / n

  acf_values <- numeric(max_lag + 1)
  acf_values[1] <- 1.0 # ACF(0) は常に 1

  # ラグ 1 から max_lag までのACFを計算
  for (h in 1:max_lag) {
    # 自己共分散 gamma(h) の計算
    gamma_h <- sum(x_centered[(h + 1):n] * x_centered[1:(n - h)]) / n
    acf_values[h + 1] <- gamma_h / gamma0 # ACF(h) = gamma(h) / gamma(0)
  }

  # ラグ0からmax_lagまでの値を返す (長さ max_lag + 1)
  return(acf_values)
}

偏自己相関関数(PACF) を求める関数。

calculate_pacf <- function(x, max_lag) {
  n <- length(x)

  # 始めに、必要なラグまでのACFを計算
  # ACFはラグ0からmax_lagまで必要 (長さは max_lag + 1)
  acf_vals <- calculate_acf(x, max_lag)

  pacf_vals <- numeric(max_lag) # 結果を格納するベクトル (ラグ1からmax_lagまで)

  # --- ラグ 1 の PACF ---
  # PACF(1) = ACF(1)
  pacf_vals[1] <- acf_vals[2] # acf_valsのインデックス2がラグ1に対応

  # --- ラグ 2 から max_lag までの PACF ---
  if (max_lag >= 2) {
    for (k in 2:max_lag) {
      # Yule-Walker方程式を解くための準備
      # Γ_k * φ_k = γ_k

      # 自己相関行列 Γ_k (k x k) を構築
      # Γ_k[i, j] = ρ(|i-j|) = acf_vals[abs(i - j) + 1]
      Gamma_k <- matrix(0, nrow = k, ncol = k)
      for (i in 1:k) {
        for (j in 1:k) {
          lag_index <- abs(i - j) + 1
          Gamma_k[i, j] <- acf_vals[lag_index]
        }
      }

      # 自己相関ベクトル γ_k (k x 1) を構築
      # γ_k = [ρ(1), ρ(2), ..., ρ(k)]^T = acf_vals[2:(k+1)]
      gamma_k_vec <- acf_vals[2:(k + 1)]

      #  Γ_k * φ_k = γ_k を解いて φ_k を求める
      # solve(A, b) は Ax = b の x を返す
      phi_k_solution <- solve(Gamma_k, gamma_k_vec)

      # PACF(k) は解 φ_k の最後の要素 φ_kk
      pacf_vals[k] <- phi_k_solution[k]
    }
  }

  # ラグ1からmax_lagまでの値を返す (長さ max_lag)
  names(pacf_vals) <- 1:max_lag # 結果にラグ番号の名前をつける
  return(pacf_vals)
}

サンプルデータの 偏自己相関関数 を求めます。

max_lag_to_calculate <- 20 # 計算する最大ラグ

# PACFを計算
(pacf_results <- calculate_pacf(ar1_data, max_lag_to_calculate))
          1           2           3           4           5           6 
 0.69237188 -0.11174151 -0.05143607  0.02472952 -0.01515109 -0.07934668 
          7           8           9          10          11          12 
-0.05351803 -0.11372046  0.09839197  0.04321378 -0.03823214 -0.02222230 
         13          14          15          16          17          18 
-0.03082981  0.02400196  0.03427041  0.06812720 -0.20009914 -0.01829678 
         19          20 
 0.02378457 -0.08653871 

95%信頼区間を求めます。

confidence_level <- 0.95
alpha <- 1 - confidence_level

# Zスコアを計算
z_score <- qnorm(1 - alpha / 2)

# 信頼区間の上限と下限を計算
(conf_limit_upper <- z_score / sqrt(n))
(conf_limit_lower <- -z_score / sqrt(n))
[1] 0.1385904
[1] -0.1385904

結果を可視化します。

plot(1:max_lag_to_calculate, pacf_results,
  type = "h", lwd = 2,
  ylim = c(-1, 1), xlab = "Lag", ylab = "PACF",
  main = "PACF for AR(1) Data"
)
abline(h = 0, col = "gray")
abline(h = c(conf_limit_upper, -conf_limit_upper), lty = 2, col = "blue")
Figure 2

Rの関数 pacf {stats} と比較します。

(pacf_builtin <- pacf(ar1_data, lag.max = max_lag_to_calculate, plot = FALSE))

Partial autocorrelations of series 'ar1_data', by lag

     1      2      3      4      5      6      7      8      9     10     11 
 0.692 -0.112 -0.051  0.025 -0.015 -0.079 -0.054 -0.114  0.098  0.043 -0.038 
    12     13     14     15     16     17     18     19     20 
-0.022 -0.031  0.024  0.034  0.068 -0.200 -0.018  0.024 -0.087 
unique(round(as.vector(pacf_builtin$acf) - pacf_results, 14))
[1] 0

一致しています。

以上です。