日本の出生率が下がっている理由を、「若者が子供を欲しがらなくなったから」だと思っていないだろうか。
統計上、それはほとんど間違っている。
結婚した夫婦あたりの子供の数(有配偶出生率)は、実は ここ30年ほとんど変わっていない 。
出生率が下がった原因の大半は「子供が減った」ではなく 「結婚が減った」 ことで説明できる。
では、結婚はなぜ減るのか。
そしてどこで、いつ、どのくらい減るのか。
もしそれが事前にわかるなら、保育所も、学校統合も、新婚向け住宅も、ブライダル市場も、数年先の需要変化を読める。
そこで私は政府統計だけを使って、「結婚の減少を早期検知する指標」を作った。
この記事で作るもの:
- 47都道府県の婚姻危険度ランキング(偏差値方式)
- 月次の早期警戒指標(EWI)
- セクター別のリスク方向提示
- 1枚の「地域需要予報」ダッシュボード
データはすべてe-Stat(政府統計ポータル)から取得。
記事末尾に自分の県で動かすコードを載せている。
1. 結婚が減ると何が起きるか
婚姻率が下がることの影響は、3〜5年のタイムラグで波及する。
婚姻率 -18%(2019→2023)
↓ 3年後
出生数 -15〜20%
↓ すぐ
保育所の定員充足率 低下 → 新設の投資回収が破綻
↓ 6年後
小学校の入学者数 激減 → 統廃合の検討開始
↓ 同時に
新婚向け住宅需要 縮小 → 不動産の供給過剰
ブライダル市場 縮小 → 年-5%ペースで市場が消える
つまり婚姻率は、地域の需要の先行指標だ。
自治体の担当者も、地元の事業者も、知りたいのは「出生率がなぜ下がっているか」の学術的分析ではない。
知りたいのは 「うちの地域は来年どうなるか」 だ。
ここが出発点になる。
2. 何を作ったか
47都道府県×50年分のパネルデータから、3つのものを作った。
| 出力 | 何ができるか |
|---|---|
| 危険度ランキング | 47都道府県を偏差値で順位づけ。「うちは全国何位か」がわかる |
| 早期警戒指標(EWI) | 月次データから「いま悪化しているか」を検知する |
| セクター別リスク方向 | 保育・学校・住宅・ブライダル・若年層定住の5領域でリスクを提示 |
これらを1枚にまとめたものが「地域需要予報」ダッシュボードだ。
┌─────────────────────────────────────────────────┐
│ 地域需要予報 — 埼玉県 │
├──────────┬──────────┬──────────────────────────────┤
│ 【注意】 │ 婚姻率 │ 短期の勢い: -4.0% │
│ EWI:-7.3 │ 3.76‰ │ トレンドとの差: -0.7% │
│ │ 39位/47 │ コロナ前との差: -18.2% │
├──────────┴────────┬─┴──────────────────────────────┤
│ 月次婚姻件数の推移 │ 前年同月比(棒グラフ) │
├───────────────────┴────────────────────────────────┤
│ \[保育] 新設リスク↑ \[学校] 統合前倒し \[住宅] 供給過剰注意 │
├────────────────────────────────────────────────────┤
│ 47都道府県 婚姻危険度スコア ★埼玉: 39位 │
└────────────────────────────────────────────────────┘
以下、どうやって作ったかを説明する。
3. データ:e-Statから47県×50年を引く
使ったデータは2つ。
どちらもe-Stat(政府統計ポータル)から無料で取得できる。
| データ | ソース | 規模 |
|---|---|---|
| 都道府県パネル(年次) | e-Stat 社会・人口統計体系(SSDS) | 2,488行 × 136列 |
| 月次婚姻件数 | e-Stat 人口動態統計 | 5,184行(47県 × 108ヶ月) |
パネルデータの主要変数:
- 婚姻率(婚姻件数 / 総人口 × 1000)
- 合計特殊出生率(TFR)
- 初婚年齢(男女別)
- 可処分所得
- 若年人口比率(20-39歳女性 / 総人口)
- 若年性比(20-39歳 男 / 女 × 100)
- 純移動率
- 昼夜間人口比率
- ...他126変数
e-Statのテーブル番号(再現用):
SSDS主要テーブル:
A(人口基本), B(自然動態), C(社会動態),
E(世帯), H(家計), J(住宅・土地)
人口動態統計:
婚姻件数 月次 → 人口動態調査 > 月報(概数)
4. 予測モデル:婚姻率は予測できるか
まず「結婚がどこまで予測可能か」を確認した。
埼玉県の1975-2015年(40年分)でラグ付きOLS回帰を構築し、2016-2023年でバックテストした。
# モデル構造(M5: 最終選択モデル)
y(t) = 0.426 × y(t-1) # 前年の婚姻率(慣性)
- 0.210 × 初婚年齢\_女(t-1) # 1歳上がると -0.21‰
+ 0.170 × 若年性比(t-1) # 男性余りが多いと ↑
- 2.8e-6 × 可処分所得(t-1) # 所得↑ は晩婚化の裏返し
+ const
| 指標 | 値 |
|---|---|
| R²(adj) | 0.958 |
| AIC | -41.9 |
| バックテストMAE(2016-2023) | 0.170‰ |
| 同(COVID除外) | 0.110‰ |
機械学習は使っていない。
意図的にOLS回帰を選んだ理由は3つ。
- 係数がそのまま読める(「初婚年齢+1歳 = 婚姻率-0.21‰」)
- 40サンプルではNNもXGBも過学習する
- 意思決定者は「AIが判断しました」では動かない
予測結果:
埼玉県 婚姻率:
2023年(実績): 3.76‰
2030年(予測): 3.12‰(-16.8%)
→ 年間約5,400件の婚姻が消失(7年間で)
ここまでは「研究としての完成品」だ。
5. しかし予測レポートでは誰も動かない
ここで最大の学びがあった。
R²=0.958の予測モデルで「2030年に3.12‰になる」と報告したとき、返ってきた反応はこうだった。
「で、来年度の予算どうする?」
2030年の数字は遠すぎる。
自治体の予算サイクルは1年。
事業者の計画サイクルは半年〜1年。
7年後の予測値は「興味深い」で終わる。
ここで3つの転換が必要になった。
転換①:予測から警報へ
✗ 「2030年には悪化します」 → 遠い。自分ごとにならない。
○ 「直近3ヶ月で前年比-4.0%」 → 近い。「まずい」と感じる。
天気予報に例えるとわかりやすい。
「2030年に気温が2℃上がります」では誰も傘を持たない。
「明日は80%の確率で雨です」なら傘を持つ。
時間軸を変えるだけで価値が変わる。
転換②:分析からランキングへ
✗ 「埼玉県の婚姻率は3.76‰で低下傾向」 → だからどうした?
○ 「埼玉県は全国39位(偏差値39.6)」 → 「うちは大丈夫なのか?」
自治体が反応するのはランキングだ。
偏差値を出した瞬間、説明責任が発生する。
転換③:データから行動へ
✗ 「以下の変数が統計的に有意です」 → 予算に反映できない
○ 「\[保育施設] 新設リスク ↑ 投資回収再計算を」 → 具体的に動ける
データ分析が政策提言をすべきではない。
しかしリスクの方向なら提示できる。
6. 早期警戒指標(EWI)の設計
月次データから「いまどうなっているか」を検知する指標を作った。
# 3つの時間窓で「いま」を測る
ewi\_components = {
"ma3\_yoy\_mean": recent\["ma3\_yoy"].mean(), # 短期の勢い(3ヶ月MA YoY)
"deviation\_trend": recent\["deviation\_ma12"].mean(), # トレンドとの差
"vs\_2019\_mean": recent\["vs\_2019\_pct"].mean(), # コロナ前との差
}
# 統合警戒指数(負が大きいほど危険)
ewi = (ewi\_components\["ma3\_yoy\_mean"] \* 0.4
+ ewi\_components\["deviation\_trend"] \* 0.3
+ ewi\_components\["vs\_2019\_mean"] \* 0.3)
3つの成分は独立した時間窓を持つ。
| 成分 | 何を見ているか | 時間窓 | 重み |
|---|---|---|---|
| 短期の勢い | 直近の加速/減速 | 3ヶ月 | 0.4 |
| トレンドとの差 | 自分自身のトレンドからのずれ | 12ヶ月 | 0.3 |
| コロナ前との差 | 構造変化の大きさ | 2019年基準 | 0.3 |
3つが同時に悪化方向を向いたときが最も危険。
1つだけが悪化なら局所的なノイズかもしれない。
警報レベル:
EWI < -15 → 危機(急落が加速中)
EWI < -8 → 警戒(回復の兆候なし)
EWI < -3 → 注意(低下は鈍化も回復せず)
EWI ≥ -3 → 安定
埼玉県の結果:EWI = -7.3(「注意」)。
低下は鈍化しているがコロナ前比-18%が埋まらない。
7. 47都道府県 危険度ランキング
年次パネルデータから、7つの指標を重み付きz-scoreで合成して偏差値に変換した。
# 7指標の重み(合計1.0)
weights = {
"z\_level": 0.25, # 婚姻率の水準(低いほど危険)
"z\_slope5": 0.20, # 5年間の低下速度(急落ほど危険)
"z\_covid": 0.15, # COVID回復度(未回復ほど危険)
"z\_slope10": 0.10, # 10年間の低下速度
"z\_age": 0.10, # 初婚年齢(晩婚ほど危険)
"z\_yfr": 0.10, # 若年女性比率(少ないほど危険)
"z\_ysr": 0.10, # 若年性比(不利ほど危険)
}
# 偏差値化(50中心、σ=10)
danger\_score = 50 + 10 \* zscore(weighted\_sum)
偏差値にした理由は再計算可能性。
来年同じコードを走らせれば「去年から何ポイント動いたか」がわかる。
結果(上位・下位抜粋):
| 順位 | 都道府県 | 危険度 | 警報 | 婚姻率 |
|---|---|---|---|---|
| 1 | 青森 | 68.5 | 危機 | 2.81% |
| 2 | 新潟 | 67.1 | 危機 | 2.95% |
| 3 | 鹿児島 | 67.0 | 危機 | 3.30% |
| 4 | 北海道 | 64.2 | 警戒 | 3.39% |
| 5 | 沖縄 | 63.4 | 警戒 | 4.30% |
| ... | ||||
| 39 | 埼玉 | 39.6 | 安定 | 3.76% |
| ... | ||||
| 45 | 神奈川 | 35.9 | 安定 | 4.14% |
| 46 | 福井 | 35.4 | 安定 | 3.52% |
| 47 | 大阪 | 24.6 | 安定 | 4.39% |
注目すべきは沖縄(5位)。
婚姻率4.30‰は全国上位なのに危険度5位。
理由は5年間の低下速度が全国ワーストだから。
水準が高くても急落している県は危険という構造が偏差値方式で捉えられている。
8. セクター別リスク方向
ダッシュボードの最後のピースは「何をすべきか」だ。
ただしデータ分析が政策提言をすべきではない。
「保育所を増やせ」はモデルの守備範囲外だ。
そこでリスクの方向だけを、データの閾値に基づいて自動表示する方式にした。
# 例:保育施設のリスク判定
if covid\_pct < -15: # コロナ前比-15%超の低下
sector = ("保育施設", "新設リスク ↑",
f"婚姻-{abs(covid\_pct):.0f}% → 3-5年後の出生減が確実。"
f"新設の投資回収期間を再計算")
# 例:学校統合の判定
if ewi < -5: # EWIが-5未満
sector = ("小中学校", "統合検討の前倒し",
"5年先の児童数は現在比-15~20%が見込まれる")
埼玉県の出力:
\[保育施設] 新設リスク ↑
→ 婚姻-18% → 3-5年後の出生減が確実。新設の投資回収期間を再計算
\[小中学校] 統合検討の前倒し
→ 5年先の児童数は現在比-15~20%が見込まれる
\[住宅(新婚向け)] 供給過剰に注意
→ 婚姻率が年-0.003‰で低下中。新婚世帯向け供給計画の下方修正を検討
\[ブライダル] 市場縮小(年-5%ペース)
→ コロナ前比-18%。単価上昇×回数減のビジネスモデルへの転換が急務
\[若年層定住] 優先度 高
→ 初婚年齢30.1歳(全国上位)。若年女性の流入促進策が婚姻率改善の鍵
これは「提言」ではなく「翻訳」だ。
データが言っていることを、各セクターの言葉に変換しているだけ。
しかし意思決定者にとってはこれが最も使える情報になる。
9. 4回のフィードバックで変わったこと
このダッシュボードは一発で出来たわけではない。
4回のフィードバックを経ている。
| 版 | 指摘 | 変更 |
|---|---|---|
| v1 | 「予測レポートは装置じゃない」 | 予報→警報。EWI+ランキング追加 |
| v2 | 「なぜこのレベルか不明」「専門用語」 | 根拠1行追加。MA YoY→「短期の勢い」 |
| v3 | 「自分の位置がわからない」 | ★マーカー+短評追加 |
| v4 | 「何をすればいいか書いてない」 | 推奨アクション追加。名前を「地域需要予報」に |
振り返ると一貫したパターンがある。
v1: 情報が足りない →「未来が見えない」
v2: あるが伝わらない →「読めない」
v3: 伝わるが他人事 →「自分ごとにならない」
v4: 自分ごとだが動けない →「何をすればいいか」
足りない → 伝わらない → 自分ごとにならない → 動けない。
この4段の階段を登って初めて「装置」になる。
研究は1段目で止まることが多い。
10. 自分の県で試す(5分)
ここからが本題かもしれない。
自分の地域でこのスコアを計算する方法を書く。
Step 1: e-Statからデータを取る
必要なデータは以下の5つだけ。
すべてe-Stat(https://www.e-stat.go.jp/)から取れる。
| 変数 | e-Statでの場所 |
|---|---|
| 婚姻件数 | 人口動態統計 > 婚姻 > 都道府県別 |
| 総人口 | 社会・人口統計体系(SSDS)> A 人口・世帯 |
| 初婚年齢(女) | 人口動態統計 > 婚姻 > 平均初婚年齢 |
| 20-39歳 女性人口 | SSDS > A 人口・世帯 > 年齢別人口 |
| 20-39歳 男性人口 | 同上 |
APIが使えるなら:
import requests
API\_KEY = "あなたのe-Stat APIキー" # https://www.e-stat.go.jp/api/ で取得(無料)
BASE = "https://api.e-stat.go.jp/rest/3.0/app/json/getStatsData"
# 例: SSDS 人口基本(テーブル検索で statsDataId を特定)
params = {
"appId": API\_KEY,
"statsDataId": "対象テーブルID",
"cdArea": "11000", # 11000 = 埼玉県
}
r = requests.get(BASE, params=params, timeout=120)
e-Stat APIの注意点:
- APIキーは無料だが登録が必要(https://www.e-stat.go.jp/api/)
- タイムアウトは120秒以上を推奨(30秒だとタイムアウトする場合がある)
- テーブルIDは検索APIで都度確認する必要がある(年度で変わることがある)
Step 2: 危険度スコアを計算する
以下のコードに、県名を変えるだけで自分の県のスコアが出る。
"""
婚姻危険度スコア計算(最小構成)
入力: 47都道府県の年次パネルCSV
必須列: prefecture, year, marriage\_rate\_calc,
first\_marriage\_age\_f, young\_f\_ratio, young\_sex\_ratio
"""
import pandas as pd
import numpy as np
from scipy import stats as st
TARGET = "埼玉県" # ← ここを変える
df = pd.read\_csv("fertility\_panel\_wide.csv")
scores = \[]
for pref in df\["prefecture"].unique():
p = df\[df\["prefecture"] == pref].sort\_values("year")
row\_2023 = p\[p\["year"] == 2023].iloc\[0] if len(p\[p\["year"] == 2023]) else None
if row\_2023 is None:
continue
mr = row\_2023\["marriage\_rate\_calc"]
# 5年傾斜
recent = p\[p\["year"].between(2018, 2023)]\["marriage\_rate\_calc"].dropna()
slope5 = st.linregress(range(len(recent)), recent.values).slope if len(recent) >= 3 else np.nan
# COVID回復度(2019→2023)
mr19 = p\[p\["year"] == 2019]\["marriage\_rate\_calc"].values
covid = (mr - mr19\[0]) / mr19\[0] \* 100 if len(mr19) else np.nan
scores.append({
"prefecture": pref,
"mr": mr,
"slope5": slope5,
"covid": covid,
"fma": row\_2023.get("first\_marriage\_age\_f", np.nan),
"yfr": row\_2023.get("young\_f\_ratio", np.nan),
"ysr": row\_2023.get("young\_sex\_ratio", np.nan),
})
sdf = pd.DataFrame(scores)
# z-score(危険方向を正に統一)
z = lambda s: (s - s.mean()) / s.std()
sdf\["score"] = (
-z(sdf\["mr"]) \* 0.25 + # 低水準ほど危険
-z(sdf\["slope5"]) \* 0.20 + # 急落ほど危険
-z(sdf\["covid"]) \* 0.15 + # 未回復ほど危険
z(sdf\["fma"]) \* 0.10 + # 晩婚ほど危険
-z(sdf\["yfr"]) \* 0.10 + # 若年女性少ないほど危険
-z(sdf\["ysr"]) \* 0.10 # 性比不利ほど危険
)
# 偏差値化
sdf\["deviance"] = 50 + 10 \* z(sdf\["score"])
sdf = sdf.sort\_values("deviance", ascending=False).reset\_index(drop=True)
sdf\["rank"] = range(1, len(sdf) + 1)
# 結果表示
me = sdf\[sdf\["prefecture"] == TARGET].iloc\[0]
print(f"\\n{'='\*50}")
print(f" {TARGET}")
print(f" 婚姻危険度スコア: {me\['deviance']:.1f} (偏差値)")
print(f" 全国順位: {me\['rank']}位 / {len(sdf)}都道府県")
print(f" 婚姻率: {me\['mr']:.2f}‰")
print(f" COVID回復: {me\['covid']:+.1f}%")
print(f"{'='\*50}")
出力例(埼玉県):
==================================================
埼玉県
婚姻危険度スコア: 39.6 (偏差値)
全国順位: 39位 / 47都道府県
婚姻率: 3.76‰
COVID回復: -18.1%
==================================================
TARGET = "青森県" にすれば:
==================================================
青森県
婚姻危険度スコア: 68.5 (偏差値)
全国順位: 1位 / 47都道府県
婚姻率: 2.81‰
COVID回復: -23.5%
==================================================
Step 3: EWI(月次警戒指標)を計算する
月次婚姻件数データがあれば、EWIも計算できる。
"""月次EWI計算(最小構成)"""
TARGET = "埼玉県"
monthly = pd.read\_csv("vital\_marriage\_monthly.csv")
monthly\["date"] = pd.to\_datetime(monthly\["date"])
pref = monthly\[monthly\["prefecture"] == TARGET].set\_index("date").sort\_index()
# 3ヶ月移動平均のYoY
pref\["ma3"] = pref\["marriages"].rolling(3).mean()
pref\["ma3\_yoy"] = pref\["ma3"].pct\_change(12) \* 100
# 12ヶ月移動平均からの乖離
pref\["ma12"] = pref\["marriages"].rolling(12).mean()
pref\["dev"] = (pref\["marriages"] - pref\["ma12"]) / pref\["ma12"] \* 100
# 2019年比
base = pref.loc\["2019", "marriages"].mean()
pref\["vs19"] = (pref\["marriages"] - base) / base \* 100
# 直近12ヶ月でEWI計算
r = pref.dropna(subset=\["ma3\_yoy", "dev"]).tail(12)
ewi = r\["ma3\_yoy"].mean() \* 0.4 + r\["dev"].mean() \* 0.3 + r\["vs19"].mean() \* 0.3
level = "危機" if ewi < -15 else "警戒" if ewi < -8 else "注意" if ewi < -3 else "安定"
print(f"{TARGET}: EWI = {ewi:+.1f} → 【{level}】")
埼玉県: EWI = -7.3 → 【注意】
技術補足
予測モデルの詳細
モデル選択
5モデルを比較し、AIC最小のM5を採用した。
| モデル | 構造 | R²adj | AIC |
|---|---|---|---|
| M1 | 自己ラグのみ | 0.920 | -24.1 |
| M2 | 構造変数のみ | 0.943 | -35.6 |
| M3 | ラグ+全構造変数 | 0.946 | -31.6 |
| M4 | ラグ+逐次選択 | 0.955 | -39.8 |
| M5 | ラグ+有意変数のみ | 0.958 | -41.9 |
バックテスト方法
2016-2023年の各年について、その年の前年までのデータで学習し、1年先を予測する逐次検証を行った。
| 年 | 実績 | 予測 | 誤差 |
|---|---|---|---|
| 2016 | 4.23 | 4.33 | +0.10 |
| 2017 | 4.18 | 4.28 | +0.10 |
| 2018 | 4.16 | 4.15 | -0.01 |
| 2019 | 4.11 | 4.15 | +0.04 |
| 2020 | 3.98 | 4.46 | +0.48 |
| 2021 | 3.93 | 3.85 | -0.08 |
| 2022 | 3.72 | 3.77 | +0.05 |
| 2023 | 3.76 | 3.74 | -0.02 |
COVID(2020)の+0.48%を除けばMAE=0.06%。
外生ショックへの限界は明示すべきだが、構造的トレンドの追跡としては十分な精度。
危険度スコアの重み設計
7指標の重みは「何を最も重視すべきか」で決めた。
- 水準(0.25): いま低いことは最も直接的な危険信号
- 5年傾斜(0.20): 直近の悪化速度は行動の緊急性に直結
- COVID回復度(0.15): 外的ショックからの回復力は構造的頑健性の指標
- その他(各0.10): 長期トレンド・晩婚化・人口構造は背景要因
重みは感度分析で確認済み。
±0.05程度の変更では上位・下位5県の顔ぶれはほぼ変わらない。
まとめ
| やったこと | 結果 |
|---|---|
| 47県×50年のパネルデータ構築 | e-Stat SSDSから136変数 |
| 婚姻率予測モデル | R²adj=0.958、バックテストMAE=0.170‰ |
| 47県危険度ランキング | 偏差値方式。青森68.5〜大阪24.6 |
| 月次早期警戒指標(EWI) | 3成分加重。埼玉=-7.3(注意) |
| セクター別リスク方向 | 保育・学校・住宅・ブライダル・若年層定住 |
| 1枚ダッシュボード | 「地域需要予報」 |
最も重要だった学び:
データ分析の精度と、それが使われるかどうかは、まったく別の軸にある。
R²=0.958のモデルは正しかった。
しかし「2030年に3.12‰」では誰も予算を動かさない。
「あなたの県は全国39位で、来年は保育の新設リスクが上がっています」なら動く。間に必要だったのは精度の向上ではなく、翻訳だった。
データ分析をしていて「いい分析はできているのに活用されない」と感じたことがある人へ。
答えは精度の向上ではないかもしれない。
時間軸(予測→警報)、比較可能性(分析→ランキング)、翻訳(データ→行動)。
この3つを変えるだけで、同じデータが「参考資料」から「意思決定ツール」に変わる。
記事末尾のコードを自分の県で動かしてみてほしい。
あなたの地域の偏差値は、いくつだろうか。
