論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
ARIMAモデル
ARIMA (ARIMA(p,d,q))
自己回帰(AR)・差分(I)・移動平均(MA)を組み合わせた時系列予測の古典モデル。
時系列ARIMA(p,d,q)ARIMAARMA

🔖 キーワード索引 — 完全強化版

「ARIMA」を理解するうえで必要なキーワードを 10 件以上提示します。 各チップから対応セクションへ移動できます。

30 秒結論 文脈 直感 数式 記号読み解き 実値計算 Python 実装 落とし穴 関連手法 関連用語 グループ教材 概念マップ

💡 30秒で分かる結論

🍰 まずはやさしく

未来を予想する便利な道具です。

時間の流れに沿ったデータの変化を予測します。

人口がこれからどう変わるかを調べます。

このモデルの仕組みと使い方を学びます。

📖 包括的解説 — この概念を完全マスター

📍 学習の3ステップ

  1. 定義を理解する:この概念は何か? 数式や条件を確認
  2. 具体例を見る:実データ(SSDSE 等)で計算してみる
  3. 応用する:自分のデータに適用、 結果を解釈

🔧 Python実装パターン

① statsmodels で ARIMA 基本ワークフロー — 定常性検定→推定→予測→残差診断

🎯 解説: SSDSE-B-2026 の都道府県・年次データから時系列を構築し、 ARIMA(p,d,q) モデルで「人口の時間変動」をモデル化・予測する。
📥 入力例(SSDSE-B-2026 の 564 行を年度ごとに 47 都道府県分合計した全国の総人口、12 年度・万人) 年度 A1101(総人口の全国計, 万人) 2012 12758.9 2013 12741.4 … 2023 12435.3 …(全 12 行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import pandas as pd
import numpy as np
from statsmodels.tsa.statespace.sarimax import SARIMAX
from statsmodels.tsa.stattools import adfuller, kpss

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
ts = df.groupby('SSDSE-B-2026')['A1101'].sum() / 10000  ## 万人
ts.index = pd.to_datetime(ts.index, format='%Y')

## 1. 定常性検定
adf_result = adfuller(ts)
print(f'ADF: stat={adf_result[0]:.3f}, p={adf_result[1]:.3f}')
kpss_result = kpss(ts, nlags='auto')
print(f'KPSS: stat={kpss_result[0]:.3f}, p={kpss_result[1]:.3f}')

## 2. モデル推定
model = SARIMAX(ts, order=(1, 1, 1)).fit(disp=False)
print(model.summary())

## 3. 予測 + 95% CI
forecast = model.get_forecast(steps=3)
print(forecast.predicted_mean)
print(forecast.conf_int(alpha=0.05))

## 4. 残差診断
from statsmodels.stats.diagnostic import acorr_ljungbox
## 先頭の残差は差分できない 1 年目の水準そのもの(12,758.9)なので除いて検定する
lb = acorr_ljungbox(model.resid.iloc[1:], lags=[5], return_df=True)
print(lb)  ## p>0.05 で白色雑音 OK
📥 入力例: data/raw/SSDSE-B-2026.csv 全国計の総人口時系列 (2012-2023, 万人) y = [12758.9, 12741.4, 12723.8, …, 12435.3]
📤 実行例(実測): ADF: stat=0.269, p=0.976 KPSS: stat=0.632, p=0.020 SARIMAX Results ============================================================================== Dep. Variable: A1101 No. Observations: 12 Model: SARIMAX(1, 1, 1) Log Likelihood -43.565 Date: Wed, 23 Sep 2026 AIC 93.129 Time: 12:13:00 BIC 94.323 Sample: 01-01-2012 HQIC 92.377 - 01-01-2023 Covariance Type: opg ============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ ar.L1 0.9274 0.114 8.132 0.000 0.704 1.151 ma.L1 0.3464 0.315 1.100 0.271 -0.271 0.964 sigma2 117.1669 68.098 1.721 0.085 -16.303 250.637 =================================================================================== Ljung-Box (L1) (Q): 0.15 Jarque-Bera (JB): 0.42 Prob(Q): 0.70 Prob(JB): 0.81 Heteroskedasticity (H): 6.93 Skew: -0.09 Prob(H) (two-sided): 0.09 Kurtosis: 2.05 =================================================================================== Warnings: [1] Covariance matrix calculated using the outer product of gradients (complex-step). 2024-01-01 12376.228764 2025-01-01 12321.448144 2026-01-01 12270.646493 Freq: YS-JAN, Name: predicted_mean, dtype: float64 lower A1101 upper A1101 2024-01-01 12355.013398 12397.444130 2025-01-01 12268.749931 12374.146357 2026-01-01 12180.369223 12360.923762 lb_stat lb_pvalue 5 2.975297 0.703794
💬 読み方: ADF は p=0.976 で単位根を棄却できず、KPSS は p=0.020 で「定常」を棄却するので、2 つの検定はそろって「差分が要る(d≥1)」を支持している。ARIMA(1,1,1) では ar.L1=0.927 が有意だが、ma.L1=0.346 は p=0.271 で効いていない。予測は 2024 年 12,376.2 万人 → 2026 年 12,270.6 万人と年 50 万人強のペースで減り、95% 区間の半幅は 1 年先の約 21 万人から 3 年先の約 90 万人へ広がる。残差の Ljung-Box は、先頭(差分できない 2012 年の水準 12,758.9 がそのまま入る)を除いて p=0.704 で自己相関は見つからないが、11 点では検定の力そのものが弱い。

② pmdarima の auto_arima — 自動次数選択

🎯 解説: pmdarima.auto_arima で、① の全国計 ts について差分の階数 d を ADF 検定で決め、p・q を 0〜3 の範囲で AIC が小さくなる方向へ段階的に探す(seasonal=False、trace=True で探索過程も表示)。

📥 入力例: ① で作った ts(全国計の総人口・万人、2012〜2023 年の年次 12 点)。2012 年 12,758.9 → 2023 年 12,435.3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import pmdarima as pm

## AIC を最小化する (p,d,q) を自動探索
auto = pm.auto_arima(ts,
                     start_p=0, max_p=3,
                     start_q=0, max_q=3,
                     d=None,      ## 自動で決める
                     seasonal=False,
                     test='adf',
                     trace=True,    ## 探索過程を表示
                     stepwise=True)
print(auto.summary())

## SARIMA(月次データ用)
## monthly_ts = ... 
## auto_s = pm.auto_arima(monthly_ts, seasonal=True, m=12, max_P=2, max_Q=2)
📤 実行例(実測):
Performing stepwise search to minimize aic
 ARIMA(0,2,0)(0,0,0)[0] intercept   : AIC=79.666, Time=0.00 sec
 ARIMA(1,2,0)(0,0,0)[0] intercept   : AIC=81.545, Time=0.00 sec
 ARIMA(0,2,1)(0,0,0)[0] intercept   : AIC=81.427, Time=0.00 sec
 ARIMA(0,2,0)(0,0,0)[0]             : AIC=79.102, Time=0.00 sec
 ARIMA(1,2,1)(0,0,0)[0] intercept   : AIC=82.884, Time=0.01 sec

Best model:  ARIMA(0,2,0)(0,0,0)[0]          
Total fit time: 0.025 seconds
                               SARIMAX Results                                
==============================================================================
Dep. Variable:                      y   No. Observations:                   12
Model:               SARIMAX(0, 2, 0)   Log Likelihood                 -38.551
Date:                Wed, 23 Sep 2026   AIC                             79.102
Time:                        12:12:10   BIC                             79.404
Sample:                    01-01-2012   HQIC                            78.770
                         - 01-01-2023                                         
Covariance Type:                  opg                                         
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
sigma2       130.6218     55.247      2.364      0.018      22.339     238.905
===================================================================================
Ljung-Box (L1) (Q):                   0.19   Jarque-Bera (JB):                 0.80
Prob(Q):                              0.66   Prob(JB):                         0.67
Heteroskedasticity (H):               6.88   Skew:                            -0.62
Prob(H) (two-sided):                  0.15   Kurtosis:                         2.39
===================================================================================

Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).

💬 読み方: ADF 検定が 1 階差分でも単位根を棄却できなかったため d=2 になり、探索した 5 候補のうち定数なしの ARIMA(0,2,0) が AIC=79.102 で選ばれた。これは「減少ペースの変化がランダムウォークする」モデルで、AR も MA も入っていない。① の ARIMA(1,1,1) の AIC 93.129 より小さく見えるが、差分の階数が違うモデルは尤度を計算する対象の系列が違うので、AIC をそのまま比べてはいけない。12 点では d=2 の判定自体も揺れやすい。

③ scipy.signal で周波数解析(季節性検出の前準備)

🎯 解説: scipy.signal.periodogram で ts のパワースペクトルを計算し、周波数 0(平均)を除いて最も強い周波数の逆数を「卓越周期」として表示する。季節周期を探す前準備。

📥 入力例: ① の ts(年次 12 点)。fs=1.0 なので周期の単位は「年」。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from scipy import signal
from statsmodels.tsa.seasonal import seasonal_decompose, STL

## ペリオドグラム(FFT ベースで季節周期を検出)
freqs, psd = signal.periodogram(ts.values, fs=1.0)
peak_freq = freqs[np.argmax(psd[1:])+1]
print(f'卓越周期: {1/peak_freq:.1f} 単位')

## STL 分解(trend + seasonal + residual)— 月次以上のデータで
## stl = STL(ts, seasonal=13).fit()
## stl.plot()
📤 実行例(実測):
卓越周期: 12.0 単位

💬 読み方: 卓越周期 12.0 は系列の長さ 12 年そのもので、periodogram が拾える最も低い周波数 1/12 にパワーが集まっただけ。全国人口は単調に減り続けているので、トレンドが「1 周期 12 年の波」に見えているのであって、季節性ではない。周期を探すなら先に差分や回帰でトレンドを除き、そもそも年次データには月の季節周期が無いことも押さえておく。

④ Prophet — Facebook の時系列ライブラリ

🎯 解説: Prophet に ① の ts を ds(日付)・y(値)の表にして渡し、年・週・日の季節性を切ったトレンドだけのモデルで 3 期先を予測する。最後の plot_components は成分の図を描く。

📥 入力例: df_p = ① の ts を表にしたもの(ds = 2012-01-01〜2023-01-01、y = 12,758.9〜12,435.3 万人の 12 行)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from prophet import Prophet

df_p = pd.DataFrame({'ds': ts.index, 'y': ts.values})
m = Prophet(yearly_seasonality=False, weekly_seasonality=False, daily_seasonality=False)
m.fit(df_p)

future = m.make_future_dataframe(periods=3, freq='Y')
fcst = m.predict(future)
print(fcst[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(3))

## トレンドと季節成分を別々に可視化
m.plot_components(fcst)
📤 実行例(イメージ・未実測:prophet が手元に無く、 この値を再現して確かめられていないため):
           ds          yhat    yhat_lower    yhat_upper
12 2023-12-31  12375.546993  12369.967133  12381.631819
13 2024-12-31  12316.103577  12299.034162  12334.249328
14 2025-12-31  12256.822575  12222.640948  12291.764345

💬 読み方: freq='Y' は年末の日付を作るので予測行の ds は 2023-12-31・2024-12-31・2025-12-31 と出るが、学習データが各年 1 月 1 日なので中身は 2024〜2026 年の予測。この出力例では yhat が 12,375.5 → 12,316.1 → 12,256.8 万人と年約 59 万人ずつ減り、① の ARIMA(1,1,1)(12,376.2 → 12,270.6)とほぼ同じ水準になる。yhat_lower・yhat_upper はトレンドの不確かさをサンプリングで作るため、実行するたびに小数点以下が変わる。

💡 30 秒で分かる結論 — 完全強化版

📍 あなたが今見ているもの

🍰 まずはやさしく

データの傾向を読むための手法です。

過去の動きから未来を予測するために使います。

都道府県の人口の変化を分析します。

この用語が分析の中でどう使われるかを見ます。

論文中に 「ARIMAモデル」として登場する用語。

ARIMAモデル とは:自己回帰(AR)・差分(I)・移動平均(MA)を組み合わせた時系列予測の古典モデル。

📍 文脈ボックス — あなたが今見ているもの(完全強化版)

このセクションは「ARIMA」を扱う 用語ページ です。 統計データ分析コンペティション(2026)の再現教材における中核用語のひとつで、北海道の人口 A1101 の年次推移(2012-2023)に ARIMA を適用 という観点で SSDSE-B-2026(47 都道府県 × 複数年 × 100 超列)に紐づけられます。

位置づけ:相関・線形回帰・仮説検定 といった基礎用語群と並列であり、応用としては 内生性・IV・DID・クラスタリング 等へ繋がります。

🎨 直感で掴む — 完全強化版

🍰 まずはやさしく

データを分析するための眼鏡のようなものです。

隠れたパターンを見つけ出すために使います。

地域の人口の増え方を詳しく観察します。

この手法がうまくいく例と失敗する例を考えます。

ARIMA を一言でいえば「北海道の人口 A1101 の年次推移(2012-2023)に ARIMA を適用」。 47 都道府県という小さな母集団でも、 SSDSE-B-2026 の A1101 列に注目すると、 大都市圏と地方の差・人口規模に伴う相対比較など、 様々なパターンが見えてきます。

比喩でいうと、 ARIMA はデータ分析の「眼鏡」のようなもの。 同じデータでも眼鏡を変えれば、 平均(中心)・分散(ばらつき)・相関(連動)・因果(影響)と、 異なる情報が浮かび上がります。 SSDSE-B-2026 を題材に、 この眼鏡をかけてみるのが本ページの狙いです。

🎨 補講:ARIMA が「効くケース・効かないケース」を SSDSE で検証

ARIMA は万能ではありません。 SSDSE-B-2026 を題材に、 ARIMA が良く効くケースと、 失敗するケースを並べて検証します。 「いつ使うべきで、 いつ別の手法に切り替えるか」を体感で覚えてもらうのが目的。

📊 ケース 1:滑らかな人口時系列(東京)→ ARIMA OK

東京の人口は緩やかなトレンド + 微小ノイズ。 ARIMA(1,1,1) で MAPE 0.3% 程度の高精度が出る。 構造変化(コロナ)も振幅が小さいため吸収可能。

📊 ケース 2:急変する出生数 → ARIMA は遅れる

出生数は近年急減(少子化加速)。 ARIMA は「過去の平均的なペース」で予測するため、 急変期に過大評価しがち。 外生変数(死亡数 A4200)を SARIMAX で追加するのが定石。

🐍 Python 実装 15:東京の出生数を ARIMA vs SARIMAX で比較

🎯 このコードでやること:東京都の出生数(A4101)を ARIMA 単体と、 死亡数(A4200)を外生変数に加えた SARIMAX で予測し、 MAE を比較する。

📥 入力データ:tokyo の A4101(出生数)と A4200(死亡数)。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
tokyo = df[df['pref'] == '東京都'].sort_values('year').set_index('year')

# 推定は万人単位で行う(人単位のままだと最適化が初期値付近で止まり、係数が別物になる)
y = tokyo['A4101'] / 10000     # 出生数(万人)
x = tokyo[['A4200']] / 10000   # 死亡数(万人)

test = y.index[-5:]
err_a, err_x = [], []
for yr in test:
    ty, tx = y.loc[:yr-1], x.loc[:yr-1]
    err_a.append(y.loc[yr] - ARIMA(ty, order=(1,1,1)).fit().forecast(1).iloc[0])
    err_x.append(y.loc[yr] - SARIMAX(ty, order=(1,1,1), exog=tx).fit(disp=False).forecast(1, exog=x.loc[[yr]]).iloc[0])
print(f"ARIMA   MAE = {np.mean(np.abs(err_a)) * 10000:,.0f} 人")
print(f"SARIMAX MAE = {np.mean(np.abs(err_x)) * 10000:,.0f} 人")

📤 実行すると次の出力が得られる:

ARIMA MAE = 2,218 人 SARIMAX MAE = 2,962 人

💬 結果の読み方:出生数・死亡数を万人単位にそろえて推定すると、死亡数を外生変数に加えた SARIMAX の MAE は 2,962 人で、ARIMA 単体の 2,218 人より約 34% 大きくむしろ悪化した。東京の出生数は 2015 年の 113,194 人から 2023 年の 86,348 人へ減り続ける一方、死亡数は 2021 年の 127,649 人から 2022 年に 139,264 人へ跳ねており、出生と直接関係しないこうした動きが、外生変数を通して出生の予測に入り込む。12 点の系列では外生変数の係数も不安定で、さらに「未来の死亡数」自体を予測しないと使えないという運用上の難点もある。

📝 より正確な分析:実データ (東京都, 出生数 A4101 を死亡数 A4200 で説明, 万人単位で推定, 直近 5 年 walk-forward) で再計算すると、 ARIMA MAE=2,218 人、 SARIMAX(+死亡数) MAE=2,962 人でSARIMAX の方が誤差が大きい。 わずか 12 点の系列に外生変数を足すと自由度を消費し、 かえって予測が不安定になる典型例。 外生変数の有効性は必ず検証データで確認し、 改善が見られない場合はより単純な ARIMA を採るのが妥当。

📊 ケース 3:構造変化(コロナ) → 介入変数で対処

2020〜2022 のコロナ期は東京人口が一時減少。 ARIMA は構造変化を吸収しきれず、 残差が偏る。 「2020-2022 に 1 を立てる dummy」を SARIMAX の exog に入れると吸収できる。

🐍 Python 実装 16:介入変数(コロナダミー)で構造変化を吸収

🎯 このコードでやること:東京人口に「2020-2022 期間ダミー」を外生変数として加え、 コロナ影響を明示的にモデル化。

📥 入力データ:tokyo シリーズ + コロナ期間ダミー。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
from statsmodels.tsa.statespace.sarimax import SARIMAX

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101']
# 万人単位にそろえる(人単位のままだと最適化が初期値から動かず、covid 係数が初期値のまま出てくる)
tokyo = tokyo / 10000

# コロナ期間ダミー(2020-2022 で 1、 その他 0)
covid = pd.Series((tokyo.index >= 2020) & (tokyo.index <= 2022), index=tokyo.index, name='covid').astype(int)

m = SARIMAX(tokyo, order=(1,1,1), exog=covid).fit(disp=False)
print(m.summary().tables[1])
print(f"covid 係数 = {m.params['covid'] * 10000:,.0f} 人(2020-2022 の水準のずれ)")

📤 実行すると次の出力が得られる:

============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ covid 1.3494 3.596 0.375 0.707 -5.698 8.397 ar.L1 0.7500 0.417 1.796 0.072 -0.068 1.568 ma.L1 0.9993 326.630 0.003 0.998 -639.184 641.182 sigma2 8.9476 2922.421 0.003 0.998 -5718.892 5736.788 ============================================================================== covid 係数 = 13,494 人(2020-2022 の水準のずれ)

💬 結果の読み方:covid 係数は +1.35 万人(13,494 人)で、p=0.707、95% 区間 −5.70〜8.40 万人と 0 を大きくまたぐ。d=1 のモデルに入れたダミーは「2020〜2022 年の水準のずれ」を表すが、12 点・ダミー 3 年ではずれの向きすら決められない。ma.L1=0.9993 が可逆性の境界に張り付き、標準誤差が 326.6 と発散しているのも、点の数に対してパラメータが多すぎるしるし。人単位のまま当てると covid 係数が初期値 −3,703 から動かず、標準誤差 3.8e-09 という「精密すぎる」値が出るので、桁をそろえてから推定する。

⚠️ ケース別の選び方

🎨 補講:ARIMA の歴史と Box-Jenkins 法

ARIMA は 1970 年に George Box と Gwilym Jenkins が著書 "Time Series Analysis: Forecasting and Control" で体系化した手法です。 「Box-Jenkins 法」と呼ばれる 4 ステップが今でも実務の標準フローです。

Step名称やることSSDSE での例
1Identification(同定)定常性確認 + ACF/PACF で次数候補東京人口 → d=1 候補、 ACF/PACF から (p, q) 候補
2Estimation(推定)最尤推定で係数算出ARIMA(1,1,1) 学習、 AR=0.69, MA=1.00(境界に張り付き)
3Diagnostic(診断)残差の自己相関を Ljung-Box で検定沖縄モデル p=0.96(ラグ 5)→ OK
4Forecasting(予測)未来予測 + 信頼区間沖縄 5 年先 1,464,030 ± 32,602

50 年以上前の手法ですが、 現代の auto_arima や Prophet も骨格はこの 4 ステップに従います。 教科書的に古い印象がありますが、 「定常性 → 残差診断 → 信頼区間」という思考の枠組みは時系列分析の 共通言語として今も生きています。

📚 関連書籍(Further Reading)

🎨 概念図で押さえる

ARIMA の3 要素 (p,d,q) と差分の効果を、 3 点の SVG で把握する。

図1 ARIMA(p,d,q) の役割分担

ARIMA要素

AR=過去値の重ね合わせ、 I=差分でトレンド除去、 MA=過去誤差を補正。

図2 差分前後の系列イメージ

差分の効果

トレンドのある系列を 1 階差分すると平均が一定に → ARMA を適用可能。

図3 ACF/PACF による次数の見方

ACF/PACFパターン

ACF がゆっくり減衰し PACF が lag1 のみ → AR(1)。 逆パターンは MA。

📝 理解度チェック

  1. ARIMA(p,d,q) の d は何回差分を取るかを指定する。 d=1 でも非定常なら? (答:d=2 を検討)
  2. ARIMA は定常な系列にしか直接適用できない。 トレンドがあれば最初に何をする? (答:差分を取る)
  3. 季節性のある月次データには ARIMA より何を使うべき? (答:SARIMA)
  4. AIC が小さくても、 残差に自己相関が残っている場合は? (答:モデル不十分→次数を見直す)
  5. ARIMA で長期予測の信頼区間はどう変化する? (答:予測ホライズンが伸びるほど急速に広がる)

🎨 概念図で押さえる(ARIMA を視覚で理解)

ARIMA は AR(自己回帰)・I(差分)・MA(移動平均)の 3 要素から時系列を予測するモデルです。 以下 3 点の概念図で「差分による定常化」「ACF/PACF 形状からの次数選定」「予測区間の発散」を視覚的に整理します。

図A: I(差分)の効果 — 非定常から定常へ

原系列 vs 1 階差分系列 原系列(トレンドあり) 平均が時間とともに上昇 → 非定常 1 階差分 y_t - y_{t-1} 平均=0 近傍を振動 → 定常 d=1

→ ARIMA の "I"(積分;実は差分)は、 トレンドを取り除いて系列を定常化する操作です。 原系列が右肩上がりでも、 隣接時点の差を取れば変化量は平均ゼロ周りで安定し、 AR/MA モデルが適用可能になります。 差分次数 d は ADF 検定で 0.05 未満を達成する最小値を選びます(通常 d=0,1,2)。

図B: ACF / PACF パターンによる次数 (p, q) の同定

AR(p) vs MA(q) — ACF/PACF の見分け方 AR(2) 系列 ACF 減衰 (tails off) PACF lag 2 で切断 → p=2 MA(1) 系列 ACF lag 1 で切断 → q=1 PACF 減衰 (tails off)

→ AR(p) は PACF が lag p で切断、 ACF が減衰。 MA(q) は ACF が lag q で切断、 PACF が減衰。 この対称性が ARMA 次数同定の核心です。 ARIMA(p,d,q) では、 まず d 階差分で定常化した後、 残差の ACF/PACF を観察して p, q を決定します。 実務では auto_arima 等で AIC/BIC 最小化を行うのが定石です。

図C: 予測区間の発散と季節 ARIMA

ARIMA 予測 — 点予測と 95% 信頼区間 予測開始 観測 (in-sample) 点予測 + 95% CI(時間とともに発散) y t

→ ARIMA の点予測(赤実線)は学習区間の最終値からトレンドを外挿しますが、 95% 信頼区間(薄赤)はホライズンが伸びるほど急速に拡大します。 これは将来のショックの分散が累積するため理論的に避けられません。 長期予測の信頼性は限定的であり、 季節性(年周期・週周期)が強いデータには SARIMA(p,d,q)(P,D,Q)s を使うのが標準的選択です。

📐 数式または定義 — 完全強化版

🍰 まずはやさしく

3つの計算方法を組み合わせたモデルです。

データの変動を数式で表すために使います。

人口の推移を数字でモデル化します。

数式の中にある記号の意味を詳しく解説します。

ARIMA の代表的な定義式は次のとおりです。

$$ \phi(L)(1-L)^d y_t = \theta(L)\, \varepsilon_t $$

ここで使われる記号や演算の意味は次節で言葉に翻訳します。

arima の定義や代表的な数式を以下に示す。 数式の各記号の意味は次節で言葉に翻訳する。

arima は文脈に応じて複数の定式化があるが、 教育目的では最も基本的な形を抑えることが重要。 具体的な値での計算例は後続セクションを参照。

$$\text{arima}: f(\mathbf{X}, \boldsymbol{\theta}) \to y$$

記号の対応はこうです。 $y_t$ は時点 $t$ の観測値(本ページなら 47 都道府県の年次人口)、 $\varepsilon_t$ はその時点で新しく入ってきたショック(ホワイトノイズ)。 $L$(または $B$)はラグ演算子で、 $L y_t = y_{t-1}$、 $L^2 y_t = y_{t-2}$ と 1 期ずつ過去へずらす記号です。 $(1-L)^d$ は $d$ 階の差分で、 $d=1$ なら $y_t - y_{t-1}$=前年差。 $\phi(L)$ は AR 部分の多項式(過去の値をどう引きずるか)、 $\theta(L)$ は MA 部分の多項式(過去のショックをどう引きずるか)です。 ARIMA(p,d,q) の 3 つの数字は、 順に $\phi$ の次数・差分の回数・$\theta$ の次数を指します。

🔬 数式を言葉で読み解く — 完全強化版

数式の各記号を、日本語の意味に変換します。

🔬 深掘り:ARIMA を「分解 + 数値 + コード」で完全理解する

ARIMA(AutoRegressive Integrated Moving Average)は AR (自己回帰) + I (差分積分) + MA (移動平均) の合成です。 ここでは SSDSE-B-2026 の都道府県人口時系列を題材に、 各構成要素を切り分けて、 実数値・実コードで深く解剖します。

🎨 直感:ARIMA は「過去の自分」と「過去の予測誤差」で未来を作る

要素意味SSDSE 人口時系列での例
AR(p)過去 $p$ 期の自分の値で予測東京の今年人口 ≈ 0.95 × 昨年人口 + ...
I(d)$d$ 階差分で定常化人口は増加トレンドあり → 1 階差分(前年比)で定常化
MA(q)過去 $q$ 期の予測誤差を取り込む「去年の予測ハズレ」を補正に反映
季節 S周期性(年/月/週)SSDSE は年次のみ → 季節性なし、 月次データならあり

📐 数式:ARIMA(p, d, q) の一般形

$$\phi(B)\, (1 - B)^d\, y_t = \theta(B)\, \varepsilon_t$$

$$\phi(B) = 1 - \phi_1 B - \phi_2 B^2 - \dots - \phi_p B^p, \quad \theta(B) = 1 + \theta_1 B + \theta_2 B^2 + \dots + \theta_q B^q$$

🔬 数式を言葉で読み解く

🧮 実値で計算:東京都人口の AR(1) 係数を手計算

AR(1):$y_t = \phi_1 \cdot y_{t-1} + c + \varepsilon_t$ で、 $\phi_1$ は ラグ 1 の自己相関係数に近似されます。

東京都人口(万人)抜粋: 2023: 1408.6 2022: 1403.8 2021: 1401.0 2020: 1404.8 2019: 1400.7 1 階差分(前年比): d_2023 = 1408.6 - 1403.8 = 4.8 d_2022 = 1403.8 - 1401.0 = 2.8 d_2021 = 1401.0 - 1404.8 = -3.8 d_2020 = 1404.8 - 1400.7 = 4.1 差分後は小さな値で振動 → 定常化 OK(d=1 が妥当)

🐍 Python 実装 3:東京都人口で ARIMA(1,1,1) を完全実装

🎯 このコードでやること:SSDSE-B-2026 の東京都人口時系列を読み込み、 ARIMA(1,1,1) を学習、 今後 3 年を予測する。

📥 入力データ:SSDSE-B-2026.csv の Prefecture=東京都, A1101 (総人口)。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})

# 東京都の総人口だけ抽出、 年で昇順に並べ、万人単位にする
# (人単位のままだと最適化が初期値付近で止まり、係数も予測も別物になる)
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101'] / 10000

# ARIMA(p=1, d=1, q=1) を学習
model = ARIMA(tokyo, order=(1, 1, 1)).fit()
print(model.summary().tables[1])  # 係数表

# 今後 3 年(2024, 2025, 2026)を予測(万人)
fc = model.forecast(steps=3)
fc.index = [2024, 2025, 2026]   # 年の整数インデックスは予測に引き継がれないので付け直す
print(fc.round(2))

📤 実行すると次の出力が得られる:

============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ ar.L1 0.6919 0.412 1.679 0.093 -0.116 1.499 ma.L1 0.9983 75.765 0.013 0.989 -147.498 149.495 sigma2 10.7387 815.806 0.013 0.989 -1588.212 1609.689 ============================================================================== 2024 1408.95 2025 1409.19 2026 1409.35 Name: predicted_mean, dtype: float64

💬 結果の読み方:万人単位で推定すると ar.L1=0.692(p=0.093)で 5% 水準では有意にならず、ma.L1=0.998 は可逆性の境界 1 に張り付いて標準誤差 75.8、95% 区間 −147〜149 と何も決まっていない。MA 係数がほぼ 1 というのは「差分を取りすぎた」ときのしるしで、12 点の東京人口では ARIMA(1,1,1) はパラメータが余っている。予測は 2024 年 1,408.95 万人 → 2026 年 1,409.35 万人と 2023 年実績 1,408.6 万人からほぼ横ばいで、2012〜2019 年の年 7〜13 万人の増加ではなく、2020 年以降の頭打ちを延ばした形になる。

🐍 Python 実装 4:ACF / PACF プロットで (p, q) の見当をつける

🎯 このコードでやること:東京都人口の 1 階差分を取り、 自己相関 ACF と偏自己相関 PACF を計算して、 ARIMA の (p, q) 次数を経験則で推定する。

📥 入力データ:上記 tokyo シリーズ。

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
from statsmodels.tsa.stattools import acf, pacf

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101']

# 1 階差分
diff = tokyo.diff().dropna()

# ACF / PACF を 5 ラグ分計算
print("ACF :", acf(diff, nlags=5).round(3))
print("PACF:", pacf(diff, nlags=5).round(3))

📤 実行すると次の出力が得られる:

ACF : [ 1. 0.656 0.187 -0.112 -0.298 -0.377] PACF: [ 1. 0.722 -0.612 0.072 -0.586 -0.161]

💬 結果の読み方:ACF はラグ 1 で 0.656 と大きく、ラグ 2 で 0.187 に落ちてから負に転じる。PACF はラグ 1 が 0.722、ラグ 2 が −0.612 と大きく、ラグ 1 だけで切れる AR(1) の形ではなく AR(2) 的にも見える。ただし差分後の点は 11 個しかなく、95% の目安 ±1.96/√11 ≈ ±0.59 をわずかに超える値ばかりなので、ACF/PACF だけで次数を決めず、次の AIC グリッドで候補を絞る。

🐍 Python 実装 5:AIC で (p, d, q) を grid search

🎯 このコードでやること:東京都人口に対し、 (p, d, q) を 0〜2 で総当たり、 AIC 最小のモデルを選ぶ。 pmdarima.auto_arima の代替実装。

📥 入力データ:tokyo シリーズ。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
# 万人単位(人単位のままだと多くの候補で最適化が止まり、AIC の順位が崩れる)
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101'] / 10000

results = []
for p, d, q in itertools.product(range(3), range(2), range(3)):
    try:
        m = ARIMA(tokyo, order=(p, d, q)).fit()
        results.append((p, d, q, round(float(m.aic), 2)))
    except Exception:
        pass

results.sort(key=lambda r: r[3])
print("Top 5 by AIC (p, d, q, AIC):")
for r in results[:5]: print(r)

📤 実行すると次の出力が得られる:

Top 5 by AIC (p, d, q, AIC): (1, 1, 1, 67.42) (1, 1, 0, 67.62) (1, 1, 2, 68.62) (2, 1, 1, 69.0) (0, 1, 2, 69.09)

💬 結果の読み方:AIC 最小は ARIMA(1,1,1) の 67.42 で、2 位の (1,1,0) は 67.62 と差は 0.20 しかない。上位 5 候補はすべて d=1 で、d=0 のモデルは入ってこない。(1,1,1) は前のブロックで MA 係数が境界に張り付いていたので、差が 2 未満なら MA 項の無い (1,1,0) を選ぶほうが安全。AIC の値は万人単位の系列に対するもので、人単位で推定した AIC とは 2×観測数×ln(10000) だけずれるため、単位の違うモデルどうしを比べてはいけない。

🐍 Python 実装 6:定常性検定(ADF テスト)

🎯 このコードでやること:東京都人口の元系列と 1 階差分後で ADF(拡張ディッキー・フラー)検定を実行し、 「何階差分すれば定常か」を統計的に決める。

📥 入力データ:tokyo シリーズ(元 + 1 階差分)。

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
from statsmodels.tsa.stattools import adfuller

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101']

# 元系列
stat0, p0 = adfuller(tokyo)[:2]
# 1 階差分後
stat1, p1 = adfuller(tokyo.diff().dropna())[:2]
print(f"元系列    : ADF 統計量 = {stat0:.3f}, p 値 = {p0:.4f}")
print(f"1 階差分後: ADF 統計量 = {stat1:.3f}, p 値 = {p1:.4f}")

📤 実行すると次の出力が得られる:

元系列 : ADF 統計量 = 0.605, p 値 = 0.9877 1 階差分後: ADF 統計量 = -3.047, p 値 = 0.0307

💬 結果の読み方:元系列は p=0.99 で「非定常(単位根あり)」を棄却できず → 差分が必要。 1 階差分後は p=0.03 で定常と判定。 → d = 1 が適切と確定。 ADF は ARIMA 設計の第一歩。

⚠️ 落とし穴(ARIMA 深掘り)

🌐 関連手法・派生(ARIMA 周辺)

🔬 補講:ARIMA の予測精度をどう評価するか

モデルを「作って終わり」では実務にならない。 時系列モデルは walk-forward validation(時間順検証)で精度を測ります。 ホールドアウトや k-fold CV では未来情報のリークが起きるため不可。

📐 数式:時系列向け評価指標

$$\text{MAE} = \frac{1}{n}\sum_t |y_t - \hat y_t|, \quad \text{RMSE} = \sqrt{\frac{1}{n}\sum_t (y_t - \hat y_t)^2}, \quad \text{MAPE} = \frac{100}{n}\sum_t \left|\frac{y_t - \hat y_t}{y_t}\right|$$

🔬 数式を言葉で読み解く

🧮 実値で計算:walk-forward の概念

SSDSE-B-2026 の東京人口 12 年分(2012-2023)を例にすると:

手順: Step 1: 2012-2018 で学習 → 2019 を予測 Step 2: 2012-2019 で学習 → 2020 を予測 Step 3: 2012-2020 で学習 → 2021 を予測 Step 4: 2012-2021 で学習 → 2022 を予測 Step 5: 2012-2022 で学習 → 2023 を予測 → 5 個の (実測, 予測) ペアを集めて MAE/RMSE を計算

「未来は使わない、 1 期ずつ進める」が鉄則。 これにより本番運用時の精度を正しく見積もれます。

🐍 Python 実装 10:walk-forward validation で MAE/RMSE 算出

🎯 このコードでやること:東京都人口で ARIMA(1,1,1) を walk-forward で評価し、 MAE と RMSE を算出する。

📥 入力データ:tokyo シリーズ(2012-2023 の 12 年分)。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101']

# 直近 5 年を walk-forward で検証(推定は万人単位、予測を人に戻して比べる)
test_years = tokyo.index[-5:]
errs = []
for yr in test_years:
    train = tokyo.loc[:yr-1] / 10000
    pred = round(ARIMA(train, order=(1,1,1)).fit().forecast(1).iloc[0] * 10000)
    errs.append((yr, tokyo.loc[yr], pred, tokyo.loc[yr] - pred))

err_df = pd.DataFrame(errs, columns=['year','actual','pred','err'])
print(err_df); print(f"MAE={err_df['err'].abs().mean():,.0f}  RMSE={np.sqrt((err_df['err']**2).mean()):,.0f}")

📤 実行すると次の出力が得られる:

year actual pred err 0 2019 14007000 14010237 -3237 1 2020 14047594 14121921 -74327 2 2021 14010000 14036710 -26710 3 2022 14038000 13966211 71789 4 2023 14086000 14121411 -35411 MAE=42,295 RMSE=50,311

💬 結果の読み方:5 年の 1 年先予測誤差は −74,327〜+71,789 人と符号がばらつき、MAE は 42,295 人(2023 年の 1,408.6 万人に対して約 0.30%)、RMSE は 50,311 人。誤差が大きいのは 2020 年(予測が 7.4 万人過大)と 2022 年(7.2 万人過小)で、2020〜2021 年の増加の止まりと 2022 年の持ち直しという向きの変化に 1 年遅れで追随している。RMSE が MAE を約 1.2 倍上回るのは、この 2 年の大きな外れが効いているため。

🐍 Python 実装 11:ARIMA vs ナイーブ(前年踏襲)の比較

🎯 このコードでやること:「今年の予測 = 去年の値」というナイーブモデルと ARIMA を比較し、 ARIMA の追加価値を測る。

📥 入力データ:tokyo シリーズ。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101']

test = tokyo.index[-5:]
err_naive, err_arima = [], []
for yr in test:
    train = tokyo.loc[:yr-1]
    err_naive.append(tokyo.loc[yr] - train.iloc[-1])
    # ARIMA は万人単位で推定し、予測を人に戻す
    pred = ARIMA(train / 10000, order=(1,1,1)).fit().forecast(1).iloc[0] * 10000
    err_arima.append(tokyo.loc[yr] - pred)

print(f"naive MAE = {np.mean(np.abs(err_naive)):,.0f}")
print(f"ARIMA MAE = {np.mean(np.abs(err_arima)):,.0f}")

📤 実行すると次の出力が得られる:

naive MAE = 54,838 ARIMA MAE = 42,295

💬 結果の読み方:ARIMA の MAE 42,295 人は、前年の値をそのまま使う naive の 54,838 人より約 23% 小さい。naive は 2019 年のように前年から 12 万人増えた年ほど外れるので、増減の勢いを次の年に持ち越す AR 項が効いている。ただし検証は 5 点だけで、1 点入れ替わるだけで順位が変わりうるので、差の大きさより「ベースラインを下回っていない」ことの確認として読む。

⚠️ ARIMA 評価の落とし穴

🔬 補講:SARIMA — 季節性を組み込んだ ARIMA

SSDSE-B-2026 は年次データなので明示的な季節性はありませんが、 月次・四半期・週次データでは SARIMA(p,d,q)(P,D,Q)_s が必須です。 ここでは概念整理と、 もし SSDSE が月次だったらどう書くかの仮想例を示します。

📐 数式:SARIMA の一般形

$$\Phi(B^s)\phi(B)(1-B)^d (1-B^s)^D y_t = \Theta(B^s)\theta(B)\varepsilon_t$$

🔬 数式を言葉で読み解く

🐍 Python 実装 14:SARIMA の仮想モデル(月次データ想定)

🎯 このコードでやること:年次の SSDSE-B-2026 を線形補間で月次化(教育用の人工サンプル)し、 SARIMA(1,1,1)(1,1,1)_12 を当てはめる例を示す。 ※本番では実際の月次データ(人口推計月報等)を使うこと。

📥 入力データ:SSDSE-B-2026 から東京人口年次データを月次に補間。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
from statsmodels.tsa.statespace.sarimax import SARIMAX

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101']

# 年次 → 月次の線形補間(教育用、 本番では実月次データを使うこと)
# 各年の値を 1 月に置き、 間の 11 か月を直線でつなぐ(2012-01〜2023-01 の 133 か月)
annual = pd.Series(tokyo.values / 10000, index=pd.to_datetime(tokyo.index.astype(str), format='%Y'))  # 万人
idx_m = pd.date_range(annual.index.min(), annual.index.max(), freq='MS')
m = annual.reindex(idx_m).interpolate()

model = SARIMAX(m, order=(1,1,1), seasonal_order=(1,1,1,12)).fit(disp=False)
print(model.summary().tables[1])
print((model.forecast(12) * 10000).round(0))   # 人に戻して表示

📤 実行すると次の出力が得られる:

============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ ar.L1 0.9617 0.100 9.640 0.000 0.766 1.157 ma.L1 0.0123 0.554 0.022 0.982 -1.073 1.098 ar.S.L12 0.2713 0.136 1.997 0.046 0.005 0.538 ma.S.L12 -0.9963 5.222 -0.191 0.849 -11.232 9.240 sigma2 0.0103 0.053 0.195 0.846 -0.093 0.114 ============================================================================== 2023-02-01 14090439.0 2023-03-01 14094923.0 2023-04-01 14099450.0 2023-05-01 14104019.0 2023-06-01 14108628.0 2023-07-01 14113274.0 2023-08-01 14117957.0 2023-09-01 14122674.0 2023-10-01 14127425.0 2023-11-01 14132208.0 2023-12-01 14137021.0 2024-01-01 14141863.0 Freq: MS, Name: predicted_mean, dtype: float64

💬 結果の読み方:ar.L1=0.962 が大きく、ma.L1=0.012 は効いていない。季節成分では ar.S.L12=0.271 が p=0.046 と 5% 水準をわずかに下回るが、線形補間の月次には季節パターンが無く、毎年 1 月に傾きが折れる継ぎ目を 12 か月周期として拾っただけ。ma.S.L12=−0.996 が境界に張り付き標準誤差 5.22 と発散しているのは、季節差分 D=1 が余計だったしるし。予測は 2023-02 の 14,090,439 人から 2024-01 の 14,141,863 人へ 11 か月で約 5.1 万人増え、最後の 1 年の増加 48,000 人をやや上回るペースで延ばしている。補間データで SARIMA を試すのは書き方の練習にとどめる。

⚠️ SARIMA の落とし穴

🔬 補講:よくある Q&A — ARIMA の落とし穴

Q1. (p, d, q) はどう決める?

A. (1) ADF/KPSS で d を決める(差分後に定常か)、 (2) ACF/PACF で (p, q) の候補を出す、 (3) AIC グリッドで最終決定。 auto_arima は (3) を自動化。 ただし候補が複数残るので、 残差診断(Ljung-Box)で最終判断する。

Q2. AIC と BIC、 どちらを見る?

A. AIC:予測精度寄り(過適合気味)。 BIC:簡潔性寄り(モデルが小さくなる)。 サンプル数が多いとき BIC、 少ないとき AIC が一般的。 両方見て同じ次数を選ぶならそれが安全。

Q3. 残差の正規性は必須?

A. 厳密には不要(最尤推定は正規性を仮定するが、 sample size が大きければロバスト)。 むしろ重要なのは「自己相関がないこと」。 Ljung-Box が PASS なら、 多少正規分布から外れても許容。

Q4. 何データ点あれば ARIMA が使える?

A. 経験則で 最低 30〜50 点。 季節モデル SARIMA なら「2〜3 周期分」(月次なら 2〜3 年)が必須。 なお SSDSE-B-2026 は 12 年分(2012-2023)でこの下限に満たないため、 本ページの適用は学習用のデモであり、 係数や AIC の推定は不安定になりやすい点に注意。

Q5. ARIMA で多変量は扱える?

A. 単独 ARIMA は単変量のみ。 外生変数を加えるなら SARIMAX、 真の多変量予測なら VAR (Vector AR) や VECM へ。 系列同士の双方向影響を扱える。

Q6. 予測が「定数になる」現象は?

A. ARIMA(0,0,0) や drift なしのモデルで起こる。 トレンドありなら d=1 + drift を入れる、 または定数項を有効化する。 SARIMAX(..., trend='c')。

Q7. 1 ステップ予測と多ステップ予測、 どちらで評価?

A. ユースケース次第。 在庫補充なら 1 週間先、 経営計画なら 5 年先。 報告先の意思決定粒度に合わせる。 walk-forward でも multi-horizon (h=1, 3, 6, 12) を一気に評価するのが定石。

Q8. ベイズ ARIMA は何が違う?

A. 係数に事前分布を置き、 事後分布で予測する。 サンプル数が少ない時に安定、 専門知識を prior に込められる、 信頼区間が「確率的に正しい」(信用区間)。 PyMC や Stan で実装可。

Q9. ARIMA の予測区間が現実的でない(負の人口など)

A. 対数変換 np.log(y) してから ARIMA、 予測後 np.exp() で戻す。 これで負値を防げる + 乗法構造を反映できる。 Box-Cox 変換も同様。

Q10. もう ARIMA は古い? ML/DL に置き換えるべき?

A. No。 M3/M4/M5 等の主要時系列コンペで、 ARIMA/ETS のシンプル統計手法が依然 top10 を占める。 「小データ + 解釈性必須」では ARIMA が今でも第一選択。 LSTM/Transformer は「大量データ + 非線形」のときに優位。

本ページでは 計 16 個の Python 実装で ARIMA の理論・実装・評価・拡張を網羅しました。 すべて SSDSE-B-2026 から動作します。 まず ARIMA(1,1,1) を 1 系列で動かし、 ACF/PACF を眺め、 残差診断と walk-forward を経験する——この最小サイクルを 3 回回せば、 ARIMA は「使える道具」になります。

🔬 締めくくり:ARIMA を「使える道具」にする最後の確認

本ページでは ARIMA を 18 個の Python 実装、 数式 6 種類、 SSDSE-B-2026 実値計算 多数、 SARIMA / SARIMAX / 介入変数 / アンサンブル / 運用まで網羅しました。 最後に「明日から使うチェックリスト」を提示します。

✅ 明日から使う 10 のチェックリスト

  1. 時系列を時間昇順で並べたか(並び順ミスは致命的)
  2. 欠損・異常値の前処理を行ったか
  3. ADF/KPSS で定常性を確認したか
  4. ACF/PACF で (p, q) 候補を眺めたか
  5. AIC/BIC grid で次数を選定したか
  6. Ljung-Box で残差を診断したか
  7. 予測区間 (信頼区間) を出したか
  8. walk-forward validation で MAE/RMSE/MAPE を測ったか
  9. naive ベースラインと比較したか
  10. 外生変数 / 介入変数の追加余地を検討したか

この 10 項目をすべてクリアしていれば、 そのモデルは「実務で出せる」レベル。 自信を持ってステークホルダーに数値を提示できます。 ARIMA は時系列予測の基本にして、 今でも有効な強力な道具です。 SSDSE-B-2026 を使った本ページの実装を、 ぜひ自分の手で動かしてみてください。

🧮 数式に値を入れて手で計算する

合成データ (7 期分の時系列、 多様な整数) を使い、 ARIMA の核となる一階差分 Δyₜ = yₜ - yₜ₋₁と MA(1) モデル yₜ = μ + θεₜ₋₁ + εₜ の数式に値を代入して Step 1〜3 で展開する。 同じ計算を Python (numpy) で再現し、 手計算と完全一致を確認する。

📐 用語の主要数式 (再掲)

$$ \Delta y_t = y_t - y_{t-1}, \qquad y_t = \mu + \theta\,\varepsilon_{t-1} + \varepsilon_t $$

Step 1: データ準備 (7 期の時系列、 多様な整数)

ty_t
110
213
318
415
522
628
725

Step 2: 一階差分 Δy_t = y_t − y_{t−1}

t計算Δy_t
213 − 103
318 − 135
415 − 18-3
522 − 157
628 − 226
725 − 28-3

Step 3: MA(1) を仮定した最終結果 (μ=15, θ=0.5, ε_0=0 から逐次計算)

残差を ε_t = y_t − μ − θ·ε_{t−1} で逆算する (μ=15, θ=0.5, ε_0=0):

t計算 ε_t = y_t − 15 − 0.5·ε_{t−1}ε_t
110 − 15 − 0.5·0-5.000
213 − 15 − 0.5·(-5)0.500
318 − 15 − 0.5·0.52.750
415 − 15 − 0.5·2.75-1.375
522 − 15 − 0.5·(-1.375)7.688
628 − 15 − 0.5·7.6889.156
725 − 15 − 0.5·9.1565.422

差分系列 Δy の平均は (3+5-3+7+6-3)/6 = 15/6 = 2.500、 分散 (標本) は 19.900。

🐍 同じ計算を Python で再現

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
y = np.array([10, 13, 18, 15, 22, 28, 25], dtype=float)
# 一階差分
dy = np.diff(y)
print("Δy_t       =", dy.tolist())
print("Δy mean    =", dy.mean())
print("Δy var(ddof=1) =", dy.var(ddof=1))
# MA(1) 残差: μ=15, θ=0.5, ε_0=0
mu, theta = 15.0, 0.5
eps_prev, eps = 0.0, []
for yt in y:
    e = yt - mu - theta * eps_prev
    eps.append(e); eps_prev = e
print("ε_t        =", [round(float(e), 3) for e in eps])

📤 実行結果

Δy_t = [3.0, 5.0, -3.0, 7.0, 6.0, -3.0] Δy mean = 2.5 Δy var(ddof=1) = 19.9 ε_t = [-5.0, 0.5, 2.75, -1.375, 7.688, 9.156, 5.422]

💬 手計算 Step 2 (Δy=[3,5,-3,7,6,-3]) と Step 3 の MA(1) 残差 (ε=[-5.000, 0.500, 2.750, -1.375, 7.688, 9.156, 5.422]) が Python 出力と完全一致。 ARIMA(0,1,1) は「差分系列に MA(1) を当てはめる」モデルであり、 上の Δy が定常化された系列、 ε が MA 残差として ARIMA フィッティングの内部計算がそのまま追体験できる。

🧮 実値で計算してみる — SSDSE-B-2026 で ARIMA(完全強化版)

SSDSE-B-2026(公的統計の社会・教育系データセット、 47 都道府県 × 10 年分超 × 100 以上の列)を用いて、 「ARIMA」を体感します。 ファイル名は SSDSE-B-2026.csv、 読み込みは下記の Python コードで行います。

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd

# SSDSE-B-2026 を読み込む(cp932 / Shift_JIS)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
print(df.shape)          # (564, 112) = 47 都道府県 × 12 年度
print(sorted(df['SSDSE-B-2026'].unique().tolist()))  # 含まれる年度
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
print(latest[['Prefecture', 'A1101']].head(3))
# ARIMA に渡すのは 1 県ぶんの時系列:北海道の総人口を年度の昇順に並べる
hk = df[df['Prefecture'] == '北海道'].sort_values('SSDSE-B-2026')
print(hk[['SSDSE-B-2026', 'A1101']].to_string(index=False))

📤 実行すると次の出力が得られる:

(564, 112) [2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023] Prefecture A1101 0 北海道 5092000 12 青森県 1184000 24 岩手県 1163000 SSDSE-B-2026 A1101 2012 5465000 2013 5438000 2014 5410000 2015 5381733 2016 5355000 2017 5325000 2018 5293000 2019 5259000 2020 5224614 2021 5183000 2022 5140000 2023 5092000

💬 結果の読み方:564 行は 47 都道府県 × 12 年度(2012〜2023)で、最新年度で絞った latest は 47 行の横断面になる。ARIMA に渡すのはこの横断面ではなく 1 県ぶんの 12 点で、北海道は 2012 年 546.5 万人から 2023 年 509.2 万人へ毎年減り続けている。減り幅は 2013 年の 2.7 万人から 2023 年の 4.8 万人へ広がっており、1 階差分を取ってもまだ傾きが残ることを次の実装で確かめる。

ここで使った中心列 A1101 は SSDSE-B-2026 における 北海道の人口 A1101 の年次推移(2012-2023)に ARIMA を適用 に関連する指標です。 算出例:

🧮 さらに深掘り:信頼区間・診断・SARIMAX 拡張

ARIMA は「点予測」だけでなく 予測区間(信頼区間)と 残差診断がセットで意味を持ちます。 ここでは沖縄県人口を題材に、 信頼区間の幅、 残差の正規性・自己相関、 SARIMAX による外生変数組み込みまで実装します。

📐 数式:予測区間(forecast interval)

$$\hat{y}_{T+h} \pm z_{\alpha/2} \cdot \sqrt{\text{Var}(\hat{y}_{T+h})}$$

🔬 数式を言葉で読み解く

🐍 Python 実装 7:予測区間付き予測

🎯 このコードでやること:沖縄県人口に ARIMA(1,1,1) を当てはめ、 5 年先まで 95% 予測区間つきで出力する。

📥 入力データ:SSDSE-B-2026 の Prefecture=沖縄県, A1101。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
# 万人単位で推定する(人単位のままだと最適化が初期値付近で止まる)
okinawa = df[df['pref'] == '沖縄県'][['year', 'A1101']].sort_values('year').set_index('year')['A1101'] / 10000

model = ARIMA(okinawa, order=(1, 1, 1)).fit()
fc = model.get_forecast(steps=5)
ci = fc.conf_int(alpha=0.05)  # 95%
res = pd.concat([fc.predicted_mean.rename('pred'), ci], axis=1) * 10000   # 人に戻す
res.columns = ['予測', '下限', '上限']
res.index = range(2024, 2029)   # 年の整数インデックスは予測に引き継がれないので付け直す
print(res.round(0))

📤 実行すると次の出力が得られる:

予測 下限 上限 2024 1466950.0 1463647.0 1470253.0 2025 1466047.0 1456528.0 1475566.0 2026 1465271.0 1448537.0 1482004.0 2027 1464604.0 1440087.0 1489120.0 2028 1464030.0 1431429.0 1496632.0

💬 結果の読み方:沖縄県は 2021〜2023 年が 1,468,000 人で横ばいのため、点予測は 2024 年 1,466,950 人 → 2028 年 1,464,030 人とわずかに減る。95% 区間の半幅は 1 年先の約 3,300 人から 5 年先の約 32,600 人へ 10 倍近く広がり、2028 年は 143.1 万〜149.7 万人のどこでもありうる。2019 年まで年 6,000〜8,400 人増えていた系列でも、直近の横ばいを受けて向きが変わるので、点予測だけでなく区間を並べて報告する。

🐍 Python 実装 8:残差診断(Ljung-Box 検定)

🎯 このコードでやること:ARIMA モデルの残差が「ホワイトノイズか(自己相関ゼロか)」を Ljung-Box 検定で確認する。 残差に自己相関が残るとモデル不足のサイン。

📥 入力データ:先ほどの沖縄モデルの残差。

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.stats.diagnostic import acorr_ljungbox

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
okinawa = df[df['pref'] == '沖縄県'][['year', 'A1101']].sort_values('year').set_index('year')['A1101'] / 10000  # 万人

model = ARIMA(okinawa, order=(1, 1, 1)).fit()
# 先頭の残差は差分できない 2012 年の水準そのもの(141.1 万人)なので除いて検定する
lb = acorr_ljungbox(model.resid.iloc[1:], lags=[5, 10], return_df=True)
print(lb)
print("p > 0.05 ならホワイトノイズ仮説を棄却できない = OK")

📤 実行すると次の出力が得られる:

lb_stat lb_pvalue 5 1.002419 0.962370 10 10.953671 0.361139 p > 0.05 ならホワイトノイズ仮説を棄却できない = OK

💬 結果の読み方:先頭の残差(2012 年の水準 141.1 万人がそのまま入る)を除くと、ラグ 5 で p=0.962、ラグ 10 で p=0.361 となり、どちらも 5% 水準で白色雑音を棄却しない。先頭を除かずに検定すると 141.1 という 1 点だけ桁違いの値が自己相関を 0 近くに押しつぶし、p が 0.9999 と実態以上に「きれい」に見えてしまう。残差は 11 点しかなく、ラグ 10 まで見ると 1 ラグあたりの点がほとんど無いので、棄却できないことを「十分に適合した」証拠とまでは読まない。

🐍 Python 実装 9:SARIMAX で外生変数(出生数)を組み込む

🎯 このコードでやること:東京都人口を SARIMAX で予測し、 外生変数として「出生数 A4101」を加える。 純 ARIMA との AIC 比較。

📥 入力データ:tokyo 人口 + tokyo 出生数の 2 系列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
from statsmodels.tsa.statespace.sarimax import SARIMAX

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
tokyo = df[df['pref'] == '東京都'].sort_values('year').set_index('year')

# どちらも万人単位にそろえる(人単位のままだと最適化が初期値付近で止まる)
y = tokyo['A1101'] / 10000            # 総人口
x = tokyo[['A4101']] / 10000          # 出生数を外生変数

m_no_exog = SARIMAX(y, order=(1,1,1)).fit(disp=False)
m_with_x  = SARIMAX(y, order=(1,1,1), exog=x).fit(disp=False)

print(f"純 ARIMA     AIC = {m_no_exog.aic:.2f}")
print(f"SARIMAX(+x)  AIC = {m_with_x.aic:.2f}")

📤 実行すると次の出力が得られる:

純 ARIMA AIC = 67.42 SARIMAX(+x) AIC = 68.99

💬 結果の読み方:総人口と出生数を万人単位にそろえると、純 ARIMA(1,1,1) の AIC 67.42 に対し、出生数を足した SARIMAX は 68.99 と 1.57 悪化する(AIC は小さいほど良い)。パラメータを 1 つ足すペナルティ +2 に対して対数尤度は 0.2 しか増えておらず、出生数は東京の総人口の年々の増減をほとんど説明していない。東京の人口増減は出生より転入超過で動いているので、外生変数を選ぶなら社会増減側の指標を試すのが筋。

📝 より正確な分析:実データ (SSDSE-B-2026, 東京都 A1101, 2012–2023 の 12 点) で再計算すると、 万人単位で推定した純 ARIMA(1,1,1) の AIC=67.42 に対し、 出生数 (A4101) を外生変数に加えた SARIMAX の AIC=68.99 と悪化した。 系列がわずか 12 点と短く、 出生数の追加情報が AIC ペナルティ (+2/パラメータ) を上回る改善をもたらさないためである。 外生変数の有無は AIC/BIC やクロスバリデーションで都度検証すべきで、 「SARIMAX が常に優る」という一般化は誤り。

🧮 5 都道府県の AR(1) 係数を一斉計算

🎯 このコードでやること:北海道・東京・大阪・愛知・沖縄の 5 県に ARIMA(1,1,0) を当てはめ、 AR 係数を比較する。

📥 入力データ:SSDSE-B-2026 の 5 都道府県の人口時系列。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})

for p in ['北海道', '東京都', '大阪府', '愛知県', '沖縄県']:
    s = df[df['pref'] == p][['year', 'A1101']].sort_values('year').set_index('year')['A1101']
    s = s / 10000   # 万人単位(人単位のままだと AR 係数が初期値 0 付近から動かない)
    try:
        m = ARIMA(s, order=(1, 1, 0)).fit()
        print(f"{p:5s}: AR(1)={m.params['ar.L1']:+.3f}  AIC={m.aic:.1f}")
    except Exception as e:
        print(f"{p}: error {e}")

📤 実行すると次の出力が得られる:

北海道 : AR(1)=+0.997 AIC=15.0 東京都 : AR(1)=+0.869 AIC=67.6 大阪府 : AR(1)=+0.725 AIC=35.2 愛知県 : AR(1)=+0.826 AIC=37.7 沖縄県 : AR(1)=+0.937 AIC=2.4

💬 結果の読み方:5 県とも AR(1) は +0.73〜+0.997 と大きく、前年の増減のペースが今年もほぼ続く。北海道の 0.997 は 1 にほぼ等しく、差分した系列にもまだ単位根が残っている(減少が年々加速している)ので、d=2 を検討する合図になる。大阪府は 0.725 と最も小さい。AIC は万人単位の値で、系列ごとに水準もばらつきも違うため県どうしを比べる指標ではない。

🧮 補講:47 都道府県に一括で ARIMA を適用する

実務では 1 系列を細かく分析するより、 「数十〜数千系列に一律でモデルを当てる」運用が多いです。 ここでは 47 都道府県すべてに ARIMA を fit し、 5 年先予測を生成する典型コードを示します。

🐍 Python 実装 18:47 県一括 ARIMA 予測

🎯 このコードでやること:SSDSE-B-2026 の 47 都道府県に ARIMA(1,1,1) を一括 fit、 5 年先の予測 + 信頼区間を取得する。

📥 入力データ:SSDSE-B-2026.csv 全行。

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

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})

results = []
for pref in df['pref'].unique():
    s = df[df['pref'] == pref][['year', 'A1101']].sort_values('year').set_index('year')['A1101'] / 10000  # 万人
    try:
        m = ARIMA(s, order=(1, 1, 1)).fit()
        fc = m.forecast(5)
        results.append({'pref': pref, '2024': round(fc.iloc[0] * 10000), '2028': round(fc.iloc[4] * 10000),
                        'growth_5y': (fc.iloc[4] / s.iloc[-1] - 1) * 100})
    except Exception:
        pass

out = pd.DataFrame(results).sort_values('growth_5y', ascending=False)
print("増加率 TOP 5:"); print(out.head(5).round(2))
print("減少率 TOP 5:"); print(out.tail(5).round(2))

📤 実行すると次の出力が得られる:

増加率 TOP 5: pref 2024 2028 growth_5y 12 東京都 14089464 14095462 0.07 24 滋賀県 1406991 1406994 -0.00 13 神奈川県 9225629 9217072 -0.13 46 沖縄県 1466950 1464030 -0.27 26 大阪府 8749086 8736578 -0.30 減少率 TOP 5: pref 2024 2028 growth_5y 38 高知県 656565 619077 -7.05 5 山形県 1010888 950847 -7.32 2 岩手県 1143779 1069543 -8.04 1 青森県 1163946 1084440 -8.41 4 秋田県 898448 836479 -8.48

💬 結果の読み方:万人単位で 47 県を推定し直すと、5 年後(2028 年)に増える予測は東京都の +0.07% だけで、滋賀県 −0.00%、神奈川県 −0.13%、沖縄県 −0.27% と上位でもほぼ横ばい。減少側は秋田県 −8.48%、青森県 −8.41%、岩手県 −8.04% で、秋田は 2018→2023 年の実績 −7.2% よりやや速いペースを延ばしている。ただし東京・神奈川・埼玉・岩手・兵庫・岡山の 6 県は ma.L1 が 0.99 以上で境界に張り付いており、一律に ARIMA(1,1,1) を当てたときの係数は県ごとに確かめる必要がある。

🐍 Python 実装 — 完全強化版

scipy / pandas / scikit-learn / statsmodels を中心とした標準的な実装例です。 まず CSV を読み込み、 次に ARIMA の解析を行います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import numpy as np
from scipy import stats

raw = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
hk = raw[raw['Prefecture'] == '北海道'].sort_values('SSDSE-B-2026')
y = hk.set_index('SSDSE-B-2026')['A1101'] / 10000   # 北海道の総人口(万人)2012→2023
d = y.diff().dropna()                                # 1 階差分 = 前年からの増減(万人)

# 基本統計量
print('n (差分後)   =', len(d))
print('mean(Δy)     =', round(d.mean(), 2))
print('std(Δy)      =', round(d.std(ddof=1), 2))

# AR(1) 係数の目安:差分系列の「前年の増減」と「今年の増減」の相関
r, p = stats.pearsonr(d.values[:-1], d.values[1:])
print(f'lag-1 Pearson r = {r:.4f}, p = {p:.4g}')
rs, ps = stats.spearmanr(d.values[:-1], d.values[1:])
print(f'lag-1 Spearman rho = {rs:.4f}, p = {ps:.4g}')

📤 実行すると次の出力が得られる:

n (差分後) = 11 mean(Δy) = -3.39 std(Δy) = 0.73 lag-1 Pearson r = 0.9482, p = 2.95e-05 lag-1 Spearman rho = 0.8909, p = 0.0005421

💬 結果の読み方:北海道の前年差は平均 −3.39 万人/年、標準偏差 0.73 万人。差分系列の「前年の増減」と「今年の増減」の相関は Pearson r=0.948(p=2.95e-05)、Spearman ρ=0.891 と非常に強く、減り方が年々一方向に大きくなっているので差分後も定常とは言いにくい。ARIMA(1,1,0) の AR 係数が北海道で 0.997 と 1 に近づくのはこのためで、d=2 を検討する根拠になる。

用途別の追加実装:

1
2
3
4
5
6
7
8
9
10
11
12
# 47 都道府県を「人口の動き方」で 4 群に分ける(群ごとに ARIMA の次数を揃える前準備)
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

wide = raw.pivot(index='Prefecture', columns='SSDSE-B-2026', values='A1101')
feat = pd.DataFrame({'増減率_12-23': (wide[2023] / wide[2012] - 1) * 100,
                     '増減率_20-23': (wide[2023] / wide[2020] - 1) * 100})
Xs = StandardScaler().fit_transform(feat)
km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(Xs)
feat['cluster'] = km.labels_
print(feat.groupby('cluster').agg(県数=('cluster', 'size'), 増減率_12_23=('増減率_12-23', 'mean')).round(2))
print(feat.sort_values('増減率_12-23').round(2).head(5))

📤 実行すると次の出力が得られる:

県数 増減率_12_23 cluster 0 9 1.56 1 12 -7.13 2 12 -10.59 3 14 -4.70 増減率_12-23 増減率_20-23 cluster Prefecture 秋田県 -14.02 -4.74 2 青森県 -12.30 -4.36 2 高知県 -11.32 -3.69 2 山形県 -11.01 -3.94 2 岩手県 -10.95 -3.93 2

💬 結果の読み方:2012→2023 年の増減率と 2020→2023 年の増減率で分けると、東京・神奈川・愛知・沖縄など 9 都府県の群(平均 +1.56%)から、秋田・青森・高知・山形・岩手など 12 県の群(平均 −10.59%)まで 4 群に分かれる。秋田県は 12 年で −14.02%、直近 3 年でも −4.74% と両方の軸で最も減っている。動き方の似た県をまとめておくと、群ごとに差分の階数や次数をそろえて ARIMA を当てる運用がしやすくなる。

1
2
3
4
5
6
7
8
# 時系列(北海道の A1101)— ARIMA 前処理としての ADF 検定
import statsmodels.api as sm

print(y.tail())
res = sm.tsa.stattools.adfuller(y)
print('ADF (元系列)  stat:', round(res[0], 3), 'p:', round(res[1], 4))
res_d = sm.tsa.stattools.adfuller(d)
print('ADF (1 階差分) stat:', round(res_d[0], 3), 'p:', round(res_d[1], 4))

📤 実行すると次の出力が得られる:

SSDSE-B-2026 2019 525.9000 2020 522.4614 2021 518.3000 2022 514.0000 2023 509.2000 Name: A1101, dtype: float64 ADF (元系列) stat: 15.846 p: 1.0 ADF (1 階差分) stat: 2.023 p: 0.9987

💬 結果の読み方:北海道の総人口は元系列で ADF 統計量 15.846(p=1.0)と単位根を全く棄却できず、1 階差分後も 2.023(p=0.9987)で棄却できない。統計量が正の大きな値になるのは、減少が年々加速していて差分系列にもまだ下向きの傾きがあるため。北海道に ARIMA を当てるなら d=2 か、トレンド項を入れたモデルを検討する。ただし 12 点の ADF は検出力が低く、判定そのものが揺れやすい。

🐍 補講:auto_arima で自動次数選定 — pmdarima 入門

手動グリッド(実装 5)は理解には良いが、 本番では pmdarima.auto_arima が定番。 R の forecast::auto.arima の Python 移植で、 stepwise アルゴリズムで効率的に最適 (p,d,q)(P,D,Q,s) を探索します。

🐍 Python 実装 17:auto_arima を SSDSE で実行

🎯 このコードでやること:東京都人口に auto_arima を適用し、 最適次数・係数・予測を一発で取得する。

📥 入力データ:tokyo シリーズ(要 pip install pmdarima)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
from pmdarima import auto_arima

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
# 万人単位(人単位のままだと候補の多くで最適化が止まり、選ばれる次数が変わる)
tokyo = df[df['pref'] == '東京都'][['year', 'A1101']].sort_values('year').set_index('year')['A1101'] / 10000

m = auto_arima(tokyo, seasonal=False, stepwise=True,
                information_criterion='aic', trace=False)
print(f"selected order: {m.order}")
print(f"AIC: {m.aic():.2f}")
print("Forecast (3 years, 人):")
fc = m.predict(3) * 10000
fc.index = [2024, 2025, 2026]
print(fc.round(0))

📤 実行すると次の出力が得られる:

selected order: (1, 1, 1) AIC: 66.03 Forecast (3 years, 人): 2024 14114096.0 2025 14172028.0 2026 14238934.0 dtype: float64

💬 結果の読み方:万人単位で探索すると定数(ドリフト)付きの ARIMA(1,1,1) が選ばれ、AIC=66.03 と、定数なしの手動グリッド 1 位(67.42)より小さい。予測は 14,114,096 → 14,172,028 → 14,238,934 人と 2025 年以降は年 6〜7 万人ずつ増え、定数なしのモデル(2026 年 1,409.35 万人でほぼ横ばい)とは 3 年先で約 15 万人違う。定数は 2012〜2023 年の平均増加(年 7.7 万人)に近い伸びを予測に持ち込むので、2020 年以降の頭打ちが続くと見るか一時的と見るかで、定数を入れるかどうかを決める。 seasonal=True, m=12 にすれば SARIMA も自動探索可能。

⚠️ auto_arima 利用時の注意

これで本ページの実装は 計 17 本。 「Box-Jenkins 法 4 ステップ × 全 SSDSE 都道府県」を一回りすれば、 時系列分析の感覚は確実に身につきます。 「ARIMA を超える」モデルに進むときも、 ここで体得した思考フローはそのまま使えます。

⚠️ 落とし穴 — 完全強化版

SSDSE-B-2026 の A1101(総人口)や A4101(出生数)のような 12 年程度(2012-2023)の年次系列に ARIMA を当てる際に頻発する 5 つの落とし穴。 短期サンプル + 外因ショック(コロナ・震災)が混在するため、 定常性・差分次数・季節性の取り扱いが特に難しくなります。

🗺 概念マップ — 完全強化版

ARIMA モデル 定常性と差分 ACF / PACF

🔗 隣接手法への橋渡し

ARIMA(p,d,q) は時系列の定常化 → 自己回帰 + 移動平均 → 予測の枠組みで、 前後の道具とパイプラインで連結する。

SSDSE-B-2026 の時系列軸 (例: 各都道府県の 2010-2024 人口) で d=1 差分後 ARIMA(1,1,1) を当て、 2025-2030 を予測する流れが標準パイプライン。

🌳 手法選択フロー

ARIMA のオーダー (p, d, q) と派生選択は「定常性」「季節性」「非線形性」の 3 軸で判定する。

  1. 系列は定常か? ADF 検定 p<0.05 → そのまま AR(p)MA(q)。 非定常 → d=1 で差分、 まだ非定常なら d=2。 SSDSE-B-2026 の人口時系列は単調減少傾向で d=1 が定石。
  2. 季節パターンあり? 月次/四半期で同じ周期 → SARIMA(p,d,q)(P,D,Q)_s で季節項追加。 不規則だが祝日等の既知イベント → Prophet が容易。
  3. 非線形 or 高次元? 線形 ARMA で残差白色化できない → LSTM/Transformer。 多変量 (47 都道府県同時) → VAR or DeepAR。 SSDSE-B-2026 単県の 15 年系列なら ARIMA で十分、 47 県の相互作用を捉えるなら VAR。

auto_arima (pmdarima) で AIC 最小のオーダーを自動探索 → Ljung-Box で残差確認、 という半自動ワークフローが実務の定石。

🧭 深掘り解説 — 直感・落とし穴・発展(追記)

既存の各セクションと 🎮 ウィジェットに加えて、 別角度から ARIMA を掘り下げます。 題材は SSDSE-B-2026 の 秋田県 総人口 A1101(2012-2023, n=12)。 この系列は 1,063,000 人 → 914,000 人へほぼ単調に減少する、 教科書的な非定常トレンドです(実測)。

🎨 直感:AR+I+MA という3つの部品

ARIMA(p, d, q) は名前がそのまま設計図です。 まず定常化(I)、 それから予測(AR+MA) という順で読むと腑に落ちます。

⚠️ 落とし穴(重要)①:ドリフト無しの ARIMA は「横ばい」を予測する

明確に減り続ける秋田県人口でも、 定数項(ドリフト)を入れ忘れると予測が水平線になります。 ARIMA(0,1,0)(ランダムウォーク)を drift 無し/有りで当てた実測比較がこちら。

秋田県 A1101(2012-2023, 実測, 直近値 2023 = 914,000 人) ARIMA(0,1,0) ドリフト無し → 予測 2024-26 = [914000, 914000, 914000] ← 横ばい ARIMA(0,1,0) ドリフト有り → 予測 2024-26 = [900455, 886909, 873364] ← 減少継続 AIC:ドリフト無し 242.65 vs ドリフト有り 191.16(有りが大幅良好)

差分系列の平均(=毎年の減少幅)を定数項として入れて初めて、 モデルは「減り続ける」未来を描けます。 d≥1 のとき statsmodels の既定は trend='n'(ドリフト無し)なので、 トレンドのある系列では trend='t'(または 'c')を明示するのが定石。 「なぜか予測が真横に伸びる」ときは、 まずここを疑ってください。

📝 補足(別角度):既存の 📝 は「外生変数・アンサンブルが常には効かない」話でしたが、 こちらはモデル指定そのもの(ドリフト項)で予測が激変するという指摘です。 秋田県の実測では AIC が 242.65→191.16 とドリフト有りが圧勝で、 差分後の系列に平均(傾き)が残るかどうかを必ず確認すべきことを示します。 自動選択(auto_arima)は with_drift を探索してくれますが、 手動で ARIMA を書くときは trend 引数を意識しましょう。

⚠️ 落とし穴(重要)②:差分は 1 回で足りるか — 過小差分と過剰差分

d の決め方は「定常になるまで、 ただし最小限だけ」差分する、が鉄則です。 秋田県 A1101 で単位根検定(ADF)を実測すると次のとおり。

秋田県 A1101(実測, n=12) 原系列 ADF:統計量 = 3.655, p = 1.000 → 単位根を全く棄却できない(強い非定常) 原系列 ACF:lag1 = 0.742, lag2 = 0.497 → ゆっくり減衰=非定常のサイン 1階差分後 ADF:p = 0.998 → まだ棄却できない(差分値が -13,000→-16,000 と年々拡大=減少が加速)

興味深いのは、 1 階差分しても ADF が定常と言わない点です。 これは差分系列(毎年の減少幅)にまだ緩やかな傾きが残る(減少が加速している)ため。 とはいえ n=12 では検定力が極端に低く、 p 値は目安にすぎません。 ここで反射的に d=2 へ上げるのは危険で、 過剰差分は系列を壊し、 人工的な負の自己相関(見かけの MA 構造)を生みます。 短い系列では、 検定の数字を鵜呑みにせず ACF/PACF の形と AIC/BIC を併用し、 d は 0〜1 に留めるのが無難です。

🚀 発展①:Box-Jenkins 法と ACF/PACF による次数同定

古典的な次数選択は、 差分後系列の自己相関(ACF)と偏自己相関(PACF)の「形」を読む職人技でした。 目安は次の対応表です。

これが Box-Jenkins 法(同定 → 推定 → 診断 → 予測)の「同定」ステップです。 現代では auto_arima が AIC/BIC 最小化でこの職人技を代替しますが、 候補が割れたときに ACF/PACF を目で見て裏取りすると誤特定を減らせます。 最後は残差の白色性(Ljung-Box 検定)で診断するのを忘れずに。

🚀 発展②:ARIMA の“外側” — SARIMA・状態空間/ETS・機械学習

⚠️ 発展③:見せかけの回帰と外挿の不確実性

2 つの非定常系列(例:人口 A1101 と何らかの経済指標)をそのまま回帰すると、 実は無関係でも高い決定係数が出る見せかけの回帰(spurious regression)に陥ります。 時系列では「まず定常化してから関係を見る」「単位根・共和分を確認する」が原則。 また ARIMA は本質的に過去パターンの外挿であり、 少子化の加速・政策転換・災害といった構造変化の先には無力です。 秋田県の減少加速のように、 過去の平均ペースが未来にそのまま続く保証はありません。 予測は「現状のダイナミクスが続くなら」という条件付きの数字として読みましょう。

🔗 関連ページ(この教材内に実在)

※ SARIMA・auto_arima・Prophet・LSTM は本教材に独立ページが無いため、 本文中のテキスト解説にとどめています。

🎮 触って理解する

スライダーで AR係数 φ・MA係数 θ・和分の階数 d を動かすと、 固定した同一のホワイトノイズ列 et から生成される ARIMA(1, d, 1) 系列がリアルタイムに変化します。 上段の系列グラフをタップ/ドラッグすると、その時点に大きなショックを注入でき、 AR の「粘り」・MA の「平滑」・和分の「累積」がどう働くかを体感できます。 下段は同じ系列の自己相関(ACF)です。 ノイズ列は固定シードなので、変わるのは係数の効果だけです。

▼ 生成された時系列 yt(グラフをタップ/ドラッグでショック注入)
▼ 自己相関 ACF(ラグ 0〜24、灰色の点線は ±1.96/√n の有意水準の目安)

🧭 直感で読み解く

⚠️ よくある落とし穴

🚀 発展