論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
時系列分析
Time Series Analysis
時間順に並んだデータを分析する手法群。自己相関や周期性、トレンドが特徴。
時系列time series

🔖 キーワード索引

「time series」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「time series」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

time series統計分析SSDSE-B-2026前提条件適用範囲落とし穴関連手法Python 実装検証方法

これらのキーワードは「time series の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

💡 30秒で分かる結論

🍰 まずはやさしく

時間順に並んだデータを分析する方法です。

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

スマホで見る毎日の気温の変化などが例です。

この章では分析の基本と代表的なモデルを読みます。

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

📍 学習の3ステップ

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

🔧 Python実装パターン

🎯 このコードでやること:時系列を扱う基本の型。SSDSE-B-2026 から東京都の「食料費(二人以上の世帯)」を取り出し、年度の古い順に並べて 12 年分の系列にし、前年差の平均を出して折れ線で描く。

📥 入力例(SSDSE-B-2026、東京都の 12 行から 3 行)
都道府県  年度  食料費(二人以上の世帯)
東京都    2012   79991
東京都    2020   92079
東京都    2023   97776
…(CSV 上は 2023 → 2012 の降順に並んでいる)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 基本パターン:1 つの県・1 つの指標を年度順に並べて時系列にする
import pandas as pd
import matplotlib.pyplot as plt

# データ読み込み(header=1 で 2 行目の日本語列名を見出しにする)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)

# CSV は新しい年度が先(2023 → 2012)に並ぶので、年度で並べ替えてから使う
tk = df[df['都道府県'] == '東京都'].sort_values('年度').set_index('年度')
s = tk['食料費(二人以上の世帯)']
print(s.to_string())
print('前年差の平均:', round(s.diff().mean(), 1))

# 可視化:横軸を年度にした折れ線
s.plot(marker='o')
plt.ylabel('食料費(円/月)')
plt.show()
📤 実行例(実測) 年度 2012 79991 2013 81466 2014 82178 2015 84843 2016 84980 2017 86412 2018 87282 2019 89185 2020 92079 2021 90894 2022 87973 2023 97776 前年差の平均: 1616.8
💬 読み方:東京都の食料費は 2012 年度の 79,991 円から 2023 年度の 97,776 円へ、11 年で約 22% 増えた。前年差の平均 1,616.8 円は (97,776 − 79,991) ÷ 11 と同じ値で、途中の上下は打ち消し合って消える。実際には 2020 年度の 92,079 円のあと 2 年続けて下がり、2023 年度に 9,803 円跳ね上がっているので、平均の増え方だけで翌年を予測すると外しやすい。

📚 統計概念マップでの位置

このページの上にある3つの概念マップ(関係マップ、 包含マップ、 ツリーマップ)でこの概念の位置づけが視覚的に分かります。 関連手法を辿って学習を進めましょう。

🎯 SSDSE-B-2026 で挑戦

統計データ活用コンペティションのSSDSE-B-2026データは、 47都道府県の社会経済データ。 この概念を使って以下のような分析ができます:

💡 よく使うコマンド集

機能 Python (pandas) Python (scipy)
要約統計df.describe()stats.describe()
平均df.mean()np.mean()
標準偏差df.std()np.std()
相関df.corr()stats.pearsonr()
t検定—stats.ttest_ind()
回帰—stats.linregress()
分布フィッティング—stats.norm.fit()

🚧 一般的な落とし穴と対策

📊 結果報告の標準フォーマット

🌐 関連分野での応用

🎓 さらに学ぶための文献

🔗 統計用語ネットワーク

この概念は、 他の多くの統計概念と密接に関連しています。 ジャストインタイム型学習では、 必要に応じて関連用語へジャンプしながら全体像を構築します。

主要な関連概念のグループ

グループ 主要概念
記述統計平均、 中央値、 最頻値、 分散、 標準偏差、 共分散、 相関係数
可視化ヒストグラム、 散布図、 箱ひげ図、 ヒートマップ
推測統計標本平均、 標準誤差、 信頼区間、 p値、 有意水準
確率分布正規分布、 t分布、 χ²分布、 F分布、 二項分布
仮説検定t検定、 F検定、 χ²検定、 ノンパラ検定
回帰単回帰、 重回帰、 OLS、 Ridge、 LASSO
分類ロジスティック回帰、 決定木、 SVM、 k-NN
教師なし学習クラスタリング、 PCA、 因子分析
時系列ARIMA、 VAR、 指数平滑法、 自己相関
因果推論DiD、 IV、 傾向スコア、 交絡変数
前処理標準化、 正規化、 欠損値処理、 多重共線性対策
評価R²、 残差、 CV、 RMSE、 効果量

学習順序の推奨

  1. 記述統計(平均、 分散、 標準偏差)
  2. 可視化(ヒストグラム、 散布図)
  3. 確率分布(正規分布)
  4. 推測統計(標準誤差、 信頼区間、 p値)
  5. 仮説検定(t検定、 χ²検定)
  6. 相関と回帰(単回帰、 重回帰)
  7. 多変量解析(PCA、 クラスタリング)
  8. 機械学習(決定木、 RF、 NN)
  9. 時系列・因果推論(応用)

📝 実践練習 — SSDSE-B-2026 で挑戦

初級課題

  1. 東北6県の家計食料費の基本統計量を計算
  2. 食料費のヒストグラムを描く
  3. 食料費と教育費の散布図を描く
  4. 都道府県を「東日本/西日本」に分け、 平均を比較

中級課題

  1. 家計支出 5項目で相関行列を作成、 ヒートマップ可視化
  2. 食料費 → 教育費の単回帰を実行、 残差分析
  3. 家計5項目で PCA を実施、 バイプロット表示
  4. k-means (k=3) で都道府県をクラスタリング、 解釈

上級課題

  1. 地域別の家計パターンに有意差があるか ANOVA で検定
  2. 重回帰で教育費を予測、 多重共線性を VIF で確認
  3. Ridge/LASSO で正則化、 CV で α を最適化
  4. 階層クラスタリングと Ward 法で都道府県を分類、 デンドログラム作成

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

🍰 まずはやさしく

時間の流れに沿ったデータの分析手法です。

データサイエンスの重要な考え方を学ぶために使います。

都道府県ごとの所得の変化などを分析します。

定義から実装までを6つの視点で読み解きます。

論文中に 「時系列分析」として登場する用語。

時系列分析 とは:時間順に並んだデータを分析する手法群。自己相関や周期性、トレンドが特徴。

本ページでは「time series」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。

「time series」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。

🎨 直感で掴む — 時系列 の本質

🍰 まずはやさしく

過去のデータが未来のヒントになる考え方です。

データの傾向や周期性を掴むために使います。

婚姻数や出生数の年ごとの変化が例です。

時間的なつながりがどう影響するかを読みます。

時系列(time series)は「同じ対象を時間順に観測したデータ」。 一般のデータが 行と行が独立と仮定するのに対し、 時系列は 時間的な依存関係(自己相関)が本質。 「昨日の気温が分かれば今日の気温も予測しやすい」ように、 過去が未来に情報を持つ。

SSDSE-B-2026 で取れる時系列の例:

時系列の 4 つの構成要素(古典的分解): $y_t = T_t + S_t + C_t + I_t$。 トレンド(長期的傾向)、 季節成分(年内周期)、 循環成分(数年周期)、 不規則成分(残差)に分けて理解する。 SSDSE-B-2026 の出生数は 下降トレンドに コロナの一時急減(不規則)が重なった構造。 月次データなら 3 月卒業 → 結婚増 → 翌年出生増という季節性も見える。

時系列が「ふつうのデータ」と決定的に違う 3 点:

主な分析タスク: トレンド抽出(移動平均、 LOESS)、 季節調整(X-12-ARIMA、 STL 分解)、 予測(ARIMA、 Prophet、 LSTM)、 異常検知(Z-score、 STL 残差)、 因果推論(Granger 因果、 介入研究)。 SSDSE-B-2026 の都道府県 × 年度パネルでは パネル時系列(固定効果モデル、 動学パネル GMM)が定番。

📐 数式または定義 — 時系列 の形式的表現

🍰 まずはやさしく

時系列を数式で表したルールのようなものです。

今の値を過去の値から計算するために使います。

昨日のテストの点数で今日の点数を予想する例です。

数式の中にある記号の意味を一つずつ読みます。

直感で全体像を掴んだら、 次は厳密な定義を見ます。 数式は短いものでも、 「何を入力にして、 何を出力するのか」を意識して読むと早く慣れます。

【AR(p) モデル — 過去 p 期の値で現在を説明】
$$ y_t = c + \phi_1 y_{t-1} + \phi_2 y_{t-2} + \cdots + \phi_p y_{t-p} + \varepsilon_t \quad (\mathrm{AR}(p)) $$
この数式は「時系列 がどう計算されるか」を最短で示したもの。 記号の意味は次の「🔬 数式を言葉で読み解く」で 1 つずつ解説します。
📚 数式が苦手な方へ:1 つの長い式を一度に理解しようとせず、 記号ごとに「言葉に翻訳」するのが王道。 紙に書き写してから、 自分の言葉で音読してみてください。

🔬 数式を言葉で読み解く — 時系列 の記号辞書

上の数式に出てくる各記号が何を表すかを、 言葉で翻訳します。 1 つずつ自分の言葉で言い換えられるようになると、 論文や教科書のスピードが一気に上がります。

記号意味(言葉での説明)
$y_t$時刻 $t$ の値
$c$切片(長期平均に関係)
$\phi_i$$i$ 期前の自己回帰係数
$\varepsilon_t$誤差項(ホワイトノイズを仮定)
$p$モデルの「次数」=何期前まで使うか
📌 読み下しのコツ:左から右に「主語 → 述語 → 目的語」と見立てて、 「これは何を、 どうしている式か?」と一文で要約してみてください。 慣れれば 5 秒で読めます。

🧮 SSDSE-B-2026 実値計算 — 出生数の ARIMA 予測

「全国出生数」の年次データ(SSDSE-B-2026 の 47 都道府県を年度ごとに合計した 12 点)に ARIMA(1,1,1) を当てはめ、 5 年先まで予測します。 年次データなので季節項は付けません(コードの seasonal_order=(0,0,0,0) がそれに対応)。

🎯 このコードでやること:SSDSE-B-2026 から全国の出生数(47 都道府県の合計)を年度ごとに作り、ADF 検定で定常性を確かめたうえで ARIMA(1,1,1) を当てはめ、2024〜2028 年度の 5 年先を予測する。

📥 入力例(SSDSE-B-2026 を header=1 で読み、年度ごとに出生数を合計した 12 点)
年度   出生数(全国)
2012  1,037,165
2018    918,361
2023    727,269
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
import statsmodels.api as sm

# SSDSE-A は市区町村単位で見出しが 3 行あり、年次の系列にならない。
# 年度の入っている SSDSE-B から全国の出生数の推移(2012〜2023 年)を作る
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
df['年度'] = pd.to_numeric(df['年度'], errors='coerce')
df['出生数'] = pd.to_numeric(df['出生数'], errors='coerce')
ts = df.groupby('年度')['出生数'].sum().sort_index()
print(ts)

# ADF 検定(定常性確認)
adf = sm.tsa.adfuller(ts)
print(f'ADF p-value = {adf[1]:.4f}')   # > 0.05 なら非定常

# ARIMA(1,1,1)(季節項なし)
mod = sm.tsa.statespace.SARIMAX(ts, order=(1,1,1), seasonal_order=(0,0,0,0)).fit(disp=False)
print(mod.summary())
forecast = mod.get_forecast(steps=5)
print(forecast.predicted_mean.round(0))
print(forecast.conf_int().round(0))
📤 実行例(実測) 年度 2012 1037165 2013 1029763 2014 1003544 2015 1005668 2016 977177 2017 946095 2018 918361 2019 865212 2020 840808 2021 811611 2022 770750 2023 727269 Name: 出生数, dtype: int64 ADF p-value = 1.0000 SARIMAX Results ============================================================================== Dep. Variable: 出生数 No. Observations: 12 Model: SARIMAX(1, 1, 1) Log Likelihood -123.953 Date: Sat, 26 Sep 2026 AIC 253.905 Time: 15:47:26 BIC 255.099 Sample: 0 HQIC 253.153 - 12 Covariance Type: opg ============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ ar.L1 0.9411 0.017 56.296 0.000 0.908 0.974 ma.L1 -1.0000 0.576 -1.735 0.083 -2.129 0.129 sigma2 3.505e+08 1.64e-09 2.13e+17 0.000 3.5e+08 3.5e+08 =================================================================================== Ljung-Box (L1) (Q): 1.37 Jarque-Bera (JB): 0.45 Prob(Q): 0.24 Prob(JB): 0.80 Heteroskedasticity (H): 1.06 Skew: 0.39 Prob(H) (two-sided): 0.96 Kurtosis: 2.39 =================================================================================== Warnings: [1] Covariance matrix calculated using the outer product of gradients (complex-step). [2] Covariance matrix is singular or near-singular, with condition number 8.31e+33. Standard errors may be unstable. 12 714049.0 13 701607.0 14 689897.0 15 678877.0 16 668506.0 Name: predicted_mean, dtype: float64 lower 出生数 upper 出生数 12 676950.0 751148.0 13 650112.0 753102.0 14 627974.0 751820.0 15 608650.0 749105.0 16 591364.0 745648.0
💬 読み方:ADF の p 値は 1.0000 で、12 年間ほぼ一方向に減り続ける出生数は非定常と判定された(d=1 を入れる理由)。推定値は ar.L1 = 0.941 に対して ma.L1 = −1.000 と境界に張り付き、sigma2 の標準誤差も 1.64e-09 と潰れていて、警告 [2](条件数 8.31e+33)のとおり係数と標準誤差はあてにならない。予測は 2024 年度 714,049 人から 2028 年度 668,506 人へ減り続けるが、95% 区間の上限は 5 年とも 74〜75 万人台にとどまり、2023 年度の実績 727,269 人を上回る可能性も区間に含まれる。

STL 分解で構成要素を可視化

🎯 このコードでやること:全国出生数の 12 点を STL で「トレンド+周期 5 の成分+残差」に分けて図にする。年次データに決まった周期は無いので、period=5 は仮に置いた値。

📥 入力例: 上のコードで作った ts(全国出生数、2012〜2023 年度の 12 点)。
1
2
3
from statsmodels.tsa.seasonal import STL
stl = STL(ts, period=5).fit()  # 5 年周期と仮定
stl.plot()
📤 このブロックは標準出力には何も出さない(図を描くだけ)。図の中身を数値で確かめると、トレンドは 2012 年度 1,061,891 → 2023 年度 730,519、周期 5 の成分は −20,866〜+14,944、残差は −3,860〜+13,690。
💬 読み方:12 年間の減少のほぼすべてがトレンドに入り、「周期 5 の成分」は最大 2 万人ほどの振れを拾っただけ。period=5 は根拠のある周期ではないので、この成分を「5 年周期の変動」と解釈してはいけない。年次データで STL を使うのは、トレンドの滑らかな形を見るためと割り切る。

予測結果(上の ARIMA(1,1,1) の実測値)

年度実測(万人)ARIMA(1,1,1) 予測(万人)95% 予測区間(万人)
202372.7——
2024—71.4[67.7, 75.1]
2025—70.2[65.0, 75.3]
2026—69.0[62.8, 75.2]
2027—67.9[60.9, 74.9]
2028—66.9[59.1, 74.6]

🧮 実値で計算してみる — SSDSE-B-2026 で 時系列 を体感

数式だけでは「分かった気になる」だけで終わりがち。 ここで SSDSE-B-2026(教育用標準データセット — 47 都道府県 × 100+ 指標、 2012-2023 年度)の実値を当てはめて、 時系列 の挙動を電卓的に追体験します。

👉 計算例:SSDSE-B-2026 で東京都の総人口は 2019 年 14,007,000 → 2020 年 14,047,594 → 2021 年 14,010,000 → … → 2023 年 14,086,000 と微増基調。 2019→2023 年の前年差は +40,594・−37,594・+28,000・+48,000 人と上下するが、どれも総人口の 0.35% 未満で、「前年の値をそのまま翌年の予測に使う」だけでも誤差は 5 万人に届かない。都道府県の人口は前年の値が翌年をほぼ決める、持続性(persistence)の強い時系列であることが分かる。

SSDSE-B-2026 は 統計センターの SSDSE 配布ページ から CSV を直接ダウンロードできます。 本サイトでは data/raw/SSDSE-B-2026.csv に配置している前提でコードを書いています。

🧮 数式に値を入れて手で計算する: 時系列の分解

合成 12 月データから トレンド・季節・残差を分解する。

Step 1: 元データ

x = [100, 95, 110, 130, 140, 145, 150, 145, 130, 115, 100, 95] 12 ヶ月

Step 2: トレンド (3 期移動平均)

MA3 はおおむね 100→145→100 で山型 (季節性含む) 12 期 MA で純トレンド ≈ 121.25 (平坦) 季節成分: 夏 (6-8月) ≈ +25, 冬 (12-2月) ≈ -25

🐍 Python で再現

1
2
3
4
5
6
import numpy as np
x = np.array([100, 95, 110, 130, 140, 145, 150, 145, 130, 115, 100, 95])
trend = x.mean()
ma3 = np.convolve(x, np.ones(3)/3, mode='valid')
print(f"全体平均: {trend}")
print(f"3 期 MA 範囲: {ma3.min():.1f} - {ma3.max():.1f}")

📤 実行結果

全体平均: 121.25 3 期 MA 範囲: 101.7 - 146.7

💬 手計算 (Step 2) と Python 出力が完全一致。

🐍 Python 実装バリエーション

A. statsmodels.tsa(標準ライブラリ)

🎯 このコードでやること:statsmodels の SARIMAX で、全国出生数(年次 12 点)に季節項なしの ARIMA(1,1,1) を当てはめ、推定結果の要約を出す。

📥 入力例: 上で作った ts(全国出生数、2012〜2023 年度の 12 点)。
1
2
3
4
5
6
7
import statsmodels.api as sm
# ts は年度ごとの全国出生数(12 時点)。年次データに「12 か月周期」は無いので、
# seasonal_order=(1,1,1,12) を付けると季節差分でデータが尽き、標準誤差が非数になる。
# 月次データを扱うときだけ季節項を入れること。
mod = sm.tsa.statespace.SARIMAX(ts, order=(1,1,1), seasonal_order=(0,0,0,0))
res = mod.fit(disp=False)
print(res.summary())
📤 実行例(実測) SARIMAX Results ============================================================================== Dep. Variable: 出生数 No. Observations: 12 Model: SARIMAX(1, 1, 1) Log Likelihood -123.953 Date: Sat, 29 Aug 2026 AIC 253.905 Time: 10:14:59 BIC 255.099 Sample: 0 HQIC 253.153 - 12 Covariance Type: opg ============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ ar.L1 0.9411 0.017 56.296 0.000 0.908 0.974 ma.L1 -1.0000 0.576 -1.735 0.083 -2.129 0.129 sigma2 3.505e+08 1.64e-09 2.13e+17 0.000 3.5e+08 3.5e+08 =================================================================================== Ljung-Box (L1) (Q): 1.37 Jarque-Bera (JB): 0.45 Prob(Q): 0.24 Prob(JB): 0.80 Heteroskedasticity (H): 1.06 Skew: 0.39 Prob(H) (two-sided): 0.96 Kurtosis: 2.39 =================================================================================== Warnings: [1] Covariance matrix calculated using the outer product of gradients (complex-step). [2] Covariance matrix is singular or near-singular, with condition number 8.31e+33. Standard errors may be unstable.
💬 読み方:上の ARIMA 予測と同じモデルなので、AIC 253.905、ar.L1 = 0.9411、ma.L1 = −1.0000 もまったく同じ値になる。ma.L1 が −1 に張り付くのは、ほぼ直線的に減る系列に差分と MA 項を重ねたときの典型的な症状で、下の落とし穴 2 の「過剰差分」にあたる。Ljung-Box の Prob(Q) = 0.24 で残差の自己相関は見つからないが、12 点では検出力が小さい。

B. pmdarima(auto_arima で自動次数決定)

🎯 このコードでやること:pmdarima の auto_arima で、全国出生数(年次 12 点)に合う ARIMA の次数を AIC 最小で自動探索する。年次データなので季節項は探さない(seasonal=False)。

📥 入力例: 上で作った ts(全国出生数、12 点)。
1
2
3
4
5
import pmdarima as pm
# ts は年次データ(12 点)なので季節項は探さない(m=12 は月次データ用)
auto = pm.auto_arima(ts, seasonal=False, stepwise=True,
                     information_criterion='aic')
print(auto.summary())
📤 実行例(実測。pmdarima 2.1.1・statsmodels 0.14.5 で実行。Date・Time の行は実行時刻) SARIMAX Results ============================================================================== Dep. Variable: y No. Observations: 12 Model: SARIMAX(1, 1, 0) Log Likelihood -120.117 Date: Sat, 26 Sep 2026 AIC 246.234 Time: 21:57:28 BIC 247.428 Sample: 0 HQIC 245.482 - 12 Covariance Type: opg ============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ intercept -2.751e+04 7870.719 -3.495 0.000 -4.29e+04 -1.21e+04 ar.L1 0.0202 0.231 0.088 0.930 -0.432 0.473 sigma2 1.899e+08 0.302 6.3e+08 0.000 1.9e+08 1.9e+08 =================================================================================== Ljung-Box (L1) (Q): 0.03 Jarque-Bera (JB): 1.61 Prob(Q): 0.87 Prob(JB): 0.45 Heteroskedasticity (H): 0.45 Skew: 0.72 Prob(H) (two-sided): 0.46 Kurtosis: 4.21 =================================================================================== Warnings: [1] Covariance matrix calculated using the outer product of gradients (complex-step). [2] Covariance matrix is singular or near-singular, with condition number 2.49e+24. Standard errors may be unstable.
💬 読み方:Model 行は SARIMAX(1, 1, 0) で、auto_arima は定数(intercept)付きの ARIMA(1,1,0) を AIC 246.234 で選んだ。上で手で当てた定数なしの ARIMA(1,1,1)(AIC 253.905)より 7.7 小さい。intercept = −27,510 は差分をとった系列に付く定数で、−27,510 ÷ (1 − 0.0202) ≈ −28,080 が「毎年約 2.8 万人ずつ減る」ドリフトにあたる(実データの 2012→2023 年度の平均減少は年 28,172 人)。ar.L1 = 0.0202(p = 0.930)はほぼ 0 なので、実質は「一定の人数ずつ減るランダムウォーク」になっている。sigma2 の標準誤差 0.302 は共分散行列が特異(Warnings [2])なための値で、信用しない。

C. prophet(ビジネス向け・休日効果対応)

🎯 このコードでやること:Prophet で全国出生数(年次 12 点)の 2024〜2028 年を予測し、予測値と不確実性区間を表に出す。

📥 入力例: ds = 2012〜2023 年の各 1 月 1 日、y = 全国出生数(上で作った ts)。
1
2
3
4
5
6
7
8
9
10
from prophet import Prophet
d = pd.DataFrame({'ds': pd.to_datetime(ts.index, format='%Y'), 'y': ts.values})
# 年次データは 1 年に 1 点しか無いので、年周期(yearly_seasonality)は推定できない
m = Prophet(yearly_seasonality=False, weekly_seasonality=False,
            daily_seasonality=False).fit(d)
# ds は各年の 1 月 1 日なので、未来も年初('YS')で 5 年分つくる
future = m.make_future_dataframe(periods=5, freq='YS')
fcst = m.predict(future)
print(fcst[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(5).round(0))
m.plot(fcst)
📤 実行例(実測) ds yhat yhat_lower yhat_upper 12 2024-01-01 696925.0 689133.0 704733.0 13 2025-01-01 661003.0 651212.0 670032.0 14 2026-01-01 625180.0 612372.0 637801.0 15 2027-01-01 589357.0 570012.0 607975.0 16 2028-01-01 553534.0 526919.0 579014.0 (yhat_lower・yhat_upper はサンプリングで求めるので、実行ごとに数百人ずつ変わる)
💬 読み方:Prophet の予測は 2024 年 696,925 人から 2028 年 553,534 人へ、毎年約 3.6 万人ずつ減る直線になった。同じデータの ARIMA(1,1,1)(2028 年度 668,506 人)より 11 万人以上低いのは、Prophet が 2019 年以降の急な落ち込みを傾きの変化として取り込み、その傾きをそのまま延ばすため。区間は Prophet 既定の 80%(ARIMA は 95%)なので、幅をそのまま比べない。

D. sktime(パイプライン・CV を sklearn 風に)

🎯 このコードでやること:sktime の ARIMA(1,1,1) で、全国出生数の最後の 5 年(2019〜2023 年度)を検証用に取り分け、残り 7 年で学習して 5 期先を予測する。

📥 入力例: 上で作った ts(全国出生数、12 点)。temporal_train_test_split で学習 7 点(2012〜2018 年度)・検証 5 点に分ける。
1
2
3
4
5
6
from sktime.forecasting.arima import ARIMA
from sktime.split import temporal_train_test_split
y_train, y_test = temporal_train_test_split(ts, test_size=5)
forecaster = ARIMA(order=(1,1,1), suppress_warnings=True).fit(y_train)
y_pred = forecaster.predict(fh=list(range(1, 6)))
print(y_pred)
📤 sktime はこの教材の実行環境に入っていないので実測はない(pip install sktime が必要)。
💬 読み方:学習に使う 2012〜2018 年度は年 2 万人前後の減り方(1,037,165 → 918,361 人)だったのに対し、2018→2019 年度は 5.3 万人減り、検証期間の 2019〜2023 年度も年 3.4 万人のペースで減っている(865,212 → 727,269 人)。過去の傾きを延ばすモデルは検証期間で実績より高めに外れやすく、その外れ方を y_pred と y_test の差で確かめるのがこのコードの目的。

E. scipy.signal による周期検出

🎯 このコードでやること:scipy.signal.periodogram で全国出生数(12 点)のパワースペクトルを計算し、周波数ごとの強さを片対数グラフに描く。

📥 入力例: 上で作った ts(全国出生数、12 点)。fs=1 なので周波数の単位は「1 年あたりの回数」。
1
2
3
4
from scipy.signal import periodogram
f, Pxx = periodogram(ts.values, fs=1)
import matplotlib.pyplot as plt
plt.semilogy(f, Pxx); plt.xlabel('frequency'); plt.ylabel('PSD')
📤 このブロックは標準出力には何も出さない(図を描くだけ)。f と Pxx を確かめると、周波数は 0, 1/12, 2/12, …, 6/12 の 7 点で、平均を引いたあとのパワーの 67% が最も低い周波数 1/12(周期 12 年)に集まる。
💬 読み方:パワーが 1/12 に集中するのは、12 年間ずっと減り続けるトレンドが「系列全体で 1 周期の波」に見えるからで、12 年周期の循環があるという意味ではない。トレンドのある系列で周期を探すときは、差分を取るか STL でトレンドを除いてから periodogram をかける。

🐍 Python 実装 — 時系列 を SSDSE-B-2026 で動かす

🎯 このコードでやること:SSDSE-B-2026 から東京都の 12 年度分を取り出して古い順に並べ、合計特殊出生率の前年差・3 年移動平均・lag-1 自己相関・直線トレンドと、総人口との相関(水準どうし・前年差どうし)を計算する。

📥 入力例(SSDSE-B-2026 の東京都・2012〜2023 年度の 12 行から 3 行) 都道府県 年度 合計特殊出生率 総人口 東京都 2012 1.09 13,234,000 東京都 2015 1.24 13,515,271 東京都 2023 0.99 14,086,000 …(全 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
# 時系列 を SSDSE-B-2026 で確かめる最小コード
import pandas as pd
import numpy as np

# 1) SSDSE-B-2026(教育用標準データセット)を読み込み
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
print('shape:', df.shape)        # (564, 112) — 47 都道府県 × 12 年度
print('cols head:', list(df.columns[:8]))

# 2) 時系列にするので年度は絞らず、1 つの県(東京都)の 12 年度分を古い順に並べる
tk = df[df['都道府県'] == '東京都'].sort_values('年度').set_index('年度')
print('rows for 東京都:', len(tk), '/ 年度:', tk.index.min(), '〜', tk.index.max())

# 3) 時系列 を動かすために必要な列だけ取り出す
y = tk['合計特殊出生率'].astype(float)
x = tk['総人口'].astype(float)

# 4) 時系列 の本処理(このページの主題): 前年差・移動平均・自己相関・トレンド
print('---- 時系列 結果 ----')
out = pd.DataFrame({'出生率': y, '前年差': y.diff().round(2),
                    '3年移動平均': y.rolling(3).mean().round(3),
                    '総人口(万人)': (x / 1e4).round(0)})
print(out.to_string())
print('lag-1 自己相関 (出生率):', round(y.autocorr(lag=1), 3))
slope = np.polyfit(y.index, y.values, 1)[0]
print('出生率の直線トレンド (1 年あたり):', round(slope, 4))
print('corr(x, y) 12 年度:', round(y.corr(x), 3))
print('corr(前年差どうし):', round(y.diff().corr(x.diff()), 3))
📤 実行例(実測) shape: (564, 112) cols head: ['年度', '地域コード', '都道府県', '総人口', '総人口(男)', '総人口(女)', '日本人人口', '日本人人口(男)'] rows for 東京都: 12 / 年度: 2012 〜 2023 ---- 時系列 結果 ---- 出生率 前年差 3年移動平均 総人口(万人) 年度 2012 1.09 NaN NaN 1323.0 2013 1.13 0.04 NaN 1331.0 2014 1.15 0.02 1.123 1340.0 2015 1.24 0.09 1.173 1352.0 2016 1.24 0.00 1.210 1365.0 2017 1.21 -0.03 1.230 1377.0 2018 1.20 -0.01 1.217 1389.0 2019 1.15 -0.05 1.187 1401.0 2020 1.12 -0.03 1.157 1405.0 2021 1.08 -0.04 1.117 1401.0 2022 1.04 -0.04 1.080 1404.0 2023 0.99 -0.05 1.037 1409.0 lag-1 自己相関 (出生率): 0.84 出生率の直線トレンド (1 年あたり): -0.0115 corr(x, y) 12 年度: -0.354 corr(前年差どうし): 0.382

💬 東京都の合計特殊出生率は 2012 年度の 1.09 から 2015〜2016 年度の 1.24 まで上がり、そこから 7 年続けて下がって 2023 年度に 0.99 になった。直線トレンドの −0.0115/年は、この「上がってから下がる」形を 1 本の傾きにならしたもので、2017 年度以降の年 −0.03〜−0.05 という実際の落ち方より緩く見える。lag-1 自己相関 0.84 は前年の値が翌年をよく言い当てることを示し、12 点の時系列では独立な観測として数えられない。総人口との相関は水準どうしで −0.354、前年差どうしで +0.382 と符号が逆になるので、トレンドを持つ系列どうしの相関は差分を取ってから確かめる。

うまく動かないときは ①data/raw/SSDSE-B-2026.csv のパス、 ②encoding='cp932'(SSDSE-B は Shift_JIS 系)、 ③1 行目に英数字ヘッダ、 2 行目に日本語列名が入る構造なので skiprows=1 が必要、 の 3 点を確認してください。

⚠️ 時系列分析の落とし穴 7 連発

1. 定常性を検定せずに ARMA を当てはめる。単位根(unit root)を持つ系列に ARMA を当てると、 係数推定が不一致になり予測が暴走します。 ADF・KPSS・Phillips-Perron などを併用し、 必要なら 1 階差分(d=1)or 季節差分(D=1)を取った系列で再検定するのが正攻法です。

2. 過剰差分(over-differencing)に注意しない。「定常化のために」と差分を 2 回も 3 回も取ると、 MA 係数が −1 に張り付くなど不安定な推定が起きます。 KPSS で「定常」と出る最小回数を採用し、 残差の ACF/PACF を必ず目視確認しましょう。

3. 通常の CV(ランダム分割)でモデル選択する。未来から過去へのリークが起き、 評価指標が過剰に良く見えます。 必ず TimeSeriesSplit または expanding/sliding window で「過去→未来」順の評価を行い、 ホールドアウトも時系列末尾に取りましょう。

4. 季節性周期を間違える。月次データは m=12、 週次は m=52、 日次なら m=7(曜日)や m=365(年)。 SSDSE の年次データは原則季節性なしですが、 景気循環など長周期の隠れた季節性に注意。 STL 分解と periodogram の併用で確認しましょう。

5. 外れ値・構造変化を無視する。2008 リーマンショックや 2020 コロナ禍のような外的ショックは、 通常の AR/MA で吸収しきれません。 介入変数(dummy)として明示的に投入、 もしくは状態空間モデルで「構造変化」を扱う必要があります。

6. 信頼区間ではなく予測区間(PI)で報告すべきところを CI で報告。係数の CI は「真のパラメータ」の不確実性、 PI は「次の観測値」の不確実性で、 後者の方が広いのが正しい。 政策・経営判断には PI を必ず付け、 「点予測のみ」報告は厳禁です。

7. Prophet を万能と信じる。Prophet は柔軟で扱いやすい反面、 観測値が少ない系列・強い自己相関・複雑な季節性では SARIMA や状態空間モデルに劣ることが多いです。 必ず ARIMA 系・ETS・ナイーブ予測との水平比較を行いましょう。

⚠️ よくある落とし穴 — 時系列 で初学者がやりがちなミス

この用語を実務で使うときにつまずきやすい点を、 失敗パターン別に整理しました。 1 度経験すれば回避できるものばかりですが、 先に知っておくと事故が大幅に減ります。

❌ 定常性を確認しない
非定常データに ARMA を当てるとパラメータが発散する。 階差 ($d=1$) で対処。
❌ 残差の自己相関を残す
Ljung-Box 検定で残差が白色か確認。 残っているなら次数 $p, q$ を見直す。
❌ オーバーフィッティング
AIC/BIC で複数モデルを比較。 単純なものから順に。
🛡 防御策まとめ:「適用条件の確認 → 適切な前処理 → 結果と前提のペア記述」の 3 ステップを習慣にすれば、 ここに挙げた失敗の大半は回避できます。

🗺️ 統計手法選択フローチャート

Q1: 何を知りたい?

Q2: データの種類は?

Q3: サンプルサイズは?

Q4: 仮定は?

📏 効果量の参照表

p値だけでなく効果量も併記するのが現代統計の標準。 主要な指標と Cohen の解釈基準:

統計量 効果量 小 中 大
2群平均差Cohen's d0.20.50.8
相関r0.10.30.5
線形回帰R²0.020.130.26
ANOVAη² (eta²)0.010.060.14
χ²Cramér's V0.10.30.5
ロジスティックOdds Ratio1.52.54.0

🚀 実務応用の深掘り

典型的なプロジェクトの流れ

  1. 問題理解:ステークホルダーとの対話、 KGI/KPI 設定
  2. データ収集:内部DB、 公的データ(SSDSE等)、 API
  3. EDA:データの全体像把握、 異常検出
  4. 仮説立案:ドメイン知識からの仮説
  5. モデリング:シンプルから複雑へ段階的に
  6. 検証:CV、 ホールドアウト、 A/Bテスト
  7. 解釈:可視化、 SHAP、 部分依存プロット
  8. 展開:本番デプロイ、 監視

ベストプラクティス

論文・コンペでよく使う言い回し

日本語 英語
統計的に有意statistically significant
効果量effect size
95%信頼区間95% confidence interval (CI)
標本サイズsample size
検出力statistical power
第1種の誤りType I error / false positive
第2種の誤りType II error / false negative
多重比較問題multiple comparisons problem
過学習overfitting
汎化性能generalization
交差検証cross-validation (CV)

統計データ活用コンペでのコツ

🗺️ 概念マップ — 3つの視点で体系を理解する

時系列分析 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。

📍 体系階層のパス

🌐 統計・データサイエンス › 時系列 › 基礎 › 時系列分析(時間順に並んだデータ全般)

① 🔗 関係マップ — 「他の手法とどう繋がっているか」

中心に 時系列分析 を置き、 そこから ARIMA・VAR・指数平滑法 計 3 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。

凡例:現在の用語上位カテゴリ兄弟(並列)前提発展形応用先2階層先

② ⭕ 包含マップ — 「どのカテゴリに含まれているか」

大きな円が小さな円を包含する Circle Packing 図。 「時系列分析」は緑色でハイライト。

📍現在地:統計・データサイエンス

③ 🌳 ツリーマップ — 「面積で見るボリューム比較」

長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「時系列分析」は緑色でハイライト。

🎯 3つのマップの使い分け

マップ 分かること こんな時に見る
🔗 関係マップ手法間の横の関係(前提→発展→応用)「次に何を学べばよい?」 学習順序の判断
⭕ 包含マップ分類体系の入れ子構造(上位⊃下位)「この手法はどんなジャンルに属する?」
🌳 ツリーマップ分野の規模比較(面積=ボリューム)「データサイエンス全体の俯瞰像」

💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは 時系列分析 の隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス → 基礎 → 時系列分析 という入れ子の位置を示します。 「基礎には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。

🔗 隣接手法への橋渡し

時系列分析は独立した一手法ではなく、 前処理 → モデル選択 → 評価 → 予測の連鎖でひとつの分析パイプラインを構成する。

時系列を クロスセクション や パネルデータ と組み合わせると、 さらに「時間×地域」「時間×個体」の二次元構造を捉えられる。 SSDSE-B-2026 の都道府県年次データはまさにパネル形式で、 固定効果モデルや動学的パネル分析と接続する自然な拡張先。

🌳 手法選択フロー

「time series」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。

典型シナリオ別の手法選択

シナリオ重視する観点候補手法
データが大規模 (n が多い、 高次元)計算コスト / メモリ / 並列化が必要ARIMA 等
外れ値が多い / ノイズあり頑健性 / 外れ値除去 / 中央値ベースSARIMA 等
解釈性を重視する線形 / 木構造 / ルールベース指数平滑法 等
予測精度を最優先するアンサンブル / ハイパラ調整 / 交差検証Prophet 等
データが少ない正則化 / ベイズ / 転移学習 / 簡素なモデルLSTM 等
リアルタイム/オンライン処理ストリーミング / 軽量モデル / 逐次更新状態空間モデル 等

選んだ後の検証ステップ

  1. 前処理確認: 標準化 / 欠損処理 / カテゴリ変数のエンコード が適切か
  2. ハイパラ調整: 交差検証で安定する値を選ぶ
  3. 性能評価: タスクに応じた指標 (RMSE / Accuracy / F1 / AUC / シルエット等) を複数併用
  4. 頑健性チェック: 別手法 / 別シードで結果が大きく違わないか確認
  5. 解釈: 結果を分野知識と照らし合わせ、 意味のある発見になっているか検討

🎨 直感をさらに深める — 「順序」がすべてを変える

時系列の核心は「観測が時間順に並び、 隣り合う値が情報を共有している」点にある。 ふつうの表データ(クロスセクション)は行を入れ替えても意味が変わらないが、 時系列は並べ替えた瞬間に情報が壊れる。 これが i.i.d.(独立同分布)の仮定を捨てるということ。

4 成分への分解でイメージする:観測 $y_t$ を「長期の向き(トレンド $T_t$)+ 年内の繰り返し(季節性 $S_t$)+ 数年周期のうねり(循環 $C_t$)+ 説明のつかない揺れ(ノイズ $I_t$)」に分けて眺める。 「今どの成分を見ているのか」を意識するだけで、 グラフの読み方が一段深くなる。

自己相関=「過去が未来を予測する」を実データで体感。 SSDSE-B-2026[cp932, skiprows=[1]]で東京都の総人口(列 A1101)2012–2023 年の 12 時点を取り出すと、 13,234,000 人 → 14,086,000 人へと +852,000 人(+6.4%)のトレンド。 この系列のラグ 1 自己相関は r = 0.783で、 「昨年の人口が分かれば今年もほぼ分かる」高い persistence を示す。 秋田県(同 A1101)は逆に 1,063,000 → 914,000 人(−149,000 人、 −14.0%)の下降トレンドだが、 やはり r = 0.742と自己相関は高い。 上がる県も下がる県も「前年の値を強く引きずる」のが人口時系列の性質。

💡 直感のまとめ:時系列は「①順序に意味がある ②隣が似ている(自己相関)③成分に分けて読む」。 この 3 点だけ押さえれば、 あとの手法はすべてこの上に乗る応用にすぎない。

⚠️ 落とし穴を深掘り — 時系列で「うっかり」やる致命傷

① 見せかけの回帰(spurious regression)— 実データで再現

非定常な系列どうしを回帰すると、 因果がなくても高い相関が出る(Granger & Newbold 1974)。 SSDSE-B-2026 で東京都の総人口と秋田県の総人口(2012–2023)の相関を取ると r = −0.958。 東京は増え秋田は減るので強い負相関に見えるが、 両者に直接の因果はなく、 単に「別方向のトレンドを持つ」だけ。 実際、 1 階差分(前年差)を取ってから相関を計算すると r = +0.537 まで落ちる。 レベル(原系列)での相関はトレンドが作った蜃気楼だったわけだ。 時系列どうしの相関は、 まず定常性を確認してから解釈する(→ 見せかけの相関)。

② 定常性の確認(単位根)を飛ばさない

上の東京都人口は r(ラグ1)=0.783 と強い自己相関=単位根(unit root)が疑われる非定常系列。 ADF 検定(帰無仮説「単位根あり=非定常」)と KPSS 検定(帰無仮説「定常」)を併用し、 非定常なら 1 階差分を取る。 実際に差分を取ると東京で r(ラグ1)=0.656、 秋田で 0.742 → 0.343 と自己相関が下がり、 定常に近づく(これらも SSDSE-B-2026 の実測値)。

③ 時系列 CV で「未来漏れ」を絶対に起こさない

通常のランダム分割 CV は未来の情報で過去を予測するリークを生み、 評価が過剰に良く出る。 必ず TimeSeriesSplit や expanding / sliding window で「過去 → 未来」の順に評価し、 ホールドアウトは系列の末尾に置く。 標準化・欠損補完・特徴量作成も訓練区間の情報だけで行う(テスト期間の平均を使った標準化は典型的リーク)。

④ その他の頻出トラップ

🚀 発展 — 定常化からモデリング、 予測区間まで

定常化の道具箱

代表的モデル群

診断と予測区間

多変量・因果への展開:VAR / VECM(複数系列の相互依存・共和分)、 Granger 因果(「予測に役立つか」で定義される時系列の因果)。 SSDSE-B-2026 の都道府県×年度はパネルデータなので、 固定効果や動学パネルへ自然に接続する。

🎮 触って理解する — 時系列の分解(トレンド+季節性+残差)

時系列は「トレンド + 季節性 + ノイズ」の重ね合わせ(加法モデル $y_t = T_t + S_t + I_t$)として捉えるのが第一歩。 下のスライダーで 3 成分を自由に合成すると、 その合成系列だけを入力にした古典的分解(① 中心化移動平均でトレンド $\hat T_t$ を抽出 → ② 残り $y_t - \hat T_t$ を周期位置ごとに平均して季節成分 $\hat S_t$ を推定 → ③ 残差 $\hat R_t = y_t - \hat T_t - \hat S_t$)が即座に走り、 合成 ⇄ 分解の往復をリアルタイムで確認できる。 灰色の破線が「合成に使った真の成分」、 色付きの実線が「分解で推定した成分」。 両者が重なれば分解成功。

実験:
—
—

🧭 まず試すこと — 合成 ⇄ 分解の往復を体感

💡 直感 — 時系列 = 成分の重ね合わせ

出生数・婚姻件数・県内総生産のような実データは、 一見ランダムに揺れて見えても「長期的な傾向(トレンド)」「決まったリズム(季節性)」「説明できない揺らぎ(残差)」の重ね合わせで近似できることが多い。 分解の価値はそれぞれの成分に別の物語があること — トレンドは構造変化(少子化・都市集中)、 季節性は制度と暦(3 月卒業・年度末)、 残差は突発イベント(コロナの婚姻急減)を語る。 移動平均がトレンドを抽出できるのは、 窓幅を周期 m にそろえると季節成分が 1 周期分で足し合わされてゼロになるから(このシミュレーションでは m が偶数のとき端に重み 1/2 を置く中心化 2×m 移動平均を使用)。

⚠️ よくある落とし穴

🚀 発展 — STL・SARIMA・予測へ

ここで体感した古典的分解(moving average + 季節平均)は 1920 年代からある最も基本的な方法。 現代の実務では、 STL 分解(Seasonal-Trend decomposition using LOESS)が標準 — 局所回帰でトレンドを推定するため端点も計算でき、 季節成分が年々変化することも許容し、 外れ値に頑健なオプションを持つ(Python では statsmodels.tsa.seasonal.STL、 本ページ上部の実値計算セクションで使用済み)。 分解を「理解」から「予測」へ進めるなら、 季節差分と通常差分を組み込んだ SARIMA(ARIMA の季節拡張)、 トレンド・季節をそれぞれ平滑化パラメータで追跡する 指数平滑法(Holt-Winters)が二大古典。 いずれも適用前に定常性の確認が前提となる。 「分解 → 各成分を個別に予測 → 再合成」という戦略も実務では有効で、 M4/M5 予測コンペの上位解法にも組み込まれている。