LESSON

自己相関分析

「時系列データの最大の特徴は、過去の自分自身と相関があるということだ。」

田中VPoEがACFプロットを表示する。

「昨日の売上が高ければ今日も高い傾向がある。先週の同じ曜日と相関がある。この自己相関の構造を理解することが、ARIMAモデルの土台になる。」

自己相関(ACF)とは

自己相関(Autocorrelation Function)とは、時系列データとそのラグ(時間遅れ)との相関係数である。

import numpy as np
import pandas as pd
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.stattools import acf, pacf

# GROCERY Iの全店舗合計日次売上
grocery = train[train['family'] == 'GROCERY I'].groupby('date')['sales'].sum()

# ACFの計算
acf_values = acf(grocery, nlags=35)

# ラグごとの自己相関
for lag in [1, 7, 14, 28]:
    print(f"ラグ{lag:2d}日: ACF = {acf_values[lag]:.3f}")

# ラグ 1日: ACF = 0.85  ← 前日との相関が最も高い
# ラグ 7日: ACF = 0.90  ← 1週間前との相関が非常に高い(週次季節性)
# ラグ14日: ACF = 0.82  ← 2週間前とも高い
# ラグ28日: ACF = 0.80  ← 4週間前とも高い

ACFプロット

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# ACFプロット
plot_acf(grocery, lags=50, ax=axes[0])
axes[0].set_title('ACF(自己相関関数)')
axes[0].set_xlabel('ラグ(日)')

# PACFプロット
plot_pacf(grocery, lags=50, ax=axes[1], method='ywm')
axes[1].set_title('PACF(偏自己相関関数)')
axes[1].set_xlabel('ラグ(日)')

plt.tight_layout()
plt.show()

偏自己相関(PACF)とは

偏自己相関(Partial Autocorrelation Function)とは、中間のラグの影響を除いた、特定のラグとの純粋な相関である。

ACF:  Y(t) と Y(t-k) の相関(中間のラグの影響を含む)
PACF: Y(t) と Y(t-k) の相関(Y(t-1)...Y(t-k+1) の影響を除去)

ACFとPACFからARIMAパラメータを読み取る

ACFの挙動PACFの挙動モデル
緩やかに減衰ラグpで急にゼロAR(p)
ラグqで急にゼロ緩やかに減衰MA(q)
緩やかに減衰緩やかに減衰ARMA(p,q)

定常性検定

ARIMAモデルを適用するには、データが定常(平均・分散が時間に依存しない)である必要がある。

ADF検定(拡張ディッキー・フラー検定)

from statsmodels.tsa.stattools import adfuller

def adf_test(series, name=''):
    """ADF検定を実行し結果を表示"""
    result = adfuller(series.dropna(), autolag='AIC')
    print(f"=== ADF検定: {name} ===")
    print(f"検定統計量: {result[0]:.4f}")
    print(f"p値: {result[1]:.4f}")
    print(f"使用ラグ数: {result[2]}")
    print(f"観測数: {result[3]}")
    for key, value in result[4].items():
        print(f"  臨界値({key}): {value:.4f}")

    if result[1] < 0.05:
        print("→ 帰無仮説を棄却: 定常である")
    else:
        print("→ 帰無仮説を棄却できない: 非定常の可能性")
    print()

# 原系列のADF検定
adf_test(grocery, '原系列')

# 1次差分のADF検定
adf_test(grocery.diff().dropna(), '1次差分')

# 7日差分のADF検定(季節差分)
adf_test(grocery.diff(7).dropna(), '7日差分')

KPSS検定

ADF検定と相補的な検定。ADF検定とKPSS検定の両方を使うことで、より信頼性の高い判断ができる。

from statsmodels.tsa.stattools import kpss

def kpss_test(series, name=''):
    """KPSS検定を実行"""
    result = kpss(series.dropna(), regression='c', nlags='auto')
    print(f"=== KPSS検定: {name} ===")
    print(f"検定統計量: {result[0]:.4f}")
    print(f"p値: {result[1]:.4f}")
    if result[1] < 0.05:
        print("→ 帰無仮説を棄却: 非定常である")
    else:
        print("→ 帰無仮説を棄却できない: 定常である")
    print()

# ADF: 帰無仮説=非定常、KPSS: 帰無仮説=定常
# 両方の結果を合わせて判断する
# ADF棄却 & KPSS棄却しない → 定常
# ADF棄却しない & KPSS棄却 → 非定常
# 両方棄却 → トレンド定常の可能性
# 両方棄却しない → 判断が困難

差分による定常化

# 1次差分: トレンドを除去
diff1 = grocery.diff().dropna()

# 季節差分: 季節性を除去(7日周期)
diff7 = grocery.diff(7).dropna()

# 1次差分 + 季節差分: 両方を除去
diff1_7 = grocery.diff().diff(7).dropna()

# 各差分系列のACF/PACFを確認
fig, axes = plt.subplots(3, 2, figsize=(14, 12))
for i, (data, title) in enumerate([
    (diff1, '1次差分'),
    (diff7, '季節差分(7)'),
    (diff1_7, '1次+季節差分')
]):
    plot_acf(data, lags=35, ax=axes[i, 0])
    axes[i, 0].set_title(f'ACF: {title}')
    plot_pacf(data, lags=35, ax=axes[i, 1], method='ywm')
    axes[i, 1].set_title(f'PACF: {title}')
plt.tight_layout()
plt.show()

まとめ

項目ポイント
ACF時系列とそのラグとの相関。季節周期でスパイク
PACF中間ラグの影響を除いた純粋な相関
ADF検定定常性の検定。p < 0.05なら定常
差分非定常データを定常化する手法

チェックリスト

  • ACFとPACFの違いを説明できる
  • ACF/PACFプロットからARIMAのパラメータを読み取れる
  • ADF検定を実行し結果を解釈できる
  • 差分による定常化の方法を理解した

次のステップへ

自己相関と定常性の分析ができたところで、次は外部要因(祝日、石油価格、プロモーション)の分析に進もう。

推定読了時間: 30分