論文一覧に戻る 🕸 論文ネットワーク 🗺 用語ネットワーク 統計データ分析コンペ 教育用再現集
2018年度 統計データ分析コンペティション | 特別賞(高校生の部)

機械学習による
15歳未満人口の推定

⏱️ 推定読了時間: 約18分
伊藤 寛子(渋谷教育学園幕張高等学校) 高校生の部・特別賞(技術賞) 教育用標準データセット(市町村)/ランダムフォレスト回帰
🔬 ランダムフォレスト🔬 回帰🔬 機械学習🏷 人口・少子化
🔬 手法タグ / 🏷 応用タグ(クリックで同タグの論文をネットワーク検索)
🔬 再現カルテ — 原論文と同じデータ・同じ手法で再現(一部を除く)

この教材は原論文と同じデータを読み込み、同じ手順で計算し直しています。画面に出る数値と図は、あなたのブラウザがその場で計算した結果です。
⚠ ただし一部は再現していません:総面積・可住地面積は現行 SSDSE のどの版にも収録列が無いため、 その説明変数を含む部分は実再現していません。 ランダムフォレストの出力(原論文 表1・図2)は報告値の可視化で、 再計算ではありません。

原論文が使ったデータ教育用標準データセット
分析単位:市区町村
中核手法:ランダムフォレスト・線形回帰・相関分析
この教材が使うデータ
原論文(PDF)機械学習による15歳未満人口の推定
特別賞/伊藤 寛子(渋谷教育学園幕張高等学校)
✅ この教材でできること
  • 原論文の中核手法(ランダムフォレスト・相関分析)を実データで実行できる
  • 分析に使うデータは同梱済みで、ブラウザ上でそのまま読み込める
  • 数値・図を最後まで再計算できる(ランダムフォレスト・相関分析)
⚠️ この教材ではできないこと(原論文との違い)
  • 原論文は市区町村を単位に分析しているが、この教材は都道府県が単位

▶ ここに書いてある分析は、ページ下部の「🐍 ブラウザで動かす」でそのまま実行できます(インストール不要)。動かしているのは code/2018_H4_katsuyo.py(264 行)そのものです。

📝 3行で分かる要約

目次

  1. 研究のテーマと目的
  2. 使用データと再現可能性の整理
  3. 分析の流れ:抽出 → 分割 → 標準化 → 学習 → 評価
  4. 図1:5回の決定係数(報告値の可視化)
  5. 図2:実測 vs 推定の報告関係(報告値の可視化)
  6. 図3:総人口×15歳未満人口(実SSDSE-B・実再現)
  7. 図4:ランダムフォレストの実学習(実SSDSE-B・実再現)
  8. 結果の解釈と考察
  9. まとめと今後の課題
  10. データ・コードのDL
  11. ⚠️ よくある誤解
  12. 📖 用語集
  13. 📐 手法ガイド
  14. 🚀 発展の可能性
  15. 🎯 自分でやってみよう
  16. 🤔 Q&A
  17. 🐍 ブラウザで動かす

🎯 この記事を読むと何ができるようになるか

📥 データの準備(再現コードを動かす前に)

このページで実SSDSEから実再現できるのは図3・図4だけです。コードの編集は不要です。図1・図2は、原論文が使った「総面積・可住地面積」や市町村単位のデータ、そして機械学習の学習結果そのものが現行SSDSEでは再取得・再計算できないため、原論文 表1・図2 の報告値を転記して可視化します。

1
データをダウンロードする 独立行政法人統計センターの SSDSE(教育用標準データセット)配布ページから、以下をダウンロードします。
SSDSE-B-2026.csv ← SSDSE-B(都道府県・時系列データ)📥 直接DL
⬇ SSDSEダウンロードページを開く
2
ファイルを所定のフォルダに配置する ダウンロードしたCSVを、プロジェクトの data/raw/ フォルダに入れます。
2026 統計・データ解析コンペ/ ├── code/ │ └── 2018_H4_katsuyo.py ← 実行するスクリプト └── data/ └── raw/ SSDSE-B-2026.csv ← ここに置く(図3・図4で使用)
3
スクリプトをそのまま実行する ターミナルでプロジェクトルートに移動し、以下を実行します。
python3 code/2018_H4_katsuyo.py
図は html/figures/ に自動保存されます。図1・図2は原論文 表1・図2 の報告値から、図3・図4は SSDSE-B の総人口・15歳未満人口から実再現します。
研究のテーマと目的

都市への人口集中や村落の少子化が報じられる中、著者は「少子化が進む地域は村落が多い」という見方に着目した。そして、地域の村落度合いを表すデータ——人口総数・総面積・可住地面積——があれば、その市町村の15歳未満人口機械学習で推定できるのではないか、と考えた。

本研究は、全国1740市町村のデータを教師データにして、ランダムフォレスト回帰で15歳未満人口を推定する試みである。実現すれば、人口急増時の教育施設・福祉施設の需要予測や、公立学校運営・少子化対策に役立つ、というのが著者の動機だ。審査委員長講評は「機械学習で人口統計を分析し、その過程を詳細に記した技術的に優れた論文」と評価し、社会課題解決というより「技術賞」として特別賞に位置づけている。

1740市町村
学習に使ったデータ件数(報告値)
ランダムフォレスト
使用した機械学習手法
R²=0.9896
推定値と実測の決定係数(報告値)
r=0.9948
推定値と実測の相関係数(報告値)
研究の問い 市町村の人口総数・総面積・可住地面積という3つの値だけから、その市町村の15歳未満人口を機械学習でどこまで正確に推定できるか。
ひとことメモ:本文の「線形回帰」と実装の「ランダムフォレスト」 原論文は冒頭で「線形回帰を用いた機械学習」と述べているが、実際のソースコード(資料1)では RandomForestRegressor(ランダムフォレスト回帰)を使っている。本ページは実装どおりランダムフォレストとして解説する。ランダムフォレストは多数の決定木を束ねるアンサンブル学習で、線形回帰とは別物である。

高校生の部・特別賞(技術賞) 教育用標準データセット(市町村) ランダムフォレスト回帰 決定係数・相関係数で評価

使用データと再現可能性の整理

原論文は教育用標準データセット(当時の市町村版)から、人口総数・総面積(北方地域及び竹島を除く)・可住地面積・15歳未満人口の4列を抽出し、総面積順に並べた test2.csv(1740件・UTF-8)を作って学習に使った。

主なデータと出典(原論文 3-1)

役割変数出典本ページでの扱い
目的変数15歳未満人口教育用標準データセット(市町村・1740件)実SSDSE-Bに都道府県版が実在(図3・図4で実再現)
説明変数人口総数同上実SSDSE-Bに総人口が実在(図3・図4で実再現)
説明変数総面積(北方地域及び竹島を除く)・可住地面積同上現行SSDSE-A/B/C/Eに収録列なし(実再現不可)
学習結果5回のスコア・回帰直線・相関係数原論文 表1・図2(ランダムフォレストの出力)報告値の可視化(再計算ではない)
再現可能性の整理(このページの図の作り方)
  • 報告値の可視化(再計算ではない):原論文のランダムフォレストの学習結果(表1の5回スコア、図2の回帰直線 y=0.9635x+272.21、相関係数0.9948・決定係数0.9896)は、学習済みモデルの出力であり、しかも説明変数の一部(総面積・可住地面積)と市町村単位データが現行SSDSEに無いため再計算できない。したがって図1・図2は原論文 表1・図2 の報告値を転記して可視化する。
  • 実再現できる部分:原論文の中核前提「人口規模から15歳未満人口が精度よく推定できる」は、SSDSEに実在する総人口(A1101相当)と15歳未満人口(A1301相当)で検証できる。図3は都道府県×2023年の実データで実相関を、図4は原論文と同じ RandomForestRegressor を総人口だけで実際に学習して実測の精度を確かめる(実python実行)。
  • 単位が違う点に注意:原論文は市町村(1740件・3変数)、本ページ図3・図4は都道府県(総人口のみ)。対象も変数も異なるため、実再現値は原論文の報告値と一致しない。あくまで前提と手法の実再現である。
  • 新しい数値の捏造はしない:報告値(図1・図2)と実再現値(図3・図4)をラベルで分離する。GDP・県内総生産・高齢化率など SSDSE に無い列は使わない。

分析の流れ:抽出 → 分割 → 標準化 → 学習 → 評価

機械学習の流れ
データ抽出
人口・面積・
15歳未満人口
訓練/テスト分割
8:2に分ける
(random_state=70)
標準化
StandardScaler
で尺度をそろえる
学習
ランダム
フォレスト回帰
評価
決定係数を
5回平均

① 訓練データとテストデータに分ける(原論文 3-2)

全1740件を、学習に使う訓練データと、精度確認に使うテストデータに分ける。テストが少なすぎると評価が不安定になるため、著者は「テストを300件以上」という条件から分割比test_size=0.2(=20%)に設定した。分割の乱数シード random_state=70 は再現性のための任意の固定値である。

② 入力を標準化する(StandardScaler)

人口(数十万)と面積(数千km²)では桁が大きく違う。そこで StandardScaler で各変数を平均0・分散1に標準化し、尺度の違いが学習に悪影響を与えないようにする。標準化は訓練データで基準を作り、テストデータにも同じ基準を当てる。

③ ランダムフォレストで学習し、5回平均で評価する(原論文 3-3・4)

ランダムフォレスト回帰は、ランダムに選んだデータで多数の決定木を育て、その平均を予測とする手法。乱数を使うため実行のたびに結果が少し変わる。著者はこの偶然誤差を減らすため、同じ学習を5回繰り返して平均し、決定係数で精度を測った。

テストデータで測るのはなぜ? 学習に使った訓練データで精度を測ると、丸暗記(過学習)でも高得点が出てしまう。学習に使っていないテストデータで測ることで、「初めて見る市町村でも当てられるか」という本当の実力が分かる。
1
図1:5回の決定係数(報告値の可視化)

まず、原論文がランダムフォレストを5回実行して得た決定係数(表1)を見る。これは学習済みモデルの出力で、説明変数・データ単位が現行SSDSEと異なるため再計算できない。原論文 表1 の報告値を転記して可視化する(再計算ではない)。

やってみよう原論文 表1 のスコアと図2 の統計量を転記する【報告値】
  • ① このコードの目的:原論文 表1「スコア(決定係数)」5回分と、図2・4.2節の報告統計量(トレンドライン y=0.9635x+272.21、相関係数0.9948、決定係数0.9896、相対誤差の平均0.038)を、数値を作り出さずそのまま定数として転記する。以降の図1・図2はこの報告値だけを入力にする。
  • ② 前後のつながり:分析の出発点づくり。原論文の学習結果は再計算できないため、実データではなく原論文が報告した数値を唯一の入力とすることを、ここで明示する。
📝 コード
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# --- 原論文 表1「スコア(決定係数)」5回分をそのまま転記【報告値】 ---
#     ※ これは原論文がランダムフォレストで学習した結果であり、
#        本スクリプトが計算した値ではない(報告値の転記)。
scores = [0.9886389795692969, 0.9908011704351442, 0.9854055839021446,
          0.9814707632552758, 0.9905348525568049]
score_mean = 0.987370269943733           # 原論文 表1 の平均

# --- 原論文 図2・4.2節の報告統計量【報告値】 ---
trend_slope     = 0.9635                  # 図2 トレンドライン y = 0.9635x + 272.21
trend_intercept = 272.21
corr_report     = 0.9948                  # 5回平均と実際の15歳未満人口の相関係数
r2_report       = 0.9896                  # 同・決定係数
mean_rel_err    = 0.038                   # 図3 相対誤差の平均

print("原論文 表1 スコア(決定係数, 5回):")
for i, s in enumerate(scores, 1):
    print(f"  {i}回目: {s}")
print(f"  平均  : {score_mean}")
print(f"報告トレンドライン: y = {trend_slope}x + {trend_intercept}")
print(f"報告 相関係数 r = {corr_report} / 決定係数 R^2 = {r2_report}")
print(f"報告 相対誤差の平均 = {mean_rel_err}")
▼ 実行結果
=== [1] 原論文の報告値(表1・図2)を転記 ===
原論文 表1 スコア(決定係数, 5回):
  1回目: 0.9886389795692969
  2回目: 0.9908011704351442
  3回目: 0.9854055839021446
  4回目: 0.9814707632552758
  5回目: 0.9905348525568048
  平均  : 0.987370269943733
報告トレンドライン: y = 0.9635x + 272.21
報告 相関係数 r = 0.9948 / 決定係数 R^2 = 0.9896
報告 相対誤差の平均 = 0.038
  • ④ 実行結果の読み取り:① 5回のスコアはいずれも0.98〜0.99台で安定して高く、平均は0.9874。② 別に報告された「5回平均の推定値 vs 実測」の相関係数は0.9948、決定係数は0.9896。③ これらはすべて原論文がランダムフォレストで得た報告値であり、本スクリプトが計算した値ではない。
やってみよう5回のスコアを棒グラフにして安定性を見る【報告値の可視化・図1】
  • ① このコードの目的:原論文 表1 の5回の決定係数を棒グラフにし、5回平均(0.9874)を赤い破線で重ねる。元の学習結果が再計算できないため、これは再計算ではなく報告値の可視化である。
  • ② 前後のつながり:「ランダムフォレストは実行のたびに結果が変わる」と説明した部分を、実際の5回のばらつきとして目で確かめる。次の図2で見る高い相関の裏づけになる。
📝 コード
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# --- 原論文 表1 の5回スコアを棒グラフにする(報告値の可視化・再計算ではない) ---
fig1, ax1 = plt.subplots(figsize=(9, 5.5))
labels = [f'{i}回目' for i in range(1, 6)]
bars = ax1.bar(labels, scores, color='#4e9af1', edgecolor='white',
               linewidth=0.6, alpha=0.9, width=0.62)
ax1.axhline(score_mean, color='#c0392b', linewidth=1.8, linestyle='--',
            label=f'5回平均: {score_mean:.4f}')
for b, s in zip(bars, scores):
    ax1.text(b.get_x() + b.get_width() / 2, s + 0.0004, f'{s:.4f}',
             ha='center', va='bottom', fontsize=9.5)
ax1.set_ylim(0.975, 0.995)
ax1.set_ylabel('決定係数(スコア)', fontsize=12)
ax1.set_title('図1:ランダムフォレストの決定係数(原論文 表1・5回)\n'
              '【報告値の可視化(再計算ではない)】',
              fontsize=13, fontweight='bold', pad=12)
ax1.grid(axis='y', alpha=0.3, linewidth=0.8)
ax1.legend(fontsize=10, loc='lower right')
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
plt.tight_layout()
fig1.savefig(os.path.join(FIG_DIR, '2018_H4_fig1.png'), bbox_inches='tight')
plt.close(fig1)
▼ 実行結果
=== [2] 図1:表1スコアの可視化【報告値の可視化】 ===
5回スコアの範囲: 0.9815 〜 0.9908(平均 0.9874)
fig1 saved.(報告値の可視化)
  • ④ 実行結果の読み取り:① 5本の棒はどれも0.981〜0.991の狭い範囲に収まり、実行ごとのばらつきは小さい。② 平均線(0.9874)付近に各回が集まっており、5回平均を取ることで評価が安定することが分かる。③ 決定係数が0.98超ということは、テストデータの15歳未満人口のばらつきの98%以上をモデルが説明できている、という報告値である。
ランダムフォレストの5回の決定係数(報告値の可視化)
図1:ランダムフォレストの決定係数(原論文 表1・5回)。報告値の可視化(再計算ではない)。赤破線は5回平均0.9874。元の学習結果は説明変数(総面積・可住地面積)と市町村単位データが現行SSDSEに無く再計算できない。
📊 この図の読み方
棒の高さ
各回の決定係数(スコア)。1に近いほど精度が高い。
ばらつきの小ささ
5回とも0.98台に収まり、乱数による変動が小さいことを示す。
位置づけ
報告値の可視化。原論文がランダムフォレストで得た値で、再計算ではない。
2
図2:実測 vs 推定の報告関係(報告値の可視化)

原論文の核心的な結果が、「5回平均の推定値」と「実際の15歳未満人口」の関係(原論文 図2)だ。最小二乗法のトレンドラインは y=0.9635x+272.21、相関係数0.9948。個々のテスト推定値は原論文に数値が無いため、報告された直線と統計量だけを可視化する(再計算ではない)。

やってみよう報告された回帰直線と参照線 y=x を描く【報告値の可視化・図2】
  • ① このコードの目的:原論文 図2 の報告トレンドライン y=0.9635x+272.21 を描き、比較のため「推定=実測」を表す参照線 y=x を重ねる。傾きが1に近く切片が小さいほど、推定値が実測に一致していることを意味する。
  • ② 前後のつながり:図1で見た高い決定係数が、実測と推定の関係としてどう表れるかを見る部分。個々の点は復元できないので、報告された直線の形そのものから精度を読み取る。
📝 コード
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# --- 原論文 図2 の報告回帰直線 y=0.9635x+272.21 を描画(報告値の可視化) ---
#     ※ 個々のテスト推定値(散布点)は原論文に数値が無いため描かない。
#        報告された直線と統計量だけを転記して可視化する。
xr = np.linspace(0, 300000, 200)
y_trend = trend_slope * xr + trend_intercept

fig2, ax2 = plt.subplots(figsize=(8.5, 7))
ax2.plot(xr, y_trend, color='#c0392b', linewidth=2.2,
         label=f'報告トレンドライン: y = {trend_slope}x + {trend_intercept}')
ax2.plot(xr, xr, color='#888', linewidth=1.2, linestyle=':',
         label='参照線 y = x(完全一致)')
ax2.set_xlim(0, 300000)
ax2.set_ylim(0, 300000)
ax2.set_xlabel('実際の15歳未満人口(人)', fontsize=12)
ax2.set_ylabel('5回の推定値の平均(人)', fontsize=12)
ax2.set_title('図2:実際の15歳未満人口 vs 推定値の報告関係\n'
              f'【報告値の可視化】 r = {corr_report}, R² = {r2_report}',
              fontsize=13, fontweight='bold', pad=12)
ax2.text(0.04, 0.90,
         f'相関係数 r = {corr_report}\n決定係数 R² = {r2_report}\n'
         f'相対誤差の平均 = {mean_rel_err}',
         transform=ax2.transAxes, fontsize=10.5,
         bbox=dict(boxstyle='round', facecolor='#fff6e5', edgecolor='#f0a500'))
ax2.legend(fontsize=9.5, loc='lower right')
ax2.grid(alpha=0.25, linewidth=0.8)
ax2.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)
plt.tight_layout()
fig2.savefig(os.path.join(FIG_DIR, '2018_H4_fig2.png'), bbox_inches='tight')
plt.close(fig2)
▼ 実行結果
=== [3] 図2:報告トレンドラインの可視化【報告値の可視化】 ===
報告トレンドライン: y = 0.9635x + 272.21
傾きは1に近く(0.9635)、切片は+272.21人 → 推定値はほぼ実測に一致
fig2 saved.(報告値の可視化)
  • ④ 実行結果の読み取り:① 報告トレンドラインの傾きは0.9635(1にかなり近い)、切片は+272.21人と小さく、参照線 y=x にほぼ重なる。② これは推定値が実際の15歳未満人口をほぼそのまま再現していることを意味する。③ 相関係数0.9948・決定係数0.9896という報告値も、この「ほぼ y=x」という直線の近さと整合する。
実際の15歳未満人口と推定値の報告関係(報告値の可視化)
図2:実際の15歳未満人口 vs 5回平均の推定値(原論文 図2)。報告値の可視化(再計算ではない):報告トレンドライン y=0.9635x+272.21、相関係数0.9948、決定係数0.9896。個々の推定値は原論文に数値が無いため散布点は描かず、報告された直線と統計量のみを示す。
📊 この図の読み方
赤い直線
報告トレンドライン。傾き0.9635・切片272.21で、点線の y=x にほぼ重なる。
y=xに近い意味
推定値が実測とほぼ一致していること。相関0.9948・R²0.9896の裏づけ。
位置づけ
報告値の可視化。散布点は復元できないため直線と統計量のみ。
3
図3:総人口×15歳未満人口(実SSDSE-B・実再現)

ここからが実データによる再現だ。原論文の中核前提は「人口規模が分かれば15歳未満人口を精度よく推定できる」というもの。それを、SSDSEに実在する総人口15歳未満人口で確かめる。原論文の3変数のうち総面積・可住地面積は現行SSDSEに無いため、実在する総人口1変数で前提を検証する。

やってみようSSDSE-B(2023年)の総人口と15歳未満人口の実相関を出す【実再現・図3】
  • ① このコードの目的:SSDSE-B-2026 を cp932 で読み、都道府県行のみを抽出、年度==2023 に絞る。総人口と15歳未満人口の実測の相関係数と回帰直線を計算し、散布図にする。原論文の前提が現行データでも成り立つかを実データで確かめる。
  • ② 前後のつながり:図1・図2は原論文の報告値だったのに対し、この図は今のSSDSEから自分で計算した実データ。人口規模と15歳未満人口の結びつきが、市町村ではなく都道府県でも同じくらい強いのかを検証する。
📝 コード
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# --- SSDSE-B-2026 を cp932 で読み込み、都道府県行のみ・2023年に絞る ---
df_b = pd.read_csv(DATA_B, encoding='cp932', header=1)
df_b = df_b[df_b['地域コード'].astype(str).str.match(r'^R\d{5}', na=False)].copy()
df_b['年度'] = df_b['年度'].astype(int)

df23 = df_b[df_b['年度'] == 2023].dropna(subset=['総人口', '15歳未満人口']).copy()
xp = df23['総人口'].astype(float).values / 10000        # 万人
yp = df23['15歳未満人口'].astype(float).values / 10000  # 万人

# 実データの相関と回帰直線(実python実行=実再現値)
r_real, p_real = stats.pearsonr(xp, yp)
slope_real, intercept_real = np.polyfit(xp, yp, 1)

fig3, ax3 = plt.subplots(figsize=(9, 7))
ax3.scatter(xp, yp, s=60, color='#5cb85c', alpha=0.8,
            edgecolors='white', linewidths=0.7, zorder=3)
xr3 = np.linspace(xp.min(), xp.max(), 100)
ax3.plot(xr3, slope_real * xr3 + intercept_real, 'k-', linewidth=1.8, alpha=0.75,
         label=f'回帰直線 y = {slope_real:.3f}x + {intercept_real:.2f}')
# 突出する県にラベル
for name, xv, yv in zip(df23['都道府県'], xp, yp):
    if xv > 500 or name in ('沖縄県', '鳥取県'):
        ax3.annotate(name.replace('県', '').replace('都', '').replace('府', ''),
                     (xv, yv), xytext=(4, 3), textcoords='offset points',
                     fontsize=8, color='#333')
ax3.set_xlabel('総人口(万人・SSDSE-B 2023)', fontsize=12)
ax3.set_ylabel('15歳未満人口(万人・SSDSE-B 2023)', fontsize=12)
ax3.set_title('図3:総人口 vs 15歳未満人口(47都道府県・2023年)\n'
              f'【実SSDSE-B・実再現】 実測 r = {r_real:.4f}, R² = {r_real**2:.4f}',
              fontsize=13, fontweight='bold', pad=12)
ax3.legend(fontsize=10, loc='upper left')
ax3.grid(alpha=0.25, linewidth=0.8)
ax3.spines['top'].set_visible(False)
ax3.spines['right'].set_visible(False)
plt.tight_layout()
fig3.savefig(os.path.join(FIG_DIR, '2018_H4_fig3.png'), bbox_inches='tight')
plt.close(fig3)
▼ 実行結果
=== [4] 図3:SSDSE実データで総人口×15歳未満人口【実再現】 ===
分析対象: 47 都道府県(2023年)
総人口 × 15歳未満人口 の実測相関 r = 0.9967, R² = 0.9934, p = 1.16e-50
回帰直線: 15歳未満人口 ≒ 0.1112 × 総人口 + 0.74(万人)
fig3 saved.(実再現)
  • ④ 実行結果の読み取り:① 47都道府県の総人口と15歳未満人口の実測相関はr=0.9967(決定係数0.9934)で、ほぼ完全な直線関係。② 回帰直線は「15歳未満人口 ≒ 総人口の約11%」を示し、人口が多い県ほど15歳未満人口も比例して多い。③ 原論文が3変数で得た高精度は、実は総人口という1変数の寄与が支配的だと実データからも読み取れる(審査講評が「3変数で予測する意味を示すとよい」と述べた点にも通じる)。
総人口と15歳未満人口の散布図(実SSDSE-B・2023)
図3:総人口 vs 15歳未満人口(47都道府県・2023年)。実SSDSE-B-2026からの実再現:実測相関 r=0.9967、決定係数 R²=0.9934。原論文は市町村・3変数、本図は都道府県・総人口のみのため数値は原論文と一致しないが、人口規模から15歳未満人口が精度よく決まるという前提を実データで裏づける。
📊 この図の読み方
点の並び
ほぼ一直線。総人口が決まれば15歳未満人口がほぼ決まる(r=0.9967)。
右上と左下
右上に東京・神奈川など大都市、左下に鳥取・島根など小規模県。
位置づけ
実再現(実SSDSE-B)。原論文とは単位・変数が異なる別計算だが前提は一致。
4
図4:ランダムフォレストの実学習(実SSDSE-B・実再現)

最後に、原論文と同じ RandomForestRegressor を実際に動かす。SSDSEに実在する総人口だけを使い、原論文と同じ test_size=0.2, random_state=70・標準化で学習し、テストデータでの実測精度を確かめる。データは都道府県×全年(2012–2023)で件数を確保する。

やってみよう総人口のみでランダムフォレストを学習し、テスト精度を測る【実再現・図4】
  • ① このコードの目的:原論文と同じ RandomForestRegressor を、SSDSEの総人口→15歳未満人口で実際に学習する。都道府県×2012–2023年の全データを訓練:テスト=8:2に分け(random_state=70)、StandardScalerで標準化してからテストデータの決定係数と相関を測る。原論文の手法を、実在する変数だけで動かして再現する。
  • ② 前後のつながり:図3で「総人口と15歳未満人口は強く連動する」と確かめた。この図では、その関係を使ってランダムフォレストが未知データの15歳未満人口をどれだけ当てられるかを、実際に学習して確かめる締めくくり。
📝 コード
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# --- 原論文と同じ RandomForestRegressor を、SSDSEの総人口→15歳未満人口で実学習 ---
#     全都道府県×全年(2012-2023)を使い、原論文と同じ test_size=0.2, random_state=70。
#     説明変数は SSDSE に実在する「総人口」のみ(総面積・可住地面積は現行SSDSEに無い)。
df_ml = df_b.dropna(subset=['総人口', '15歳未満人口']).copy()
X = df_ml[['総人口']].astype(float).values
y = df_ml['15歳未満人口'].astype(float).values

X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=70)
scaler = StandardScaler().fit(X_tr)                 # 原論文どおり標準化
model = RandomForestRegressor(random_state=70).fit(scaler.transform(X_tr), y_tr)

pred = model.predict(scaler.transform(X_te))
r2_rf = model.score(scaler.transform(X_te), y_te)   # 実測の決定係数
r_rf, _ = stats.pearsonr(y_te, pred)                # 実測の相関係数

fig4, ax4 = plt.subplots(figsize=(8.5, 7))
ax4.scatter(y_te / 10000, pred / 10000, s=45, color='#9b59b6', alpha=0.7,
            edgecolors='white', linewidths=0.6, zorder=3)
lim = max(y_te.max(), pred.max()) / 10000 * 1.05
ax4.plot([0, lim], [0, lim], color='#888', linestyle=':', linewidth=1.3,
         label='y = x(完全一致)')
ax4.set_xlim(0, lim); ax4.set_ylim(0, lim)
ax4.set_xlabel('実際の15歳未満人口(万人)', fontsize=12)
ax4.set_ylabel('ランダムフォレストの推定値(万人)', fontsize=12)
ax4.set_title('図4:ランダムフォレストによる推定(総人口のみ・都道府県×年)\n'
              f'【実SSDSE-B・実学習・実再現】 実測 R² = {r2_rf:.4f}, r = {r_rf:.4f}',
              fontsize=12.5, fontweight='bold', pad=12)
ax4.legend(fontsize=10, loc='upper left')
ax4.grid(alpha=0.25, linewidth=0.8)
ax4.spines['top'].set_visible(False)
ax4.spines['right'].set_visible(False)
plt.tight_layout()
fig4.savefig(os.path.join(FIG_DIR, '2018_H4_fig4.png'), bbox_inches='tight')
plt.close(fig4)
▼ 実行結果
=== [5] 図4:ランダムフォレストを実際に学習【実再現】 ===
学習データ全体: 564 件(47都道府県 × 2012-2023年)
訓練 451 件 / テスト 113 件(test_size=0.2, random_state=70)
実再現の決定係数 R² = 0.9950, 相関係数 r = 0.9975
fig4 saved.(実再現)
  • ④ 実行結果の読み取り:① 総人口1変数だけでも、テストデータの決定係数はR²=0.9950、相関はr=0.9975と非常に高い。② 散布点はほぼ y=x 上に並び、推定値が実測をよく再現している。③ 原論文の5回平均スコア0.9874・相関0.9948と近い水準が総人口1変数の実学習でも達成できる——つまり、この推定タスクの精度は主に総人口が担っており、総面積・可住地面積の追加寄与は限定的だと実データから示唆される。
ランダムフォレストによる15歳未満人口の推定(実SSDSE-B・実学習)
図4:ランダムフォレストによる推定(総人口のみ・都道府県×2012–2023年)。実SSDSE-B-2026を用いた実学習・実再現:テストデータ実測 R²=0.9950、r=0.9975(test_size=0.2, random_state=70)。原論文は市町村・3変数のため報告値(R²=0.9896)とは一致しないが、手法を実データで動かした再現である。
📊 この図の読み方
点と y=x
推定値(縦)と実測(横)がほぼ y=x 上に並ぶ=よく当たっている。
1変数でも高精度
総人口だけで R²=0.9950。総人口の寄与が支配的であることを示す。
位置づけ
実再現(実SSDSE-B・実学習)。原論文とは単位・変数が異なるため報告値とは別物。

結果の解釈と考察

著者は結果(原論文4章・5章)を次のように読み解いた。

① 全体としては高精度(原論文 5-1)

5回平均の相関係数・決定係数はいずれも0.9を大きく超え、1回ごとの決定係数も0.98超で安定していた。著者は「概ね推定精度は良好で、かなり高い」と結論した。人口総数・総面積・可住地面積という入手しやすい3変数だけで、15歳未満人口をほぼ言い当てられたことになる。

② 15歳未満人口が少ない市町村では精度が急落(原論文 5-2)

一方、15歳未満人口が概ね100人未満の市町村では、相対誤差が1.0を超える地域も現れた。テストデータのうち1〜100人未満の8市町村の相対誤差平均は0.5769と、全体の傾向より大幅に悪い。著者はこれを「人口が少ない地域の学習データ不足」が原因と考察した。

③ 結論と展望(原論文 5-3・5-4)

そこで著者は「15歳未満人口が概ね100人以上の地域では本手法は有効だが、100人未満では精度が著しく低下するため利用に注意が必要」と結論。今後は、ランダムフォレストを多層にしたディープ・フォレストの活用や、誰でも機械学習分析を行えるソフトウェア開発を展望として挙げた。

より正確な分析のために(補足) 審査講評も指摘するとおり、3変数で15歳未満人口を予測することの意義は明確でない。本ページ図3・図4が示すように、精度の大半は「総人口」1変数で説明できる(総人口だけの実学習でも R²=0.9950)。総人口が多い地域は15歳未満人口も多いのは半ば自明で、総面積・可住地面積の追加的な貢献は限定的とみられる。また、この推定は因果を述べるものではなく、あくまで人口規模からの内挿的な当てはめである。決定係数が高いこと自体は「新しい発見」ではなく、むしろ説明変数と目的変数が強く連動していることの反映として読むのが正確だ。

まとめと今後の課題

本研究は、市町村の人口総数・総面積・可住地面積から15歳未満人口を機械学習で推定できるかという問いに、ランダムフォレスト回帰で取り組んだ。全1740市町村を訓練:テスト=8:2に分け、標準化して5回学習した結果、5回平均の決定係数0.9874、推定値と実測の相関0.9948・決定係数0.9896という高精度を報告した。ただし15歳未満人口が概ね100人未満の市町村では精度が急落し、学習データ不足という課題も明らかにした。著者はディープ・フォレストの活用や誰でも使える分析ソフトの開発を今後の展望とした。本ページでは、学習結果(表1・図2)は報告値として可視化し、SSDSEに実在する総人口・15歳未満人口で実際にランダムフォレストを学習し直して切り分けた。

この研究の限界 ①審査講評どおり、3変数で15歳未満人口を予測する社会的意義・目的が明確でない(技術賞という位置づけ)。②精度の大半は総人口1変数で説明でき、総面積・可住地面積の寄与は限定的(本ページ図4)。③高い決定係数は「発見」ではなく説明変数と目的変数の強い連動の反映。④人口が少ない市町村では精度が著しく低い。⑤本文は「線形回帰」と述べるが実装はランダムフォレストで、用語の不一致がある。
この研究から学べること 高校1年生が、データ抽出→訓練/テスト分割→標準化→学習→評価という機械学習の一連の流れを自力で実装し、乱数による変動を5回平均で抑え、決定係数・相対誤差で多面的に精度を検証した点。手法の適用範囲(100人以上でのみ有効)まで踏み込んだ誠実さ。その過程を詳細に記録した技術的な完成度が評価され、高校生の部・特別賞(技術賞)に選ばれた。

データ・コードのダウンロード

このページの図は、以下から再現できます。

🐍 再現コード(.py) 📊 SSDSE-B-2026.csv

※ 図3(総人口×15歳未満人口)・図4(ランダムフォレスト実学習)はSSDSE-B-2026から算出した実再現です。図1(5回スコア)・図2(実測 vs 推定の回帰直線)は、原論文の説明変数(総面積・可住地面積)と市町村単位データが現行SSDSEに無く、学習結果そのものは再計算できないため、原論文 表1・図2 の報告値を転記して可視化したものです。実再現(都道府県・総人口のみ)は原論文(市町村・3変数)と単位・変数が異なるため、報告値とは一致しません(新たな数値の捏造はしていません)。

⚠️ よくある誤解と注意点

この研究を読むとき・まねするときに陥りやすい誤解を整理する。

誤解1:「決定係数0.99なのだから、この手法は素晴らしい発見だ」
高い決定係数は説明変数と目的変数が強く連動していることの反映で、それ自体は新発見ではない。総人口が多い地域は15歳未満人口も多いのは半ば自明。本ページ図4のとおり総人口1変数だけでも R²=0.9950で、3変数を使う追加的意義は大きくない。
誤解2:「このページの図はすべて原論文を計算し直したもの」
図1・図2は原論文 表1・図2 の報告値の可視化で、再計算ではない。原論文の説明変数(総面積・可住地面積)と市町村単位データが現行SSDSEに無いため。実SSDSEから学習し直したのは図3・図4(総人口・都道府県)だけで、これらは原論文とは単位・変数が異なる別計算。図注に区別を明記している。
誤解3:「ランダムフォレストは1回動かせば結果が決まる」
ランダムフォレストは乱数でデータや特徴を選ぶため、実行のたびに結果が少し変わる。原論文が5回実行して平均したのはこのため。乱数シード(random_state)を固定すれば同じ結果を再現できる。
誤解4:「どの市町村でも同じ精度で当てられる」
原論文自身が示すとおり、15歳未満人口が100人未満の市町村では相対誤差が大きく精度が急落する(8市町村の相対誤差平均0.5769)。学習データが少ない小規模地域では推定値の利用に注意が必要、と著者も結論している。

📖 用語集(この記事に出てくる統計・機械学習用語)

クリックすると各用語の詳しい解説ページに移動できます。

機械学習(教師あり学習)
入力と正解のペアからパターンを学び、未知の入力に対する出力を予測する手法。本研究は3変数から15歳未満人口を予測する回帰問題。
ランダムフォレスト
ランダムに選んだデータで多数の決定木を育て、その平均で予測するアンサンブル学習。原論文も本ページ図4も RandomForestRegressor を使う。
決定木
条件分岐で予測するモデル。ランダムフォレストはこれを多数束ねたもの。
決定係数(R²)
目的変数のばらつきをモデルがどれだけ説明できたかを0〜1で表す指標。本研究の報告値は0.9896、実再現は0.9950。
相関係数
2つの量が一緒に動く強さを−1〜+1で表す。本研究では推定値と実測の相関0.9948(報告値)、総人口×15歳未満人口の実測0.9967。
訓練データ・テストデータ
学習に使うデータと精度確認に使うデータ。本研究は8:2で分割(test_size=0.2)。未知データでの実力を測るために分ける。
標準化(StandardScaler)
各変数を平均0・分散1に変換し、桁の違いをそろえる前処理。人口と面積のように尺度が違う変数を扱うときに使う。
過学習
訓練データに合わせすぎて未知データで当たらなくなる状態。テストデータで評価することで見抜く。
再現可能性
他者が同じデータ・手順で同じ結果を得られること。本ページは報告値の可視化と実データの実再現を分けて表示している。
SSDSE
統計センターが提供する教育用標準データセット。本ページ図3・図4はSSDSE-B(都道府県・時系列)の総人口・15歳未満人口を用いた。原論文当時の市町村版の総面積・可住地面積は現行版に収録が無い。

📐 使っている手法をわかりやすく解説

この研究の中心であるランダムフォレスト回帰と、その前提となる分割・標準化・評価指標を、注意点まで順に説明する。

全体像
データを訓練用とテスト用に分割標準化で尺度をそろえ → ランダムフォレストで学習 → 決定係数・相対誤差で精度評価 → 乱数変動を5回平均で安定化。因果ではなく「値を当てる(予測)」ための教師あり回帰である。
🌲 ランダムフォレスト回帰
何をする
ランダムに選んだデータで多数の決定木を育て、その予測の平均を出力する。1本の木より安定し、複雑な関係も捉えやすい。
本研究での使い方
人口総数・総面積・可住地面積から15歳未満人口を予測。乱数を使うため実行ごとに結果が変わり、5回平均で評価した。
注意
予測は得意だが係数のように「どの変数がどれだけ効くか」が読みにくい。乱数シードを固定しないと再現できない。外挿(学習範囲外)には弱い。
✂️ 訓練/テスト分割過学習
何をする
データを学習用と評価用に分け、学習に使っていないデータで精度を測る。過学習(丸暗記)を見抜くための基本作法。
本研究での使い方
「テスト300件以上」から test_size=0.2(8:2)を選び、random_state=70 で分割を固定した。
注意
テストが少なすぎると評価がぶれる。分割の乱数によっても結果が変わるため、シードの固定や複数回の評価で安定させる。
📏 標準化(StandardScaler)
何をする
各変数を平均0・分散1に変換し、桁の違い(人口=数十万 vs 面積=数千)が学習を歪めないようにする。
本研究での使い方
訓練データで基準(平均・標準偏差)を作り、同じ基準をテストデータにも適用した。
注意
基準は必ず訓練データだけで作る。テストの情報を混ぜると精度を過大評価してしまう(情報漏洩)。
📊 決定係数・相対誤差による評価
何をする
決定係数(R²)は全体の当てはまりを、相対誤差は1件ごとの外れ具合を測る。両方見ることで精度を多面的に評価する。
本研究での使い方
R²で全体精度(0.9896・報告値)を、相対誤差で小規模市町村の弱点(100人未満で急落)を見つけた。
注意
R²が高くても特定の層で大きく外すことがある。全体指標だけで満足せず、誤差の分布まで確認する。

🚀 発展の可能性(結果 X → 新仮説 Y → 課題 Z)

この研究の「人口・面積から15歳未満人口を高精度に推定できる」という結果は、次の研究の出発点になる。

発展1:どの変数が本当に効いているかを分解する
結果X
3変数で決定係数0.9896(報告値)。ただし総人口1変数だけでも実再現でR²=0.9950。
新仮説Y
総面積・可住地面積は、総人口を除いても15歳未満人口の推定を改善するのか。
課題Z
変数重要度や、総人口を除いた場合の精度低下を比較し、各変数の純粋な貢献を切り分ける。
発展2:小規模市町村の精度を上げる
結果X
15歳未満人口100人未満の市町村で相対誤差が大きい(8市町村平均0.5769)。
新仮説Y
小規模地域を重点的にサンプリングしたり、ディープ・フォレストを使えば、少人数域の精度は改善するのか。
課題Z
層化サンプリングや対数変換、別モデルとの比較で、小規模域に強い推定法を探る。

🎯 自分でやってみよう(5つのチャレンジ)

再現コードを少し変えるだけで試せる課題を、易しい順に用意した。

★☆☆☆☆ 難易度1
別の年で実相関を出す
図3は 年度==2023。ここを 20152020 に変えて、総人口×15歳未満人口の相関が年によってどう変わるか(ほとんど変わらないはず)を確かめよう。
★★☆☆☆ 難易度2
乱数シードを変えて図4を動かす
図4の random_state=700123 に変えて、テストの決定係数がどれくらい動くか(乱数による変動)を体感しよう。
★★★☆☆ 難易度3
説明変数を1つ増やす
図4の X = df_ml[['総人口']]'65歳以上人口' を加えて2変数にし、決定係数が上がるか下がるかを確かめよう(総人口だけでほぼ十分なはず)。
★★★★☆ 難易度4
線形回帰と精度を比べる
原論文は本文で「線形回帰」と書いていた。sklearn.linear_model.LinearRegression でも学習し、ランダムフォレストと決定係数を比較してみよう(総人口が支配的なので大差ないはず)。
★★★★★ 難易度5
なぜ原論文の3変数を実再現できないのか説明する
原論文の総面積・可住地面積が現行SSDSE-B/A/C/Eで実再現できない理由を、収録列の有無市町村 vs 都道府県という単位の違いの両面から、自分の言葉で説明してみよう。

💼 この手法は実社会でこう使われている

「複数の指標から目的の値を機械学習で推定する」発想は、行政・不動産・防災の現場で広く使われている。

🏫
教育・福祉施設の需要予測
人口や地域特性から将来の児童数を推定し、学校・保育所の配置や統廃合の計画に役立てる。本研究と同じ発想。
🏠
不動産価格の推定
面積・立地・築年数など多数の特徴からランダムフォレストで価格を推定する。特徴量から値を当てる典型例。
🌊
人口・需要の空間補完
面積や人口密度などの入手しやすい指標から、細かい地域の人口や需要を推定し、防災計画やインフラ整備に使う。

🤔 よくある質問(読者からの想定Q&A)

この研究を読んで浮かびやすい疑問に答える。

Q. なぜ人口総数・総面積・可住地面積の3つを選んだの?
A. 著者は「少子化が進む地域は村落が多い」と考え、地域の村落度合いを測れる指標としてこの3つを選びました。人口密度や可住地の広さで都市/村落の性格を表そうとした、という発想です。
Q. 決定係数0.99はすごい精度では?
A. 高い値ですが、総人口が多い地域は15歳未満人口も多いという半ば当たり前の関係が主因です。本ページ図4のとおり総人口1変数だけでも R²=0.9950 になり、3変数を使う追加的な意義は大きくありません。高い決定係数=新発見ではない点に注意です。
Q. このページの図は原論文と同じ数値ですか?
A. 図1・図2は原論文 表1・図2 の報告値の可視化です。原論文の説明変数(総面積・可住地面積)と市町村単位データが現行SSDSEに無く、学習結果は再計算できません。実SSDSEから学習し直した図3・図4は都道府県・総人口のみで、原論文(市町村・3変数)とは単位・変数が異なるため数値は一致しません。新たな数値の捏造はしていません。
Q. 本文には「線形回帰」と書いてあるけど?
A. 原論文は冒頭で「線形回帰」と述べていますが、実際のソースコード(資料1)は RandomForestRegressor(ランダムフォレスト回帰)です。両者は別の手法なので、本ページは実装どおりランダムフォレストとして解説しています。

✅ 理解度チェック(4問)

この論文を理解できたか、クリックで確認しましょう。間違えても解説が出ます。

🐍 ブラウザで動かす — インストール不要でこの論文の分析を再現する

このページの分析は、この画面の中でそのまま実行できます。 Python をインストールする必要も、CSV をダウンロードする必要もありません。 下のセルの 「▶ ブラウザで実行」 を上から順に押すか、 「▶ 最初から全部実行」 で一気に流してください。 表示されるのは、本文の図表とまったく同じ計算の結果です (動かしているのは再現スクリプト code/2018_H4_katsuyo.py そのもの)。

コードは書き換えられます。「✏️ 書き換える」で数字や変数を変えて ▶ を押すと、 結果がどう変わるかをその場で確かめられます(元に戻すボタンつき)。 ページを開いた時点で裏で実行環境の準備が始まっているので、待ち時間はほとんどありません。 初回だけ実行環境の取得にインターネット接続が必要です。