論文一覧に戻る 🕸 論文ネットワーク 🗺 用語ネットワーク 統計データ分析コンペ 教育用再現集
🎉
★ 総務大臣賞(最優秀賞) 2021年度
大学生・一般の部

若者の大都市から地方への移動要因を探る
―修正重力モデルによる分析―

⏱️ 推定読了時間: 約35分
2021年度 統計データ分析コンペティション | 総務大臣賞(大学生・一般の部)| 坂本 大樹(東京大学大学院情報理工学系研究科)・川本 晃大(早稲田大学大学院基幹理工学研究科)
📊 住民基本台帳人口移動報告・SSDSE-A/D ほか 📍 43大都市 → 872地方(3,752 移動ペア) 📋 修正重力モデル × Elastic Net 回帰
🔬 Elastic Net🔬 交差検証🔬 対数線形回帰🔬 重力モデル🏷 移住・人口移動🏷 文化・余暇🏷 人口・少子化
🔬 手法タグ / 🏷 応用タグ(クリックで同タグの論文をネットワーク検索)
🔬 再現カルテ — 原論文と同じデータ・同じ手法で再現

この教材は原論文と同じデータを読み込み、同じ手順で計算し直しています。画面に出る数値と図は、あなたのブラウザがその場で計算した結果です。

原論文が使ったデータ住民基本台帳人口移動報告
分析単位:市区町村
中核手法:修正重力モデル・Elastic Net 回帰
この教材が使うデータ
原論文(PDF)若者の大都市から地方への移動要因を探る ―修正重力モデルによる分析―
総務大臣賞/坂本 大樹(東京大学大学院情報理工学系研究科) 川本 晃大(早稲田大学大学院基幹理工学研究科)
✅ この教材でできること
  • 分析に使うデータは同梱済みで、ブラウザ上でそのまま読み込める
  • 数値・図を最後まで再計算できる(相関分析)
突合監査の結果、主要データと中核手法はいずれも原論文と一致しています。

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

🏅 論文審査会コメント(審査員はここを評価した)
「重力モデルを重要な政策課題に適用した本格的論文であり、テーマも狙いも良い。若者の移動要因を機械学習の手法により明らかにする分析を行っていて、今後の発展が期待される研究である。」
出典:統計センター「統計データ分析コンペティション」受賞論文PDF掲載の審査講評。プロの審査員が何を評価し、何を注文したかは論文の読み方の最良の手本になる。
📝 3行で分かる要約

目次

  1. 研究のテーマと目的
  2. データと変数(表1)
  3. 再現コード:説明変数を SSDSE-A から作る(実再現)
  4. 図1:大都市と地方の説明変数の分布(実再現)
  5. 図2:説明変数間の相関行列(実再現)
  6. 修正重力モデルと Elastic Net
  7. 図3:回帰係数(表2)の可視化(報告値)
  8. 図4:移動元と移動先の係数対比(報告値)
  9. 主要な発見(Cadwalladerの5要因で読む)
  10. まとめと課題
  11. データ・コードのDL
  12. ⚠️ よくある誤解
  13. 📖 用語集
  14. 📐 手法ガイド
  15. 🚀 発展の可能性
  16. 🎯 自分でやってみよう
  17. 🤔 Q&A
  18. 🐍 ブラウザで動かす

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

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

このページの説明変数の作成と大都市/地方の比較・相関行列(図1・図2)は、以下の手順で自分で再現できます。コードの編集は不要です。(修正重力モデルの回帰係数=表2・図3・図4は、住民基本台帳の移動フローと市区町村間の距離が必要で、これらは SSDSE に未収録のため、原論文の報告値を可視化します。)

1
データをダウンロードする 独立行政法人統計センターの SSDSE(教育用標準データセット)配布ページから、以下をダウンロードします。
SSDSE-A-2025.csv ← SSDSE-A(市区町村データ)📥 直接DL
⬇ SSDSEダウンロードページを開く
2
ファイルを所定のフォルダに配置する ダウンロードしたCSVを、プロジェクトの data/raw/ フォルダに入れます。
2026 統計・データ解析コンペ/ ├── code/ │ └── 2021_U1_daijin.py ← 実行するスクリプト └── data/ └── raw/ SSDSE-A-2025.csv ← ここに置く
3
スクリプトをそのまま実行する ターミナルでプロジェクトルートに移動し、以下を実行します。
python3 code/2021_U1_daijin.py
図は html/figures/ に自動保存されます。
研究のテーマと目的

日本は2008年をピークに人口減少に転じ、その影響は地方でとりわけ深刻だ。原因の一つが東京への一極集中で、進学・就職に加え「魅力・利便性・自由度」が若者を大都市に引き寄せている。政府は「まち・ひと・しごと創生」で地方への新しい人の流れを作ることを目標に掲げるが、三大都市圏の人口は増加・横ばいが続く。

地方創生の一手は「大都市から地方への人の流れ」を作ることだ。ではその流れを促す要因は何か。 本研究は、移動人口の約7割を占める20〜40代の若者にしぼり、地域間の人口移動を記述する修正重力モデルで、大都市から地方への移動を促す要因を定量的に探る。

−0.569
移動間距離の回帰係数(報告値・絶対値最大)
+0.107
移動先の学校数の係数(報告値)
+0.042
移動先の福祉施設数の係数(報告値)
3,752
分析対象の人口移動ペア数(報告値)
研究の問い 市区町村間で、20〜40代の若者が「大都市(移動元)から地方(移動先)」へ移動するのを促す要因は何か。総人口・距離といった基本要因に加え、就業構造・所得・教育・生活の質・行政サービスは、若者の移動量とどう関係するか。
分析のキモ:重力モデルで「移動フロー」を説明する 重力モデルは、2地域間の人口移動量を「両地域の人口の積 ÷ 距離」で説明する(万有引力のアナロジー)。原論文はこれに就業・所得・教育などの修正項を加えた修正重力モデルを使い、両辺を対数化して線形回帰にした。だから係数は「その変数が1%増えると移動量が何%変わるか」という弾力性として読める。

大学生・一般の部 住民基本台帳人口移動報告 SSDSE-A / SSDSE-D 修正重力モデル(対数線形回帰) Elastic Net 回帰

データと変数(表1)

表1 使用したおもなデータと変数

役割変数出典(原論文)
被説明変数20〜40代の大都市→地方 移動人口量(10人未満の移動は除外)住民基本台帳人口移動報告(e-Stat, 平成27年)
基本要因総人口(移動元x・移動先y)、移動間距離総人口=SSDSE-A / 距離=緯度経度+ヒュベニの公式(アマノ技研)
所得納税義務者1人あたり課税対象所得(x・y)総務省「市町村税課税状況等の調」
雇用機会第1・2・3次産業就業者率、完全失業率(x・y)SSDSE-Aから筆者算出
教育学校数(10万人あたり)、子供を対象とした活動学校数=SSDSE-A算出 / 活動=SSDSE-D(都道府県別)
生活の質安全な生活のための活動、スポーツ・文化・芸術・学術の活動SSDSE-D(都道府県別)
行政サービス福祉施設数(10万人あたり)SSDSE-A から筆者算出
再現可能性の整理(このページの図の作り方)
  • 実再現できる部分:原論文が SSDSE-A から筆者算出した「説明変数の作り方」——産業別就業者率・完全失業率・人口10万人あたり学校数/福祉施設数——は、収録データ SSDSE-A-2025 でそのまま再計算できる(本ページの図1・図2)。ただし収録版は2020年国勢調査ベースで、原論文の平成27年(2015年)とは年次が違うため、値は完全一致しない(図中に明記)。
  • 報告値の可視化(再計算ではない):修正重力モデルの回帰係数(表2)は、住民基本台帳「人口移動報告」の移動フロー、市区町村間の距離(緯度経度+ヒュベニの公式)、課税対象所得、SSDSE-D の都道府県別活動データを結合して初めて推定できる。移動フロー・距離は SSDSE に未収録のため、係数は原論文の報告値を転記して可視化する(本ページの図3・図4)。新たな数値の再計算ではない。
分析の流れ
重力モデルに
修正項を追加
両辺を
対数化
変数を正規化
Elastic Net
変数選択・推定
1
再現コード:説明変数を SSDSE-A から作る(実再現)

まず、原論文が SSDSE-A から筆者算出したのと同じ手順で説明変数を作る。就業者数から産業別就業者率と完全失業率を、学校・福祉施設の数と総人口から「人口10万人あたりの数」を計算する。これは移動フローを使わないので実データで再現できる

やってみようSSDSE-A を読み込み、原論文と同じ説明変数を作る【実再現】
  • ① このコードの目的:SSDSE-A-2025 を cp932・header=2(0行目=コード, 1行目=年度, 2行目=変数名)で読み込み、市区町村行だけ残す。原論文3.3節と同じ方法で産業別就業者率・完全失業率・人口10万人あたり学校数/福祉施設数を算出し、東京23区+政令市20市を「大都市(移動元)」、人口20万人未満を「地方(移動先)」に区分する。
  • ② 前後のつながり:ここで作った説明変数を土台に、以降で大都市と地方の分布(図1)と変数間の相関(図2)を再現していく。回帰係数(表2)は移動フローが必要なので後半で報告値として扱う。
📝 コード
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
print('=== SSDSE-A 読み込みと説明変数の算出【実再現】 ===')
raw = pd.read_csv(DATA_A, encoding='cp932', header=2)
raw = raw.rename(columns={raw.columns[0]: '地域コード',
                          raw.columns[1]: '都道府県',
                          raw.columns[2]: '市区町村'})
df = raw[raw['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()

num_cols = ['総人口', '就業者数', '第1次産業就業者数', '第2次産業就業者数',
            '第3次産業就業者数', '完全失業者数', '幼稚園数', '小学校数',
            '中学校数', '高等学校数', '公民館数', '図書館数', '一般病院数',
            '保育所等数(基本票)']
for c in num_cols:
    df[c] = pd.to_numeric(df[c], errors='coerce')
# 総人口0・就業者0の市町村(2020年国勢調査で人口0の避難区域等)は率が定義できないため除外
df = df[(df['総人口'] > 0) & (df['就業者数'] > 0)].copy()

# 原論文と同じ変数の作り方(3.3 使用した説明変数)を SSDSE-A-2025 に適用
df['第1次産業就業者率'] = df['第1次産業就業者数'] / df['就業者数'] * 100
df['第2次産業就業者率'] = df['第2次産業就業者数'] / df['就業者数'] * 100
df['第3次産業就業者率'] = df['第3次産業就業者数'] / df['就業者数'] * 100
df['完全失業率'] = df['完全失業者数'] / (df['完全失業者数'] + df['就業者数']) * 100
df['学校数_10万人'] = (df['幼稚園数'] + df['小学校数'] + df['中学校数'] + df['高等学校数']) / df['総人口'] * 1e5
df['福祉施設数_10万人'] = (df['公民館数'] + df['図書館数'] + df['一般病院数'] + df['保育所等数(基本票)']) / df['総人口'] * 1e5

# 大都市(移動元)=東京23特別区+政令指定都市20市、地方(移動先)=総人口20万人未満
seirei = ['札幌市', '仙台市', 'さいたま市', '千葉市', '横浜市', '川崎市', '相模原市',
          '新潟市', '静岡市', '浜松市', '名古屋市', '京都市', '大阪市', '堺市',
          '神戸市', '岡山市', '広島市', '北九州市', '福岡市', '熊本市']
is_ward = (df['都道府県'] == '東京都') & df['市区町村'].str.endswith('区', na=False)
is_seirei = df['市区町村'].isin(seirei)
df['地域区分'] = np.where(is_ward | is_seirei, '大都市(移動元)',
                       np.where(df['総人口'] < 200000, '地方(移動先)', 'その他(中核市等)'))

n_big = (df['地域区分'] == '大都市(移動元)').sum()
n_local = (df['地域区分'] == '地方(移動先)').sum()
print(f'市区町村総数: {len(df)}')
print(f'大都市(移動元): {n_big} 市区  /  地方(移動先): {n_local} 市町村  /  その他(中核市等): {(df["地域区分"]=="その他(中核市等)").sum()}')
print('※ 原論文(平成27年国勢調査)では 43 市区 / 1606 市町村。収録版は2020年国勢調査ベースのため件数は近似。')
▼ 実行結果
=== SSDSE-A 読み込みと説明変数の算出【実再現】 ===
市区町村総数: 1740
大都市(移動元): 43 市区  /  地方(移動先): 1608 市町村  /  その他(中核市等): 89
※ 原論文(平成27年国勢調査)では 43 市区 / 1606 市町村。収録版は2020年国勢調査ベースのため件数は近似。
  • ④ 実行結果の読み取り:大都市は43市区と原論文(43市区)に一致、地方は1608市町村(原論文1606)とほぼ一致。件数の差は原論文が平成27年、収録版が2020年国勢調査ベースであることによる。
やってみよう表1(基本統計量)を大都市/地方で再計算する【実再現】
  • ① このコードの目的:原論文の表1にならって、説明変数の平均・標準偏差・最小・最大を、大都市(移動元)と地方(移動先)それぞれで計算して並べる。
  • ② 前後のつながり:この基本統計量が図1(分布の箱ひげ図)の材料になる。大都市と地方で説明変数の水準がどう違うかを数値で押さえる。
📝 コード
106
107
108
109
110
111
112
113
114
show_vars = ['総人口', '第1次産業就業者率', '第2次産業就業者率', '第3次産業就業者率',
             '完全失業率', '学校数_10万人', '福祉施設数_10万人']
for grp in ['大都市(移動元)', '地方(移動先)']:
    sub = df[df['地域区分'] == grp]
    print(f'\n{grp}】 N={len(sub)}')
    stat = sub[show_vars].agg(['mean', 'std', 'min', 'max']).T
    stat.columns = ['平均', '標準偏差', '最小', '最大']
    print(stat.round(2).to_string())
print()
▼ 実行結果
=== 表1の再現:説明変数の基本統計量(大都市 vs 地方)【実再現・SSDSE-A-2025】 ===

【大都市(移動元)】 N=43
                   平均       標準偏差        最小          最大
総人口         872844.98  745683.00  66680.00  3777491.00
第1次産業就業者率        0.60       0.88      0.02        3.52
第2次産業就業者率       16.20       5.13      8.25       33.41
第3次産業就業者率       79.41       5.30     61.68       87.16
完全失業率            3.71       0.63      1.86        4.93
学校数_10万人        27.27       9.91     18.20       82.48
福祉施設数_10万人      34.12       7.90     23.52       67.49

【地方(移動先)】 N=1608
                  平均      標準偏差      最小         最大
総人口         36098.59  41467.46  169.00  199849.00
第1次産業就業者率      11.01      9.91    0.14      75.62
第2次産業就業者率      25.06      8.12    1.74      52.50
第3次産業就業者率      61.98      9.16   20.67      96.12
完全失業率           3.63      1.19    0.00      10.63
学校数_10万人       69.38     91.46    0.00    1891.89
福祉施設数_10万人     96.50    155.70    0.00    3169.01
  • ④ 実行結果の読み取り:大都市は総人口が桁違いに大きく第3次産業就業者率が約79%と高い。一方人口10万人あたりの学校数・福祉施設数は地方の方が多い(人口が少ないため per capita が大きい)。第1次産業就業者率も地方が圧倒的に高く、原論文の表1と同じ大都市/地方の対比が再現できている。
2
図1:大都市と地方の説明変数の分布(実再現)

表1の数値を箱ひげ図にして、大都市(移動元)と地方(移動先)で説明変数がどう分かれるかを一目で確かめる。これは SSDSE-A-2025 からの実再現である(原論文は平成27年、本図は2020年国勢調査ベース)。

大都市と地方の説明変数の分布(実再現)
図1:大都市(移動元)と地方(移動先)の説明変数の分布(実再現・SSDSE-A-2025、大都市43市区・地方1608市町村)。原論文の表1に対応する変数を箱ひげ図で比較。
📊 この図の読み方
学校数・福祉施設数
人口10万人あたりで見ると地方の方が多く、ばらつきも大きい。人口が少ない町村ほど per capita が大きくなる。原論文で移動先(地方)の学校数・福祉施設数が正の係数を持ったことと整合的。
第1次産業就業者率
地方は農林漁業の割合が高く広く分布、大都市はほぼ0付近に固まる。地域構造の違いがはっきり出ている。
完全失業率
大都市・地方とも中央値は近いが、地方の方が上振れ(高失業率の町村)が多い。
位置づけ
実再現。数値は本ページで SSDSE-A-2025 から計算したもの。原論文(平成27年)とは年次が違うため水準は完全一致しない。
3
図2:説明変数間の相関行列(実再現)

修正重力モデルは多数の説明変数を同時に扱う。ところが就業構造など互いに強く相関する変数があると、通常の重回帰は係数の推定が不安定になる(多重共線性)。その様子を相関行列で確かめる。

やってみよう説明変数間の相関行列を計算する【実再現】= Elastic Net が要る理由
  • ① このコードの目的:地方(移動先)市町村について、説明変数どうしの相関係数行列を計算し、相関の強いペアを取り出す。原論文が図2で示した「係数・変数間の相関」に対応する、多重共線性の確認である。
  • ② 前後のつながり:ここで相関の高い変数群があることを確かめると、次節でなぜ通常の重回帰ではなく Elastic Net なのかが腑に落ちる。
📝 コード
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
corr_vars = ['総人口', '第1次産業就業者率', '第2次産業就業者率', '第3次産業就業者率',
             '完全失業率', '学校数_10万人', '福祉施設数_10万人']
short = {'総人口': '総人口', '第1次産業就業者率': '第1次産業', '第2次産業就業者率': '第2次産業',
         '第3次産業就業者率': '第3次産業', '完全失業率': '完全失業率',
         '学校数_10万人': '学校数', '福祉施設数_10万人': '福祉施設数'}
cmat = loc[corr_vars].corr()
cmat_disp = cmat.rename(index=short, columns=short)
print('(地方=移動先市町村 N={} での相関)'.format(len(loc)))
print(cmat_disp.round(2).to_string())
# 最も強い相関ペア
pairs = []
cols = corr_vars
for i in range(len(cols)):
    for j in range(i + 1, len(cols)):
        pairs.append((abs(cmat.iloc[i, j]), short[cols[i]], short[cols[j]], cmat.iloc[i, j]))
pairs.sort(reverse=True)
print('\n相関の強い変数ペア上位3組(多重共線性の目安):')
for a, x, y, v in pairs[:3]:
▼ 実行結果
=== 説明変数間の相関行列【実再現】:多重共線性と Elastic Net の必要性 ===
(地方=移動先市町村 N=1608 での相関)
        総人口  第1次産業  第2次産業  第3次産業  完全失業率   学校数  福祉施設数
総人口    1.00  -0.47   0.12   0.34   0.15 -0.27  -0.24
第1次産業 -0.47   1.00  -0.46  -0.62  -0.36  0.27   0.23
第2次産業  0.12  -0.46   1.00  -0.40   0.12 -0.25  -0.10
第3次産業  0.34  -0.62  -0.40   1.00   0.28 -0.03  -0.14
完全失業率  0.15  -0.36   0.12   0.28   1.00 -0.25  -0.21
学校数   -0.27   0.27  -0.25  -0.03  -0.25  1.00   0.27
福祉施設数 -0.24   0.23  -0.10  -0.14  -0.21  0.27   1.00

相関の強い変数ペア上位3組(多重共線性の目安):
  第1次産業 × 第3次産業: r=-0.62
  総人口 × 第1次産業: r=-0.47
  第1次産業 × 第2次産業: r=-0.46
  • ④ 実行結果の読み取り:第1次産業就業者率と第3次産業就業者率が r=−0.62 など、就業構造の変数どうしが強く相関している(産業構成の合計が100%になるため)。こうした多重共線性があると通常の重回帰は係数が不安定になる。だから原論文は変数選択に強い Elastic Net を使った。
説明変数間の相関行列(実再現)
図2:説明変数間の相関行列(実再現・SSDSE-A-2025、地方1608市町村)。青=正、赤=負。相関の強い変数群があるため、原論文は Elastic Net で変数選択している。
📊 この図の読み方
赤い(負の)マス
第1次産業と第3次産業(−0.62)など、産業構成の変数どうしは強い負の相関。3つの産業比率は合計100%に近づくため、機械的に負の相関が出る。
多重共線性
こうした相関の強い変数群があると、Ridgeでは変数選択ができず、Lassoでは相関する変数群から1つしか残らない。両者の弱点を補うのが Elastic Net
位置づけ
実再現。原論文の図2(係数同士の相関行列)と同じ「変数間の相関を見て多重共線性に備える」趣旨を、収録データで再現したもの。

修正重力モデルと Elastic Net

① 重力モデル → 修正重力モデル 地域 i から j への移動量 M を、両地域の人口 P の積を距離 D で割った形で表すのが重力モデル
M(i,j) = a0 · P(i)^a1 · P(j)^a2 / D(i,j)^a3
これに所得・就業・教育などの修正項を加え、両辺の自然対数をとると次の対数線形モデルになる:
log M = logβ0 + a1·logP(i) + a2·logP(j) − a3·logD + β1·logY(i) + β2·logY(j) + Σαn·logX(i,n) + Σγm·logX(j,m)
② 対数線形だから係数=弾力性 両辺が対数なので、各係数は「その説明変数が1%増えると移動量が何%変わるか」という弾力性として読める。たとえば移動間距離の係数 −0.569 は「距離が1%長いと移動量が約0.57%減る」という意味。符号と大きさの両方に意味がある。
③ なぜ Elastic Net か 説明変数が多く多重共線性があるため、通常の重回帰は不安定。Ridgeは変数選択ができず、Lassoは相関する変数群から1つしか選べない。両者を組み合わせた Elastic Net なら、相関の強い変数群を扱いつつ変数選択ができる。原論文は正則化の強さλとL1/L2の比αを、5-fold クロスバリデーション+グリッドサーチで決定している。係数が0になった変数は「選ばれなかった=移動量と関連なし」と解釈する。
4
図3:回帰係数(表2)の可視化(報告値)

修正重力モデルを Elastic Net で推定した結果が原論文の表2である。移動フローと距離のデータが必要なので、本ページでは再計算せず、報告値をそのまま可視化する。符号(正負)と絶対値の大きさで読み解くのが原論文の方針だ。

やってみよう原論文 表2 の回帰係数を転記して可視化する【報告値・再計算ではない】
  • ① このコードの目的:原論文の表2(Elastic Net で推定した修正重力モデルの回帰係数)を、PDF の数値どおりに辞書へ転記し、絶対値の大きい順に並べる。ここは再計算ではなく報告値の転記(移動フロー・距離が SSDSE 未収録のため)。
  • ② 前後のつながり:この報告値が図3(係数の棒グラフ)の材料になる。x=移動元、y=移動先を表す。
📝 コード
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
reported = [
    ('総人口_x',                              0.061648),
    ('総人口_y',                              0.069374),
    ('移動間距離',                             -0.568857),
    ('第1次産業就業者率_x',                    0.134868),
    ('第1次産業就業者率_y',                   -0.029745),
    ('第2次産業就業者率_x',                   -0.060645),
    ('第2次産業就業者率_y',                   -0.130457),
    ('第3次産業就業者率_x',                    0.078206),
    ('完全失業率_x',                          0.015544),
    ('完全失業率_y',                          -0.032623),
    ('学校数_x',                              0.114437),
    ('学校数_y',                              0.107113),
    ('福祉施設数_x',                          0.134630),
    ('福祉施設数_y',                          0.041808),
    ('子供を対象とした活動_x',                -0.044284),
    ('子供を対象とした活動_y',                 0.010989),
    ('スポーツ文化芸術学術活動_x',            -0.076732),
    ('スポーツ文化芸術学術活動_y',            -0.031711),
    ('安全な生活のための活動_x',               0.062168),
    ('安全な生活のための活動_y',              -0.023933),
    ('課税対象所得_x',                        -0.086024),
    ('課税対象所得_y',                        -0.042550),
]
rep = pd.DataFrame(reported, columns=['変数名', '回帰係数'])
print('(原論文 表2 の報告値。x=移動元、y=移動先。※移動フロー・距離は SSDSE 未収録のため再計算不可)')
rep_sorted = rep.reindex(rep['回帰係数'].abs().sort_values(ascending=False).index)
for _, r in rep_sorted.iterrows():
    print(f'  {r["変数名"]:<24} {r["回帰係数"]:+.6f}')
print(f'\n絶対値最大:移動間距離 {rep.loc[rep["変数名"]=="移動間距離","回帰係数"].iloc[0]:+.6f}(長距離移動が人口移動のネック)')
▼ 実行結果
=== 表2の転記:修正重力モデル×Elastic Net の回帰係数【報告値・再計算ではない】 ===
(原論文 表2 の報告値。x=移動元、y=移動先。※移動フロー・距離は SSDSE 未収録のため再計算不可)
  移動間距離                    -0.568857
  第1次産業就業者率_x              +0.134868
  福祉施設数_x                  +0.134630
  第2次産業就業者率_y              -0.130457
  学校数_x                    +0.114437
  学校数_y                    +0.107113
  課税対象所得_x                 -0.086024
  第3次産業就業者率_x              +0.078206
  スポーツ文化芸術学術活動_x           -0.076732
  総人口_y                    +0.069374
  安全な生活のための活動_x            +0.062168
  総人口_x                    +0.061648
  第2次産業就業者率_x              -0.060645
  子供を対象とした活動_x             -0.044284
  課税対象所得_y                 -0.042550
  福祉施設数_y                  +0.041808
  完全失業率_y                  -0.032623
  スポーツ文化芸術学術活動_y           -0.031711
  第1次産業就業者率_y              -0.029745
  安全な生活のための活動_y            -0.023933
  完全失業率_x                  +0.015544
  子供を対象とした活動_y             +0.010989

絶対値最大:移動間距離 -0.568857(長距離移動が人口移動のネック)
  • ④ 実行結果の読み取り:移動間距離の係数 −0.568857 が絶対値最大で、長距離移動が人口移動のネックであることを示す。次いで移動元の第1次産業就業者率・福祉施設数、移動先の第2次産業就業者率などが続く。これらはすべて原論文の報告値で、図3にそのまま可視化する。
修正重力モデル×Elastic Net の回帰係数(報告値の可視化)
図3:修正重力モデル×Elastic Net の回帰係数。報告値の可視化(再計算ではない):数値は原論文 表2 の報告値。青=正、赤=負。x=移動元、y=移動先。
📊 この図の読み方
最も長い赤い棒
移動間距離(−0.569)。絶対値が全変数で最大。長距離移動が人口移動の最大のネックという、先行研究と同じ結果。
正の棒(青)
総人口(x・y とも正)、移動先の学校数(+0.107)・福祉施設数(+0.042)・子供を対象とした活動(+0.011)など。これらの充実が地方への移動を後押しする。
負の棒(赤)
課税対象所得(x・y とも負)=所得の高い地域より生活コストの低い地域へ、など。
位置づけ
報告値の可視化。数値は原論文の報告値であり、本ページで新たに計算したものではない。
5
図4:移動元と移動先の係数対比(報告値)

同じ指標でも、移動元(大都市)と移動先(地方)で係数の符号が変わることがある。その符号反転を左右の棒で対比する。移動フローが必要なので報告値の可視化である。

やってみよう移動元(x) と 移動先(y) の係数を対比する【報告値・再計算ではない】
  • ① このコードの目的:同じ指標でも「移動元(大都市)」と「移動先(地方)」で係数の符号が変わる項目に注目して、x と y を並べて表示する。すべて原論文 表2 の報告値
  • ② 前後のつながり:この対比が図4(左右の棒グラフ)になる。符号が反転する変数こそ、若者の移動メカニズムを読み解く鍵になる。
📝 コード
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
pairs_xy = [
    ('総人口', 0.061648, 0.069374),
    ('第1次産業就業者率', 0.134868, -0.029745),
    ('第2次産業就業者率', -0.060645, -0.130457),
    ('完全失業率', 0.015544, -0.032623),
    ('学校数', 0.114437, 0.107113),
    ('福祉施設数', 0.134630, 0.041808),
    ('子供を対象とした活動', -0.044284, 0.010989),
    ('安全な生活のための活動', 0.062168, -0.023933),
    ('課税対象所得', -0.086024, -0.042550),
]
pxy = pd.DataFrame(pairs_xy, columns=['変数', '移動元x', '移動先y'])
print('(同じ指標でも移動元と移動先で符号が変わる項目に注目。原論文 表2 の報告値)')
for _, r in pxy.iterrows():
    flip = '  ← 符号反転' if r['移動元x'] * r['移動先y'] < 0 else ''
    print(f'  {r["変数"]:<20} x={r["移動元x"]:+.4f}  y={r["移動先y"]:+.4f}{flip}')
▼ 実行結果
=== 移動元(x) と 移動先(y) の係数対比【報告値・再計算ではない】 ===
(同じ指標でも移動元と移動先で符号が変わる項目に注目。原論文 表2 の報告値)
  総人口                  x=+0.0616  y=+0.0694
  第1次産業就業者率            x=+0.1349  y=-0.0297  ← 符号反転
  第2次産業就業者率            x=-0.0606  y=-0.1305
  完全失業率                x=+0.0155  y=-0.0326  ← 符号反転
  学校数                  x=+0.1144  y=+0.1071
  福祉施設数                x=+0.1346  y=+0.0418
  子供を対象とした活動           x=-0.0443  y=+0.0110  ← 符号反転
  安全な生活のための活動          x=+0.0622  y=-0.0239  ← 符号反転
  課税対象所得               x=-0.0860  y=-0.0425
  • ④ 実行結果の読み取り:完全失業率・第1次産業就業者率・子供を対象とした活動・安全な生活のための活動で符号が反転。たとえば完全失業率は移動元で正・移動先で負=「失業率の低い地域へ移入する」。原論文はこうした符号の向きを Cadwallader の5要因に沿って解釈している。
移動元と移動先の回帰係数の対比(報告値の可視化)
図4:移動元(x) と 移動先(y) の係数の対比。報告値の可視化(再計算ではない):赤=移動元x、青=移動先y。数値は原論文 表2 の報告値。
📊 この図の読み方
符号が反転する変数
完全失業率・第1次産業就業者率・子供を対象とした活動・安全な生活のための活動。移動元と移動先で効き方が逆になる。
完全失業率
移動元で正・移動先で負 = 失業率の低い地域へ移入する傾向。
学校数・福祉施設数
x・y とも正だが、原論文は「大都市は人口が多く学校・施設も多いので移動元xの正は解釈しにくい。移動先yが正であることが本質」と読んでいる。
位置づけ
報告値の可視化。数値は原論文 表2 の報告値。
6
主要な発見(Cadwalladerの5要因で読む)

原論文は Cadwallader(1996) の人口移動6要因のうち、若者に不要な「年齢」を除いた5要因に変数を対応づけて解釈した。以下の係数はすべて原論文 表2 の報告値である。

基本要因:総人口と移動間距離

変数係数(報告値)解釈
総人口(移動元x/移動先y)+0.062/+0.069ともに正。人口が多い地域ほど移動が活発(重力モデルどおり)。
移動間距離−0.569絶対値最大。長距離移動が最大のネック。

① 所得格差:課税対象所得

課税対象所得は移動元・移動先ともに(x=−0.086、y=−0.043)。所得の高い地域ではなく生活コストの低い地域へ移動する傾向。荒川(2020)の主張を支持。

② 雇用機会:就業構造・完全失業率

完全失業率は移動元で正(+0.016)・移動先で負(−0.033) = 失業率の低い地域へ移入(Herzog型)。第1次産業就業者率は移動元で正(+0.135)・移動先で負(−0.030) = 農林漁業の盛んな地方へ移出。第2次産業は移動元・移動先とも負。

③ 教育:学校数・子供を対象とした活動

移動先の学校数(+0.107)・子供を対象とした活動(+0.011)がともに正。地方への移動が必要になったとき、学校の多い・子供の活動が盛んな地域が選ばれる。Cadwalladerの指摘どおり。

④ 生活の質:スポーツ文化芸術学術活動・安全な生活のための活動

スポーツ・文化・芸術・学術の活動は移動元・移動先とも負。安全な生活のための活動は移動元で正・移動先で負。この一部は「更なる検証が必要」と原論文も留保している。

⑤ 行政サービス:福祉施設数

移動先の福祉施設数(+0.042)が正。地方への移動時に、福祉施設の多い地域が選ばれる。荒川(2018)とも整合。

3つの知見(まとめ) ①若者の大都市→地方移動を促す顕著な要因は移動先の学校数・子供を対象とした活動・福祉施設数(いずれも正)で、これらの充実が地方創生につながる。②Cadwalladerの6要因のうち当てはまらない項目もあった=対象(地域・年代)を絞ると要因が変わる。③Elastic Net のハイパーパラメータを適切に設定することで、相関の強い変数を同時に扱いつつ変数選択ができた。

まとめと課題

本研究は、移動人口の約7割を占める20〜40代の若者について、大都市から地方への人口移動要因を修正重力モデル+Elastic Netで定量分析した。その結果、移動先の学校数・子供を対象とした活動・福祉施設数が若者の移動に正の影響を与えること、そしてこれらの充実が地方創生の促進につながることが示唆された。国内で修正重力モデル×Elastic Net により若者の人口移動を分析した例はなく、変数間の関係を明らかにした点に貢献がある。

今後の課題(原論文) ① Cadwallader や荒川の先行研究と符号が一致しなかった項目を、別の属性に対して同じ手法で分析し要因を確かめる。② 修正重力モデル以外の純移動率モデルや Baxter-Ewing 法でも推定・分析し、結果の正当性を検証する。
この研究から学べること 地域間の人口移動という現象を、物理の重力のアナロジー(重力モデル)で定量化し、対数線形回帰の係数を弾力性として読む発想。そして多数の相関する変数を Elastic Net で扱い、「報告値」と「収録データで再計算できる部分」を厳密に区別する姿勢。

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

このページの説明変数の作成・大都市/地方比較・相関行列(図1・図2)は、以下から再現できます。

🐍 再現コード(.py) 📊 SSDSE-A-2025.csv

※ 修正重力モデルの回帰係数(表2・図3・図4)は、住民基本台帳の移動フローと市区町村間の距離が必要で SSDSE に未収録のため、原論文の報告値を可視化したものです(再計算ではありません)。図1・図2 の再計算値も、収録版が2020年国勢調査ベースのため原論文(平成27年)とは完全一致しません。

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

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

誤解1:「係数の符号がそのまま因果の向きを表す」
修正重力モデルは相関構造をとらえた回帰であり、係数の符号は「関連の向き」を示すが、施策を打てば必ずその通り人が動くという因果保証ではない。原論文も一部の符号は「更なる検証が必要」と留保している。
誤解2:「移動元(x)の学校数が正だから、大都市の学校を増やせば移動が増える」
原論文は「大都市は人口が多く学校・福祉施設も多いので、移動元xの正は解釈しにくい」と述べている。本質は移動先yが正であること。xとyを混同しないこと。
誤解3:「Elastic Net で0になった変数は無意味」
0=「このモデル・このデータで移動量との明確な関連が検出されなかった」であり、絶対に無関係という意味ではない。変数選択の結果はデータ年次やモデルに依存する。
誤解4:「このページの図はすべて原論文の再計算」
違う。図1・図2は SSDSE-A-2025 からの実再現(2020年国勢調査ベース)、図3・図4は移動フロー・距離が必要なため原論文の報告値の可視化。図注に二重に明記している。

📖 用語集(この記事に出てくる統計用語)

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

Elastic Net 回帰
Lasso(L1)と Ridge(L2)の正則化を組み合わせた回帰。相関の強い変数群を扱いつつ変数選択ができる。本研究のパラメータ推定の中心。
Lasso 回帰
L1正則化で一部の係数を厳密に0にし変数選択する回帰。相関する変数群からは1つしか残さない弱点がある。
Ridge 回帰
L2正則化で係数を縮小し多重共線性に強い回帰。ただし係数を0にせず変数選択はできない。
正則化
係数の大きさに罰則を課して過学習を防ぐ手法。λが正則化の強さ、αがL1/L2の比。
多重共線性
説明変数どうしが強く相関し、回帰係数の推定が不安定になる問題。本研究が Elastic Net を使う動機。
クロスバリデーション
データを分割して汎化性能を評価する手法。本研究はλ・αを5-fold CV+グリッドサーチで決定。
回帰係数
説明変数が結果に与える影響の大きさと向き。対数線形モデルでは弾力性(何%変化するか)として読める。
相関係数
2変数が一緒に増減する強さと向きを−1〜+1で表す指標。本研究では変数間の多重共線性の確認に使う。
SSDSE
統計センターの教育用標準データセット。SSDSE-A は市区町村データ、SSDSE-D は都道府県別の生活行動データ。

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

この研究で使われている手法を、考え方の順に説明する。

全体像
重力モデルで移動フローを人口と距離から説明する → 社会経済変数を足して修正重力モデルにする → 両辺を対数化して線形回帰にする(係数=弾力性)→ 多重共線性に強い Elastic Net で変数選択・推定する → 選ばれた係数の符号で移動要因を解釈する。
🌍 重力モデル/修正重力モデル
何をする
2地域間の移動量を「人口の積 ÷ 距離」で説明する(万有引力のアナロジー)。これに就業・所得・教育などの修正項を加えたのが修正重力モデル。
なぜ使う
エントロピーモデルは総流出・総流入を制約に与える必要があるが、大都市↔地方の二地域モデルでは重力モデルが妥当(先行研究との比較もしやすい)。
注意
距離は緯度経度からヒュベニの公式で算出。距離・移動フローは SSDSE 未収録なので、本ページでは係数を報告値として扱う。
📈 対数線形回帰と弾力性
何をする
重力モデルの両辺の自然対数をとると、積・べき乗が和・係数の掛け算になり、ふつうの線形回帰で推定できる。
読み方
被説明変数も説明変数も対数なので、係数は弾力性=「説明変数が1%増えると移動量が何%変わるか」。移動間距離 −0.569 は「距離1%増で移動量約0.57%減」。
注意
対数は0で−∞になるため、値が0の変数(本研究では福祉施設数の一部)は対数化後に0へ置換する処理をしている。
🧲 Elastic Net による変数選択
何をする
Lasso(L1)とRidge(L2)の罰則を混ぜた正則化回帰。係数を縮小しつつ一部を0にする。
なぜ必要
就業構造など相関の強い変数群があるため。Ridgeは選択不可、Lassoは群から1つしか残らない。Elastic Netは群ごと残しつつ選択できる。
調整
正則化の強さλとL1/L2比αを、5-fold クロスバリデーション+グリッドサーチで決める。0になった係数は「選ばれなかった変数」。

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

この研究の「符号が一致しない要因があった/モデルは1つだけ検証」という限界は、次の研究の出発点になる。

発展1:別の属性でも同じ手法をかける
結果X
Cadwallader や荒川と符号が一致しない項目があった。
新仮説Y
対象を若年層以外(高齢層・子育て世帯など)に変えれば、要因の一致・不一致が切り分けられるのでは。
課題Z
被説明変数を別属性の移動量に差し替え、同じ修正重力モデル×Elastic Net で推定して符号を比較する。
発展2:別モデルで頑健性を確かめる
結果X
推定は修正重力モデル×Elastic Net の1本のみ。
新仮説Y
純移動率モデルや Baxter-Ewing 法でも同じ結論が出れば、分析の正当性が高まる。
課題Z
複数モデルで係数の符号・大きさを比較し、結果の頑健性(ロバストネス)を評価する。

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

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

★☆☆☆☆ 難易度1
大都市/地方の区分を変える
地方の人口しきい値 200000100000 に変え、大都市・地方・その他の件数がどう変わるか確かめよう。
★★☆☆☆ 難易度2
別の説明変数を作る
show_vars に「第2次産業就業者率」や新たに作った変数を足して、大都市/地方の基本統計量を比べよう。
★★★☆☆ 難易度3
大都市側で相関行列を出す
cmat = loc[...]locbig に変えて、大都市43市区での変数間相関が地方とどう違うか観察しよう。
★★★★☆ 難易度4
係数を Cadwallader の5要因で色分けする
図3の棒を、所得・雇用・教育・生活の質・行政サービスの5グループで色分けして、どの要因が効いているか一目で分かるようにしよう。
★★★★★ 難易度5
簡易な重力モデルを組んでみる
2地域の人口と(適当な)距離を仮に置いて log M = a1·logP_i + a2·logP_j − a3·logDscikit-learnElasticNet で推定し、対数線形回帰の感触をつかもう(本物の移動フローが無くても手順は学べる)。
ヒント:まず人口だけ・距離だけの単純な重力モデルから始め、少しずつ変数を足す。

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

「地域間の移動・フローを人口と距離+社会経済要因で説明する」重力モデルの発想は、現場でも広く使われている。

🏙️
地方創生・移住政策
どの施策(学校・子育て・福祉の充実)が移住を促すかを移動データで分析し、限られた予算の配分先を決める。
🚚
物流・交通需要予測
都市間の貨物・旅客の流れを重力モデルで予測し、輸送網や交通インフラの計画に活かす。
🛒
商圏・立地分析
店舗の集客を「人口 × 魅力 ÷ 距離」で見積もるハフモデル(重力モデルの応用)で出店地を検討する。

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

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

Q. 重力モデルの「重力」ってどういう意味?
A. 物理の万有引力(質量×質量÷距離²)になぞらえた名前です。2地域間の移動量を「人口の積 ÷ 距離」で説明する、という発想を表しています。修正重力モデルは、これに就業や教育などの要因を足したものです。
Q. このページの図は原論文と同じ数値ですか?
A. 一部だけ実再現です。説明変数の分布(図1)と相関行列(図2)は SSDSE-A-2025 から実際に計算した実データ(ただし2020年国勢調査ベース)。回帰係数(図3・図4)は移動フローと距離が必要なため、原論文の報告値を可視化したものです。図注に二重に明記しています。
Q. なぜ普通の重回帰ではなく Elastic Net なの?
A. 説明変数が多く、就業構造などが互いに強く相関している(多重共線性)ためです。Ridge は変数選択ができず、Lasso は相関する変数群から1つしか残せません。両方の弱点を補う Elastic Net なら、相関の強い変数群を扱いつつ変数を選べます。
Q. 係数が「弾力性」というのはどういうこと?
A. 重力モデルの両辺を対数にして回帰しているためです。被説明変数も説明変数も対数なので、係数は「説明変数が1%増えると移動量が何%変わるか」を表します。移動間距離の−0.569は「距離が1%長いと移動量が約0.57%減る」という意味です。

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

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

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

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

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