🎓 レベル:標準 | 重要度:A(必須)
📎 前提:定常性と自己相関 | 数理:確率過程(マルコフ連鎖・ポアソン過程)(統計)
要点(BLUF)
- AR()=いまの値を過去の自分 個の線形和で説明()。定常であるには係数が「特性根が単位円の外」の条件を満たす必要があります。
- MA()=いまの値を過去のショック 個の線形和で説明()。常に定常で、一意に同定するには反転可能性を課します。
- 指紋(定常性と自己相関):AR は PACF がラグ で切れ、MA は ACF がラグ で切れる。真の係数を仕込んだ擬似系列で、推定が係数を復元できることをコードで確かめます。
1. AR():過去の自分で説明する
自己回帰モデル AR() は、現在値を過去 期の自分自身の線形結合+ホワイトノイズで表します。
ラグ演算子 ()を使うと、左辺をひとつの多項式にまとめられます。
定常性条件:AR() が(弱)定常になるのは、**特性方程式 の根がすべて単位円の外()**にあるときです。AR(1) なら なので、。 ちょうどがランダムウォーク(単位根・非定常)でした(ランダムウォークと単位根)。直観は「過去への引きずられ方 が弱すぎず()なら、ショックの影響が時間とともに減衰し平均へ戻る」。AR(1) の自己相関は と幾何減衰し、PACF はラグ1で切れます(定常性と自己相関 で実証済み)。
コード①:AR(2) の係数を復元する
真の係数 を仕込んだ AR(2) を生成し、statsmodels の ARIMA(order=(2,0,0))( なので純粋な AR(2))で係数を推定します。推定値が真値に一致するか、また特性根が単位円の外(定常)かを数値で見ます。
import numpy as np
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.arima_process import arma_generate_sample
# 真の AR(2): y_t = 0.5 y_{t-1} - 0.3 y_{t-2} + ε_t
phi1_true, phi2_true = 0.5, -0.3
np.random.seed(0)
ar_poly = np.array([1, -phi1_true, -phi2_true]) # 1 - φ1 L - φ2 L^2
ma_poly = np.array([1.0])
y = arma_generate_sample(ar_poly, ma_poly, nsample=3000, scale=1.0)
res = ARIMA(y, order=(2, 0, 0), trend="c").fit()
phi1_hat = res.params[res.param_names.index("ar.L1")]
phi2_hat = res.params[res.param_names.index("ar.L2")]
print(f"{'係数':>6}{'真値':>10}{'推定値':>10}")
print(f"{'φ1':>6}{phi1_true:>10.3f}{phi1_hat:>10.3f}")
print(f"{'φ2':>6}{phi2_true:>10.3f}{phi2_hat:>10.3f}")
# 定常性チェック:特性根が単位円の外か
roots = res.arroots
print(f"特性根の絶対値 = {np.abs(roots).round(3)} (>1 なら定常)")
出力:
係数 真値 推定値
φ1 0.500 0.511
φ2 -0.300 -0.299
特性根の絶対値 = [1.83 1.83] (>1 なら定常)
出力の意味:推定値は と、仕込んだ真値 をほぼ正確に復元しました(誤差は推定の標準誤差の範囲)。arma_generate_sample に渡す係数は [1, -φ1, -φ2] の符号に注意——ラグ多項式 の係数だからです。特性根の絶対値は なので、この AR(2) は定常。シミュレーションなら真値が分かるので「ちゃんと当たっているか」を直接検証できます。
2. MA():過去のショックで説明する
移動平均モデル MA() は、現在値を過去 期のショック(ノイズ) の線形結合で表します。
MA はホワイトノイズの有限個の和なので、係数が何であっても常に定常です(平均・分散・自己共分散が時間に依らない)。そして記憶は 期で尽きる—— より離れた値とは共有するショックが無いので、自己共分散は より先で厳密に 0。これが「MA() は ACF がラグ で切れる」の正体です。
MA(1)()で自己共分散を直接計算すると、
なので自己相関は次の通り。ラグ1だけ非ゼロ、ラグ2以降はゼロです。
反転可能性(invertibility):実は MA(1) では と が同じ ACF を与えます( に を入れても同値)。つまり ACF だけでは が一意に決まりません。そこで** の根が単位円の外(MA(1) なら )という反転可能性**を課し、 の側を採用します。反転可能なら MA を と AR() に書き直せ(過去の観測値からショックを復元でき)、推定・予測が安定します。statsmodels は既定で反転可能な解を返します。
コード②:MA(1) の θ を復元し、ACF がラグ1で切れることを確認
真の を仕込んだ MA(1) を生成し、ARIMA(order=(0,0,1)) で を推定します。あわせて ACF を計算し、理論値 と一致すること・ラグ2以降がほぼ 0(=切れる)ことを確かめます。
import numpy as np
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.arima_process import arma_generate_sample
from statsmodels.tsa.stattools import acf
# 真の MA(1): y_t = ε_t + 0.6 ε_{t-1}
theta_true = 0.6
np.random.seed(1)
ar_poly = np.array([1.0])
ma_poly = np.array([1, theta_true])
y = arma_generate_sample(ar_poly, ma_poly, nsample=3000, scale=1.0)
res = ARIMA(y, order=(0, 0, 1), trend="c").fit()
theta_hat = res.params[res.param_names.index("ma.L1")]
print(f"θ 真値={theta_true:.3f} 推定値={theta_hat:.3f}")
# 理論 ACF: ρ1 = θ/(1+θ^2), ρk=0 (k>=2)
rho1_theory = theta_true / (1 + theta_true**2)
a = acf(y, nlags=5, fft=True)
print(f"理論 ρ1 = θ/(1+θ^2) = {rho1_theory:.3f}")
print(f"{'lag':>4}{'ACF推定':>10}")
for k in range(6):
print(f"{k:>4}{a[k]:>10.3f}")
出力:
θ 真値=0.600 推定値=0.588
理論 ρ1 = θ/(1+θ^2) = 0.441
lag ACF推定
0 1.000
1 0.432
2 -0.009
3 -0.001
4 0.008
5 0.008
出力の意味:推定 は真値 を復元。ACF はラグ1で ——理論 とほぼ一致し、ラグ2以降はすべてほぼ 0()。これが MA(1) の指紋「ACF がラグ1でストンと切れる」です。AR(1) の ACF が と尾を引いた(定常性と自己相関)のと対照的に、MA は記憶が有限なので ACF がぱつんと切れます。
3. AR と MA の指紋:ACF/PACF で見分ける
定常性と自己相関 の表を、AR/MA を主役にして再掲します。「切れる方が次数を教える」——AR は PACF、MA は ACF が次数で切れます。
| モデル | ACF | PACF |
|---|---|---|
| AR() | 緩やかに減衰(尾を引く) | ラグ で切れる |
| MA() | ラグ で切れる | 緩やかに減衰(尾を引く) |
AR(2)()と MA(1)()の ACF/PACF を並べて、この指紋を目で確かめます。
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib # 日本語ラベル用
from statsmodels.tsa.arima_process import arma_generate_sample
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
np.random.seed(2)
ar2 = arma_generate_sample(np.array([1, -0.5, 0.3]), np.array([1.0]), nsample=3000) # AR(2): φ1=0.5, φ2=-0.3
ma1 = arma_generate_sample(np.array([1.0]), np.array([1, 0.6]), nsample=3000) # MA(1): θ=0.6
fig, ax = plt.subplots(2, 2, figsize=(11, 7))
plot_acf(ar2, lags=12, ax=ax[0, 0]); ax[0, 0].set_title("AR(2) の ACF(緩やかに減衰)")
plot_pacf(ar2, lags=12, ax=ax[0, 1], method="ywm"); ax[0, 1].set_title("AR(2) の PACF(ラグ2で切れる)")
plot_acf(ma1, lags=12, ax=ax[1, 0]); ax[1, 0].set_title("MA(1) の ACF(ラグ1で切れる)")
plot_pacf(ma1, lags=12, ax=ax[1, 1], method="ywm"); ax[1, 1].set_title("MA(1) の PACF(緩やかに減衰)")
plt.tight_layout(); plt.show()
グラフの意味:上段 AR(2) は、左の ACF が徐々に減衰(尾を引く)、右の PACF がラグ2まで棒が立ち、ラグ3以降は信頼帯の中=0。下段 MA(1) は逆で、左の ACF がラグ1だけ立ってラグ2以降は0、右の PACF が尾を引きます。「ACF が切れたら MA、PACF が切れたら AR、切れた位置が次数」——次数の当てずっぽうの出発点になります。両方とも尾を引いて切れないなら、次節の ARMA を疑います(ARMA・ARIMAモデル)。
4. 数式の直観
- AR は「慣性」、MA は「ショックの尾」:AR() は過去の値を引きずる(一度ずれたら戻るのに時間がかかる)。MA() は過去のノイズを 期だけ引きずる(記憶が有限)。
- AR の定常性 = ショックが減衰すること: を解くと という MA() 表現になり、(根が単位円の外)なら と減衰します。これが「過去のショックの影響が消えていく=定常」の中身です。
- MA の反転可能性 = ショックを観測から復元できること: なら と AR() に書け、過去の から現在のショックを一意に逆算できます。これが推定・予測の安定につながります。
⚠️ よくある誤解
- 「AR の係数は何でもよい」ではない: が大きすぎ(特性根が単位円の内側)だと非定常。推定前に定常化(差分)を検討し、推定後は特性根を確認します。
- 「MA は ACF さえ合えば が決まる」ではない: と が同じ ACF を持つので、反転可能()な側に固定して初めて一意。
statsmodelsは反転可能解を返します。 - 「ACF と PACF を片方だけ見ればよい」ではない:AR/MA の判別には両方必要(ACF が切れる=MA、PACF が切れる=AR)。片方だけでは取り違えます。
- 「指紋は理論どおりくっきり出る」ではない:有限標本では信頼帯付近で揺れます。1本の山が帯を超えても、全体のパターンで判断します(多重比較で偶然超えるものは出ます)。
- AR/MA の符号規約に注意:AR は (プラス)、ラグ多項式は (マイナス)。生成時に係数の符号を間違えると別物になります(コード①参照)。
関連ノート
- 定常性と自己相関(ACF/PACF の指紋・AR(1) の幾何減衰)
- ランダムウォークと単位根( の単位根・差分による定常化)
- 第2章 ARIMA系モデル 目次
- ARMA・ARIMAモデル(AR と MA を統合し、差分 I を足した ARIMA・予測)
- 確率過程(マルコフ連鎖・ポアソン過程)(統計・定常過程とホワイトノイズの土台)
- 時系列分析・予測テキスト 全体目次