「ARIMA」を理解するうえで必要なキーワードを 10 件以上提示します。 各チップから対応セクションへ移動できます。
30 秒結論 文脈 直感 数式 記号読み解き 実値計算 Python 実装 落とし穴 関連手法 関連用語 グループ教材 概念マップ
🍰 まずはやさしく
未来を予想する便利な道具です。
時間の流れに沿ったデータの変化を予測します。
人口がこれからどう変わるかを調べます。
このモデルの仕組みと使い方を学びます。
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 |
📥 入力例: ① で作った 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 の判定自体も揺れやすい。
📥 入力例: ① の 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 年の波」に見えているのであって、季節性ではない。周期を探すなら先に差分や回帰でトレンドを除き、そもそも年次データには月の季節周期が無いことも押さえておく。
📥 入力例: 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 はトレンドの不確かさをサンプリングで作るため、実行するたびに小数点以下が変わる。
🍰 まずはやさしく
データの傾向を読むための手法です。
過去の動きから未来を予測するために使います。
都道府県の人口の変化を分析します。
この用語が分析の中でどう使われるかを見ます。
論文中に 「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-B-2026 を題材に、 ARIMA が良く効くケースと、 失敗するケースを並べて検証します。 「いつ使うべきで、 いつ別の手法に切り替えるか」を体感で覚えてもらうのが目的。
東京の人口は緩やかなトレンド + 微小ノイズ。 ARIMA(1,1,1) で MAPE 0.3% 程度の高精度が出る。 構造変化(コロナ)も振幅が小さいため吸収可能。
出生数は近年急減(少子化加速)。 ARIMA は「過去の平均的なペース」で予測するため、 急変期に過大評価しがち。 外生変数(死亡数 A4200)を 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} 人") |
📤 実行すると次の出力が得られる:
💬 結果の読み方:出生数・死亡数を万人単位にそろえて推定すると、死亡数を外生変数に加えた 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 を採るのが妥当。
2020〜2022 のコロナ期は東京人口が一時減少。 ARIMA は構造変化を吸収しきれず、 残差が偏る。 「2020-2022 に 1 を立てる dummy」を SARIMAX の exog に入れると吸収できる。
🎯 このコードでやること:東京人口に「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 の水準のずれ)") |
📤 実行すると次の出力が得られる:
💬 結果の読み方: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 は 1970 年に George Box と Gwilym Jenkins が著書 "Time Series Analysis: Forecasting and Control" で体系化した手法です。 「Box-Jenkins 法」と呼ばれる 4 ステップが今でも実務の標準フローです。
| Step | 名称 | やること | SSDSE での例 |
|---|---|---|---|
| 1 | Identification(同定) | 定常性確認 + ACF/PACF で次数候補 | 東京人口 → d=1 候補、 ACF/PACF から (p, q) 候補 |
| 2 | Estimation(推定) | 最尤推定で係数算出 | ARIMA(1,1,1) 学習、 AR=0.69, MA=1.00(境界に張り付き) |
| 3 | Diagnostic(診断) | 残差の自己相関を Ljung-Box で検定 | 沖縄モデル p=0.96(ラグ 5)→ OK |
| 4 | Forecasting(予測) | 未来予測 + 信頼区間 | 沖縄 5 年先 1,464,030 ± 32,602 |
50 年以上前の手法ですが、 現代の auto_arima や Prophet も骨格はこの 4 ステップに従います。 教科書的に古い印象がありますが、 「定常性 → 残差診断 → 信頼区間」という思考の枠組みは時系列分析の 共通言語として今も生きています。
ARIMA の3 要素 (p,d,q) と差分の効果を、 3 点の SVG で把握する。
AR=過去値の重ね合わせ、 I=差分でトレンド除去、 MA=過去誤差を補正。
トレンドのある系列を 1 階差分すると平均が一定に → ARMA を適用可能。
ACF がゆっくり減衰し PACF が lag1 のみ → AR(1)。 逆パターンは MA。
ARIMA は AR(自己回帰)・I(差分)・MA(移動平均)の 3 要素から時系列を予測するモデルです。 以下 3 点の概念図で「差分による定常化」「ACF/PACF 形状からの次数選定」「予測区間の発散」を視覚的に整理します。
→ ARIMA の "I"(積分;実は差分)は、 トレンドを取り除いて系列を定常化する操作です。 原系列が右肩上がりでも、 隣接時点の差を取れば変化量は平均ゼロ周りで安定し、 AR/MA モデルが適用可能になります。 差分次数 d は ADF 検定で 0.05 未満を達成する最小値を選びます(通常 d=0,1,2)。
→ 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 最小化を行うのが定石です。
→ 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(AutoRegressive Integrated Moving Average)は AR (自己回帰) + I (差分積分) + MA (移動平均) の合成です。 ここでは SSDSE-B-2026 の都道府県人口時系列を題材に、 各構成要素を切り分けて、 実数値・実コードで深く解剖します。
| 要素 | 意味 | SSDSE 人口時系列での例 |
|---|---|---|
| AR(p) | 過去 $p$ 期の自分の値で予測 | 東京の今年人口 ≈ 0.95 × 昨年人口 + ... |
| I(d) | $d$ 階差分で定常化 | 人口は増加トレンドあり → 1 階差分(前年比)で定常化 |
| MA(q) | 過去 $q$ 期の予測誤差を取り込む | 「去年の予測ハズレ」を補正に反映 |
| 季節 S | 周期性(年/月/週) | SSDSE は年次のみ → 季節性なし、 月次データならあり |
$$\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):$y_t = \phi_1 \cdot y_{t-1} + c + \varepsilon_t$ で、 $\phi_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)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:万人単位で推定すると 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 年以降の頭打ちを延ばした形になる。
🎯 このコードでやること:東京都人口の 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 と大きく、ラグ 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 グリッドで候補を絞る。
🎯 このコードでやること:東京都人口に対し、 (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) |
📤 実行すると次の出力が得られる:
💬 結果の読み方: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) だけずれるため、単位の違うモデルどうしを比べてはいけない。
🎯 このコードでやること:東京都人口の元系列と 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}") |
📤 実行すると次の出力が得られる:
💬 結果の読み方:元系列は p=0.99 で「非定常(単位根あり)」を棄却できず → 差分が必要。 1 階差分後は p=0.03 で定常と判定。 → d = 1 が適切と確定。 ADF は 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|$$
SSDSE-B-2026 の東京人口 12 年分(2012-2023)を例にすると:
「未来は使わない、 1 期ずつ進める」が鉄則。 これにより本番運用時の精度を正しく見積もれます。
🎯 このコードでやること:東京都人口で 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}") |
📤 実行すると次の出力が得られる:
💬 結果の読み方: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 年の大きな外れが効いているため。
🎯 このコードでやること:「今年の予測 = 去年の値」というナイーブモデルと 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}") |
📤 実行すると次の出力が得られる:
💬 結果の読み方:ARIMA の MAE 42,295 人は、前年の値をそのまま使う naive の 54,838 人より約 23% 小さい。naive は 2019 年のように前年から 12 万人増えた年ほど外れるので、増減の勢いを次の年に持ち越す AR 項が効いている。ただし検証は 5 点だけで、1 点入れ替わるだけで順位が変わりうるので、差の大きさより「ベースラインを下回っていない」ことの確認として読む。
SSDSE-B-2026 は年次データなので明示的な季節性はありませんが、 月次・四半期・週次データでは SARIMA(p,d,q)(P,D,Q)_s が必須です。 ここでは概念整理と、 もし SSDSE が月次だったらどう書くかの仮想例を示します。
$$\Phi(B^s)\phi(B)(1-B)^d (1-B^s)^D y_t = \Theta(B^s)\theta(B)\varepsilon_t$$
🎯 このコードでやること:年次の 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)) # 人に戻して表示 |
📤 実行すると次の出力が得られる:
💬 結果の読み方: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 を試すのは書き方の練習にとどめる。
A. (1) ADF/KPSS で d を決める(差分後に定常か)、 (2) ACF/PACF で (p, q) の候補を出す、 (3) AIC グリッドで最終決定。 auto_arima は (3) を自動化。 ただし候補が複数残るので、 残差診断(Ljung-Box)で最終判断する。
A. AIC:予測精度寄り(過適合気味)。 BIC:簡潔性寄り(モデルが小さくなる)。 サンプル数が多いとき BIC、 少ないとき AIC が一般的。 両方見て同じ次数を選ぶならそれが安全。
A. 厳密には不要(最尤推定は正規性を仮定するが、 sample size が大きければロバスト)。 むしろ重要なのは「自己相関がないこと」。 Ljung-Box が PASS なら、 多少正規分布から外れても許容。
A. 経験則で 最低 30〜50 点。 季節モデル SARIMA なら「2〜3 周期分」(月次なら 2〜3 年)が必須。 なお SSDSE-B-2026 は 12 年分(2012-2023)でこの下限に満たないため、 本ページの適用は学習用のデモであり、 係数や AIC の推定は不安定になりやすい点に注意。
A. 単独 ARIMA は単変量のみ。 外生変数を加えるなら SARIMAX、 真の多変量予測なら VAR (Vector AR) や VECM へ。 系列同士の双方向影響を扱える。
A. ARIMA(0,0,0) や drift なしのモデルで起こる。 トレンドありなら d=1 + drift を入れる、 または定数項を有効化する。 SARIMAX(..., trend='c')。
A. ユースケース次第。 在庫補充なら 1 週間先、 経営計画なら 5 年先。 報告先の意思決定粒度に合わせる。 walk-forward でも multi-horizon (h=1, 3, 6, 12) を一気に評価するのが定石。
A. 係数に事前分布を置き、 事後分布で予測する。 サンプル数が少ない時に安定、 専門知識を prior に込められる、 信頼区間が「確率的に正しい」(信用区間)。 PyMC や Stan で実装可。
A. 対数変換 np.log(y) してから ARIMA、 予測後 np.exp() で戻す。 これで負値を防げる + 乗法構造を反映できる。 Box-Cox 変換も同様。
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 を 18 個の Python 実装、 数式 6 種類、 SSDSE-B-2026 実値計算 多数、 SARIMA / SARIMAX / 介入変数 / アンサンブル / 運用まで網羅しました。 最後に「明日から使うチェックリスト」を提示します。
この 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 $$
| t | y_t |
|---|---|
| 1 | 10 |
| 2 | 13 |
| 3 | 18 |
| 4 | 15 |
| 5 | 22 |
| 6 | 28 |
| 7 | 25 |
| t | 計算 | Δy_t |
|---|---|---|
| 2 | 13 − 10 | 3 |
| 3 | 18 − 13 | 5 |
| 4 | 15 − 18 | -3 |
| 5 | 22 − 15 | 7 |
| 6 | 28 − 22 | 6 |
| 7 | 25 − 28 | -3 |
残差を ε_t = y_t − μ − θ·ε_{t−1} で逆算する (μ=15, θ=0.5, ε_0=0):
| t | 計算 ε_t = y_t − 15 − 0.5·ε_{t−1} | ε_t |
|---|---|---|
| 1 | 10 − 15 − 0.5·0 | -5.000 |
| 2 | 13 − 15 − 0.5·(-5) | 0.500 |
| 3 | 18 − 15 − 0.5·0.5 | 2.750 |
| 4 | 15 − 15 − 0.5·2.75 | -1.375 |
| 5 | 22 − 15 − 0.5·(-1.375) | 7.688 |
| 6 | 28 − 15 − 0.5·7.688 | 9.156 |
| 7 | 25 − 15 − 0.5·9.156 | 5.422 |
差分系列 Δy の平均は (3+5-3+7+6-3)/6 = 15/6 = 2.500、 分散 (標本) は 19.900。
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]) |
💬 手計算 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(公的統計の社会・教育系データセット、 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 行は 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 を適用 に関連する指標です。 算出例:
A1101 平均と標準偏差を求めるA1101 を年度順に並べ、 前年差(1 階差分)が一定か、 年々広がっているかを見るARIMA は「点予測」だけでなく 予測区間(信頼区間)と 残差診断がセットで意味を持ちます。 ここでは沖縄県人口を題材に、 信頼区間の幅、 残差の正規性・自己相関、 SARIMAX による外生変数組み込みまで実装します。
$$\hat{y}_{T+h} \pm z_{\alpha/2} \cdot \sqrt{\text{Var}(\hat{y}_{T+h})}$$
🎯 このコードでやること:沖縄県人口に 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)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:沖縄県は 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 人増えていた系列でも、直近の横ばいを受けて向きが変わるので、点予測だけでなく区間を並べて報告する。
🎯 このコードでやること: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") |
📤 実行すると次の出力が得られる:
💬 結果の読み方:先頭の残差(2012 年の水準 141.1 万人がそのまま入る)を除くと、ラグ 5 で p=0.962、ラグ 10 で p=0.361 となり、どちらも 5% 水準で白色雑音を棄却しない。先頭を除かずに検定すると 141.1 という 1 点だけ桁違いの値が自己相関を 0 近くに押しつぶし、p が 0.9999 と実態以上に「きれい」に見えてしまう。残差は 11 点しかなく、ラグ 10 まで見ると 1 ラグあたりの点がほとんど無いので、棄却できないことを「十分に適合した」証拠とまでは読まない。
🎯 このコードでやること:東京都人口を 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(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 県に 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}") |
📤 実行すると次の出力が得られる:
💬 結果の読み方:5 県とも AR(1) は +0.73〜+0.997 と大きく、前年の増減のペースが今年もほぼ続く。北海道の 0.997 は 1 にほぼ等しく、差分した系列にもまだ単位根が残っている(減少が年々加速している)ので、d=2 を検討する合図になる。大阪府は 0.725 と最も小さい。AIC は万人単位の値で、系列ごとに水準もばらつきも違うため県どうしを比べる指標ではない。
実務では 1 系列を細かく分析するより、 「数十〜数千系列に一律でモデルを当てる」運用が多いです。 ここでは 47 都道府県すべてに ARIMA を fit し、 5 年先予測を生成する典型コードを示します。
🎯 このコードでやること: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)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:万人単位で 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) を当てたときの係数は県ごとに確かめる必要がある。
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}') |
📤 実行すると次の出力が得られる:
💬 結果の読み方:北海道の前年差は平均 −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)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方: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)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:北海道の総人口は元系列で ADF 統計量 15.846(p=1.0)と単位根を全く棄却できず、1 階差分後も 2.023(p=0.9987)で棄却できない。統計量が正の大きな値になるのは、減少が年々加速していて差分系列にもまだ下向きの傾きがあるため。北海道に ARIMA を当てるなら d=2 か、トレンド項を入れたモデルを検討する。ただし 12 点の ADF は検出力が低く、判定そのものが揺れやすい。
手動グリッド(実装 5)は理解には良いが、 本番では pmdarima.auto_arima が定番。 R の forecast::auto.arima の Python 移植で、 stepwise アルゴリズムで効率的に最適 (p,d,q)(P,D,Q,s) を探索します。
🎯 このコードでやること:東京都人口に 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)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:万人単位で探索すると定数(ドリフト)付きの 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 も自動探索可能。
SARIMAX + 自作 grid でも十分代替可能。これで本ページの実装は 計 17 本。 「Box-Jenkins 法 4 ステップ × 全 SSDSE 都道府県」を一回りすれば、 時系列分析の感覚は確実に身につきます。 「ARIMA を超える」モデルに進むときも、 ここで体得した思考フローはそのまま使えます。
SSDSE-B-2026 の A1101(総人口)や A4101(出生数)のような 12 年程度(2012-2023)の年次系列に ARIMA を当てる際に頻発する 5 つの落とし穴。 短期サンプル + 外因ショック(コロナ・震災)が混在するため、 定常性・差分次数・季節性の取り扱いが特に難しくなります。
ARIMA(p,d,q) は時系列の定常化 → 自己回帰 + 移動平均 → 予測の枠組みで、 前後の道具とパイプラインで連結する。
SSDSE-B-2026 の時系列軸 (例: 各都道府県の 2010-2024 人口) で d=1 差分後 ARIMA(1,1,1) を当て、 2025-2030 を予測する流れが標準パイプライン。
ARIMA のオーダー (p, d, q) と派生選択は「定常性」「季節性」「非線形性」の 3 軸で判定する。
auto_arima (pmdarima) で AIC 最小のオーダーを自動探索 → Ljung-Box で残差確認、 という半自動ワークフローが実務の定石。
既存の各セクションと 🎮 ウィジェットに加えて、 別角度から ARIMA を掘り下げます。 題材は SSDSE-B-2026 の 秋田県 総人口 A1101(2012-2023, n=12)。 この系列は 1,063,000 人 → 914,000 人へほぼ単調に減少する、 教科書的な非定常トレンドです(実測)。
ARIMA(p, d, q) は名前がそのまま設計図です。 まず定常化(I)、 それから予測(AR+MA) という順で読むと腑に落ちます。
明確に減り続ける秋田県人口でも、 定数項(ドリフト)を入れ忘れると予測が水平線になります。 ARIMA(0,1,0)(ランダムウォーク)を drift 無し/有りで当てた実測比較がこちら。
差分系列の平均(=毎年の減少幅)を定数項として入れて初めて、 モデルは「減り続ける」未来を描けます。 d≥1 のとき statsmodels の既定は trend='n'(ドリフト無し)なので、 トレンドのある系列では trend='t'(または 'c')を明示するのが定石。 「なぜか予測が真横に伸びる」ときは、 まずここを疑ってください。
📝 補足(別角度):既存の 📝 は「外生変数・アンサンブルが常には効かない」話でしたが、 こちらはモデル指定そのもの(ドリフト項)で予測が激変するという指摘です。 秋田県の実測では AIC が 242.65→191.16 とドリフト有りが圧勝で、 差分後の系列に平均(傾き)が残るかどうかを必ず確認すべきことを示します。 自動選択(auto_arima)は with_drift を探索してくれますが、 手動で ARIMA を書くときは trend 引数を意識しましょう。
d の決め方は「定常になるまで、 ただし最小限だけ」差分する、が鉄則です。 秋田県 A1101 で単位根検定(ADF)を実測すると次のとおり。
興味深いのは、 1 階差分しても ADF が定常と言わない点です。 これは差分系列(毎年の減少幅)にまだ緩やかな傾きが残る(減少が加速している)ため。 とはいえ n=12 では検定力が極端に低く、 p 値は目安にすぎません。 ここで反射的に d=2 へ上げるのは危険で、 過剰差分は系列を壊し、 人工的な負の自己相関(見かけの MA 構造)を生みます。 短い系列では、 検定の数字を鵜呑みにせず ACF/PACF の形と AIC/BIC を併用し、 d は 0〜1 に留めるのが無難です。
古典的な次数選択は、 差分後系列の自己相関(ACF)と偏自己相関(PACF)の「形」を読む職人技でした。 目安は次の対応表です。
これが Box-Jenkins 法(同定 → 推定 → 診断 → 予測)の「同定」ステップです。 現代では auto_arima が AIC/BIC 最小化でこの職人技を代替しますが、 候補が割れたときに ACF/PACF を目で見て裏取りすると誤特定を減らせます。 最後は残差の白色性(Ljung-Box 検定)で診断するのを忘れずに。
2 つの非定常系列(例:人口 A1101 と何らかの経済指標)をそのまま回帰すると、 実は無関係でも高い決定係数が出る見せかけの回帰(spurious regression)に陥ります。 時系列では「まず定常化してから関係を見る」「単位根・共和分を確認する」が原則。 また ARIMA は本質的に過去パターンの外挿であり、 少子化の加速・政策転換・災害といった構造変化の先には無力です。 秋田県の減少加速のように、 過去の平均ペースが未来にそのまま続く保証はありません。 予測は「現状のダイナミクスが続くなら」という条件付きの数字として読みましょう。
※ SARIMA・auto_arima・Prophet・LSTM は本教材に独立ページが無いため、 本文中のテキスト解説にとどめています。
スライダーで AR係数 φ・MA係数 θ・和分の階数 d を動かすと、 固定した同一のホワイトノイズ列 et から生成される ARIMA(1, d, 1) 系列がリアルタイムに変化します。 上段の系列グラフをタップ/ドラッグすると、その時点に大きなショックを注入でき、 AR の「粘り」・MA の「平滑」・和分の「累積」がどう働くかを体感できます。 下段は同じ系列の自己相関(ACF)です。 ノイズ列は固定シードなので、変わるのは係数の効果だけです。