K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

ARIMA モデル

中級

04.6.1

ARIMA モデル

最終更新 2020-02-12 読了時間 3 分

ARIMA(AutoRegressive Integrated Moving Average)は、時系列を差分で平滑化しつつ自己回帰と移動平均を組み合わせて将来を予測する古典的モデルです。トレンドが緩やかで季節性の弱い系列に向きます。

まとめ
ARIMA(p, d, q) は、系列を d 回差分してトレンドを消し、その差分系列を「過去 p 期の値」と「過去 q 期の予測誤差」の線形結合で説明するモデルです。差分(I)がトレンドを、自己回帰(AR)が値の持続性を、移動平均(MA)がショックの余韻を担当する、と 3 つの役割を分けて覚えると次数の調整が迷わなくなります。このページでは、傾き 0.3 のトレンドに緩い波とノイズを足した 200 日の系列を 180 日で学習し、statsmodels の ARIMA(train, order=(2, 1, 1)) で残り 20 日を予測したうえで、残差の自己相関を plot_acf で診断します。読み終えると、order の 3 つの数が図のどこに効くかと、残差診断で何を見ればよいかが分かります。

AR 過程(ARIMA の自己回帰成分)と MA 過程(移動平均成分)を先に読むと、order の p と q が何を指すかがすぐにつかめます。

直感 #

毎日の売上が 1 日 0.3 ずつ右上がりに増えている系列を想像してください。そのまま「昨日と似た値になる」と予測すると、トレンドの分だけ毎日少しずつ外れ続けます。ARIMA はまず d=1 の差分で「今日 − 昨日」の変化量に置き換え、トレンドを定数に変えてしまいます。次に変化量の系列を、AR 項「直近 p 日の変化量が次の変化量に引き継がれる」と、MA 項「直近 q 日の予測の外れが次に補正として効く」で表します。最後に予測した変化量を前日の値に足し戻せば、元の水準 \(y_t\) の予測になります。差分を取りすぎるとノイズが膨らんで予測が不安定になるので、d はトレンドが消える最小の回数(たいてい 1)で止めるのがコツです。

何が起きているか(ステップで見る) #

コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。

見るポイント:差分はトレンドを消す道具。1 階差分で平均が一定の系列になり、ここに AR(2) と MA(1) を当てるのが order=(2, 1, 1)。取りすぎるとノイズが強調される。

式で書くと 3 つの項がどこにあるか #

1 階差分 \(\nabla y_t = y_t - y_{t-1}\) に対して、ARIMA(2, 1, 1) は

$$ \nabla y_t = c + \phi_1 \nabla y_{t-1} + \phi_2 \nabla y_{t-2} + \theta_1 \varepsilon_{t-1} + \varepsilon_t $$

と書けます。\(\phi_1, \phi_2\) が AR 係数で「直近 2 日の変化量をどれだけ引き継ぐか」、\(\theta_1\) が MA 係数で「前日の予測誤差 \(\varepsilon_{t-1}\) をどれだけ補正に使うか」、定数 \(c\) が差分後に残ったトレンドの平均的な傾きです。fit() はこの 4 つの係数とノイズの分散を最尤法で推定し、summary() にその値と AIC を表示します。

Python で学習と予測 #

次のコードは、1 日 0.3 の上昇に周期約 75 日の緩い波とノイズを足した 200 日の系列を作り、先頭 180 日で ARIMA(2, 1, 1) を学習して残り 20 日を予測します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import numpy as np
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA

# サンプル時系列(トレンド + ノイズ)
index = pd.date_range("2020-01-01", periods=200, freq="D")
signal = 0.3 * np.arange(200) + 10 * np.sin(np.arange(200) / 12)
noise = np.random.normal(scale=2.0, size=200)
series = pd.Series(signal + noise, index=index)

train = series[:180]
test = series[180:]

model = ARIMA(train, order=(2, 1, 1))
fitted = model.fit()

forecast = fitted.forecast(steps=len(test))
print(forecast.head())

実行結果の読み方 #

print(forecast.head()) には 2020 年 6 月 29 日からの 5 日分の予測値が並び、学習区間の末尾(0.3 × 179 + 波 ≈ 50 前後)から 1 日 0.3 程度ずつ増える値になります。test と並べて絶対誤差を取れば、最初の数日は 2 前後、20 日目に向けて徐々に広がるはずです。fitted.summary() を表示すると ar.L1・ar.L2・ma.L1 の係数と AIC が確認できます。

ハイパーパラメータと直感 #

パラメータ直感的な意味大きくすると
pどこまで過去の値を参照するか過去の揺らぎが影響し周期性を捉えやすいが、過剰にすると過学習へ
dトレンド除去の差分回数非定常を抑え安定するが、取りすぎはノイズを増やし予測が暴れがち
q誤差を何ステップ補正するか突発的な外乱の余韻を吸収できるが、過剰にすると遅れが発生

次数の決め方は、まず差分系列の ACF と PACF を眺めて p・q の候補を 2〜3 通り作り、それぞれを fit() して AIC が最小のものを選ぶ、という手順が一般的です。季節性のある系列には seasonal_order を指定できる SARIMAX を使います。

残差診断 #

学習がうまくいったかは、残差(実測 − 1 期先予測)に構造が残っていないかで判定します。次のコードは残差の時系列と自己相関(ACF)を左右に並べます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf

resid = fitted.resid.dropna()
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
axes[0].plot(resid)
axes[0].set_title("残差時系列")
plot_acf(resid, lags=30, ax=axes[1])
axes[1].set_title("残差の自己相関")
plt.show()

残差が白色雑音に近ければ、モデルが系列の構造をうまく捉えているサインです。逆に明確な自己相関が残っていれば、p や q を増やすか季節項を追加して再推定します。

使いどころと落とし穴 #

差分の回数は d=1 で十分なケースがほとんどで、d=2 は 1 次差分がまだ一方向に傾いているときだけにします。季節性が強い系列では ARIMA 単体では周期を学べないので、statsmodels の SARIMAX、Prophet、STL 分解と組み合わせた ARIMA のいずれかを検討してください。プロモーションや気温のような外部要因は exog 引数で説明変数として組み込めます。分散が水準に比例して広がる系列では、対数変換や Box-Cox で分散を均してから当てると RMSE が改善することが多いです。

まとめ #

ARIMA は d 回の差分で定常化した系列に AR(p) と MA(q) を組み合わせる予測モデルで、order=(2, 1, 1) のように 3 つの数で構成を指定します。p が過去の記憶、d がトレンド除去、q が外乱の吸収を担当し、残差の ACF が 95% 信頼帯に収まるまで調整します。次数選びは ACF・PACF で候補を絞って AIC で決め、季節性や外部変数が必要なら SARIMAX に進むのが安定した手順です。