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

外国人人口と市区町村の特性との関係性
重回帰・変数選択・決定木・ランダムフォレストによる探索的分析

⏱️ 推定読了時間: 約40分
西尾 春香(関西学院大学経済学部) | 2019年度受賞作品 | データ:SSDSE-2019A(市区町村データ)+ e-Stat 追加4変数
🔬 ランダムフォレスト🔬 交差検証🔬 変数選択🔬 決定木🔬 重回帰🏷 外国人・国際🏷 農林水産🏷 財政・行政
🔬 手法タグ / 🏷 応用タグ(クリックで同タグの論文をネットワーク検索)
🔬 再現カルテ — 原論文と同じデータ・同じ手法で再現

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

原論文が使ったデータSSDSE-A・都道府県・市区町村のすがた(社会・人口統計体系)
分析単位:市区町村
中核手法:重回帰分析・Best Subset Selection・決定木回帰・ランダムフォレスト・10-fold クロスバリデーション
この教材が使うデータ
原論文(PDF)外国人人口と市区町村の特性との関係性
特別賞/西尾 春香(関西学院大学経済学部)
✅ この教材でできること
  • 原論文の中核手法(重回帰分析・決定木回帰・ランダムフォレスト)を実データで実行できる
  • 分析に使うデータは同梱済みで、ブラウザ上でそのまま読み込める
  • 数値・図を最後まで再計算できる(ランダムフォレスト・重回帰分析(OLS)・決定木)
突合監査の結果、主要データと中核手法はいずれも原論文と一致しています。

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

🏅 論文審査会コメント(審査員はここを評価した)
「外国人人口について様々な探索的なデータ分析を行い、機械学習による政策分析の可能性を示す論文として評価された。論文としては47件に対して29変数の投入の問題など、再考の余地があるが解釈も明確である。」
出典:統計センター「統計データ分析コンペティション」受賞論文PDF掲載の審査講評。プロの審査員が何を評価し、何を注文したかは論文の読み方の最良の手本になる。
📝 3行で分かる要約

目次

  1. 研究の背景と目的
  2. データと分析手法
  3. 主要な分析結果
  4. 統計的手法の解説
  5. 発展的学習
  6. まとめ
  7. 参考文献・データ出典
  8. 📥 データの準備
  9. 💼 実社会での応用
  10. ⚠️ よくある誤解
  11. 📖 用語集
  12. 📐 手法ガイド
  13. 🚀 発展の可能性
  14. 🎯 自分でやってみよう
  15. 🤔 Q&A
  16. 🐍 ブラウザで動かす

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

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

このページの実データ計算(図1・図3・図4と実行結果)を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。図2は原論文 表2 の報告値を可視化するもので、追加データは不要です。

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

日本に住む外国人への関心が高まっている。外国人人口は1980年代後半から増加が顕著になり、リーマンショックや東日本大震災の影響で一時的に減少する時期はあったものの、増加傾向が続いてきた。総務省の住民基本台帳に基づく人口調査(2019年1月1日時点)によると、外国人人口は前年より約17万人増えて過去最多となり、全国の人口総数に占める外国人住民の割合が初めて2%を超えた。一方で日本人人口は前年より約43万人少なく、10年連続の減少となった。

さらに2019年4月1日には、人手不足が深刻な産業分野を対象とする在留資格「特定技能」が新設され、一定の専門性・技能を持つ新たな外国人材の受入れが可能になった(熟練者を想定した特定技能2号では家族の帯同を含む長期滞在が可能)。在留外国人の増加傾向は今後も続くと考えられ、受け入れ側の自治体には、災害時の多言語対応や子どもの就学支援など、生活環境の整備が求められている。

そこで原論文は「外国人人口と自治体が持つ特性との間に結びつきがあるか。あるならどの特性と、どの程度の強さか」を計量分析で調べる。 自治体は人口・経済・行政・教育・社会保障など多面的な特性を持つが、外国人人口との関連を市区町村レベルで幅広く調べた研究は少なく、この点を明らかにすることは現在の日本の社会構造の理解につながる。

先行研究と本研究の位置づけ

外国人人口に関する先行研究としては、外国人の新規流入と国内移動(石川ほか 2014)、市区町村における外国人の社会増加(清水 2017)、外国人女性の出生数と出生率(山内 2010、是川 2013)、外国人の居住地選択(是川 2008)、外国人労働者導入の影響(中村 2009)、都道府県別の外国人の自然動態(中川ほか 2018)などがある。しかし外国人人口と市区町村の特性との関連性は十分に調べられておらず、原論文は教育用標準データセット(SSDSE)の市区町村データを使った統計分析でこの点の考察を深めた。

論文審査会コメント(原論文より) 外国人人口について様々な探索的なデータ分析を行い、機械学習による政策分析の可能性を示す論文として評価された。論文としては47件に対して29変数の投入の問題など、再考の余地があるが解釈も明確である。
分析の流れ
SSDSE-A
市区町村データ
+e-Stat追加
重回帰
(29変数)
Best Subset
Selection
(Cp基準)
決定木
ランダム
フォレスト
10-fold CV
で手法比較

SSDSE-A 重回帰分析 Best Subset Selection 決定木・ランダムフォレスト 10-fold クロスバリデーション

データと分析手法

使用データ

原論文は、独立行政法人統計センターが公開する教育用標準データセット SSDSE-2019A(市区町村データ)を主に用い、e-Stat「都道府県・市区町村のすがた(社会・人口統計体系)」から4変数(未婚者割合=2015年、課税対象所得=2017年、学歴割合(大卒)=2010年、刑法犯認知件数=2008年)を追加した。目的変数外国人人口(10万人あたり)説明変数は自治体の多面的な特性を表す29変数である。

再現可能性について(本ページの方針)
原論文の29変数のうち25変数(と目的変数)は現行 SSDSE-A-2025 の収録項目から構成できるため、図1・図3・図4と実行結果は SSDSE-A-2025 による実データ部分再現である(ただし原論文は2015年国勢調査ベース、本再現は2020年国勢調査ベースで年次が異なる)。e-Stat 追加の4変数(未婚者割合・課税対象所得・学歴割合(大卒)・刑法犯認知件数)は SSDSE 未収録のため再現に含められず、29変数モデルの結果(図2)は原論文 表2 の報告値の可視化(再計算ではない)として示す。新しい数値の創作はしない。

分析変数(原論文 表1 の要約)

分野 変数 計算式(原論文 表1) SSDSE-A-2025での再現
目的変数 外国人人口(10万人あたり) log(外国人人口 / 総人口 × 100000 + 1)
人口・世帯 総人口 log(総人口)
自然人口増減率(出生数 − 死亡数) / 総人口
社会的人口増減率(転入者数 − 転出者数) / 総人口△(日本人移動者のみ収録)
核家族世帯割合・単独世帯割合各世帯数 / 一般世帯数 × 100
人口密度log(総人口 / 可住地面積)
未婚者割合(15歳以上人口)e-Stat 追加(2015年)×(未収録)
経済基盤 従業者割合(11産業) 従業者数(産業別) / 従業者数 × 100
(農林業・建設・製造・情報通信・運輸郵便・卸売小売・学術研究・宿泊飲食・教育学習支援・医療福祉・その他サービス)
農家数(販売農家、10万人あたり)log(農家数 / 総人口 × 100000 + 1)
行政基盤 経常収支比率 経常収支比率(市町村財政)
歳出における土木費割合・教育費割合各費目 / 歳出決算総額 × 100
課税対象所得(納税義務者1人あたり)e-Stat 追加(2017年)・log変換×(未収録)
教育学歴割合(大卒)e-Stat 追加(2010年)×(未収録)
労働完全失業率完全失業者数 / (完全失業者数 + 就業者数) × 100
文化・スポーツ図書館数(10万人あたり)log(図書館数 / 総人口 × 100000 + 1)
健康・医療医師数(10万人あたり)log(医師数 / 総人口 × 100000 + 1)
福祉・社会保障保育所等数(10万人あたり)log(保育所等数 / 総人口 × 100000 + 1)
安全刑法犯認知件数(10万人あたり)e-Stat 追加(2008年)・log変換×(未収録)

※ 従業者割合の11産業は「外国人労働者数が比較的多い産業」として原論文が選択したもの(前田 2019 を参照)。分布が大きく歪んだ非負データは対数変換(0を含む場合は+1してから変換)。

データ処理(原論文 3節)

除外処理と標準化
  • 総人口がゼロの市区町村と、福島県楢葉町・富岡町・大熊町・双葉町・浪江町・葛尾村・飯舘村の7町村(「農林業センサス」を出典とする項目の調査が実施されなかったため)を除外
  • 最終的に全変数を平均0・分散1に標準化して分析に使用 → 回帰係数の絶対値で関係の強さを比較できる
  • 分析には R 言語を使用(Best Subset Selection=leaps、決定木=tree、ランダムフォレスト=RandomForest)。本ページの再現は Python(statsmodels・scikit-learn)

分析手法の概要

手法目的原論文(R)本再現(Python)
重回帰分析外国人人口とすべての特性の関係を同時に推定lmstatsmodels OLS
Best Subset SelectionCp基準で説明変数の最良の部分集合を選び過適合を防ぐleaps—(報告値のみ)
決定木回帰線形性を仮定せずデータを段階的に分割treescikit-learn
ランダムフォレスト複数の木を組み合わせて予測精度を向上RandomForestscikit-learn
10-fold クロスバリデーション4手法の妥当性を平均二乗誤差で比較scikit-learn
やってみようライブラリの読み込みと設定
📝 コード
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import os
import numpy as np
import pandas as pd
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import statsmodels.api as sm
from sklearn.tree import DecisionTreeRegressor, plot_tree
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold, cross_val_score

plt.rcParams['font.family'] = 'Hiragino Sans'
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 150

FIG_DIR = 'html/figures'
DATA_A = 'data/raw/SSDSE-A-2025.csv'
os.makedirs(FIG_DIR, exist_ok=True)
▼ 実行結果
このステップは print はしません。設定やデータが裏で更新されただけ。次のステップへ進みましょう。
💡 解説
  • statsmodels は重回帰の推定・検定に、scikit-learn は決定木・ランダムフォレスト・クロスバリデーションに使います。原論文は R(leapstreeRandomForest)で同じ分析を行っています。
  • matplotlib.use('Agg') — グラフを画面に出さずファイル保存するための設定。
  • plt.rcParams['font.family'] — 図の日本語表示用フォント指定(Macは Hiragino Sans、Windowsなら Yu Gothic 等に変更)。
💡 Python TIPS from sklearn.model_selection import KFold, cross_val_score のように、必要な関数だけをインポートすると名前が短く書けます。
やってみようSSDSE-A(市区町村データ)の読み込み
📝 コード
45
46
47
48
49
50
51
52
53
54
55
# ===== ステップ1: SSDSE-A(市区町村)から原論文 表1 の変数を構成 =====
# 1行目=変数コード、2行目=年度、3行目=日本語名 → コード行を列名に使う
raw = pd.read_csv(DATA_A, encoding='cp932', header=0, skiprows=[1, 2])
raw = raw.rename(columns={raw.columns[0]: 'code',
                          'Prefecture': '都道府県',
                          'Municipality': '市区町村'})
num = raw.apply(pd.to_numeric, errors='coerce')
print(f"【SSDSE-A-2025】{len(raw)}市区町村")
print('  原論文は SSDSE-2019A(2015年国勢調査ベース)+e-Stat追加4変数の29変数。')
print('  SSDSE-A-2025 では 未婚者割合・課税対象所得・学歴割合(大卒)・')
print('  刑法犯認知件数 の4変数が未収録 → 25変数で部分再現する')
▼ 実行結果
【SSDSE-A-2025】1741市区町村
  原論文は SSDSE-2019A(2015年国勢調査ベース)+e-Stat追加4変数の29変数。
  SSDSE-A-2025 では 未婚者割合・課税対象所得・学歴割合(大卒)・
  刑法犯認知件数 の4変数が未収録 → 25変数で部分再現する
💡 解説
  • pd.read_csv(..., encoding='cp932', header=0, skiprows=[1, 2]) — SSDSE-A は1行目が変数コード、2行目が年度、3行目が日本語名。コード行(A1101・A1700 など)を列名に使います。
  • raw.apply(pd.to_numeric, errors='coerce') — 全列を数値化し、数値にできないセルは欠損(NaN)にします。
  • 実行結果の注記は本ページの再現範囲の宣言です。原論文の29変数のうち、e-Stat から追加された4変数(未婚者割合・課税対象所得・学歴割合(大卒)・刑法犯認知件数)は現行 SSDSE-A-2025 に未収録のため、25変数での部分再現になります。
💡 Python TIPS errors='coerce' は「変換できない値はNaNに」という意味。データクリーニングの定番オプションです。
やってみよう原論文 表1 の計算式どおりに変数を構成
📝 コード
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
df = pd.DataFrame({'都道府県': raw['都道府県'], '市区町村': raw['市区町村']})
pop = num['A1101'].replace(0, np.nan)  # 総人口(2020)。人口0の町村は除外

# 目的変数: 外国人人口(10万人あたり) = log(外国人/総人口*100000 + 1)
df['外国人人口'] = np.log(num['A1700'] / pop * 100000 + 1)

# 説明変数(原論文 表1 の計算式に従う。単位は標準化するため影響しない)
df['総人口'] = np.log(pop)
df['自然人口増減率'] = (num['A4101'] - num['A4200']) / pop * 100
df['社会的人口増減率'] = (num['A5101'] - num['A5102']) / pop * 100
df['核家族世帯割合'] = num['A810102'] / num['A710101'] * 100
df['単独世帯割合'] = num['A810105'] / num['A710101'] * 100
df['人口密度'] = np.log(pop / num['B1103'])          # 可住地面積あたり
emp = {'農業林業': 'C220832', '建設業': 'C220836', '製造業': 'C220837',
       '情報通信業': 'C220839', '運輸郵便業': 'C220840',
       '卸売小売業': 'C220841', '学術研究専門技術': 'C220846',
       '宿泊飲食サービス業': 'C220847', '教育学習支援業': 'C220849',
       '医療福祉': 'C220850', 'サービス業他': 'C220852'}
for name, code in emp.items():   # 従業者割合(外国人労働者が多い11産業)
    df[f'従業者割合({name})'] = num[code] / num['C2208'] * 100
df['農家数'] = np.log(num['C310201'] / pop * 100000 + 1)  # 販売農家
df['経常収支比率'] = num['D2203']
df['土木費割合'] = num['D320308'] / num['D3203'] * 100
df['教育費割合'] = num['D320310'] / num['D3203'] * 100
df['完全失業率'] = num['F1107'] / (num['F1107'] + num['F1102']) * 100
df['図書館数'] = np.log(num['G1401'] / pop * 100000 + 1)
df['医師数'] = np.log(num['I6100'] / pop * 100000 + 1)
df['保育所等数'] = np.log(num['J250302'] / pop * 100000 + 1)
▼ 実行結果
このステップは print はしません。設定やデータが裏で更新されただけ。次のステップへ進みましょう。
💡 解説
  • 目的変数は log(外国人人口 / 総人口 × 100000 + 1)。原論文は分布が大きく歪んだ非負データに対数変換を施し、0を含む変数には1を加えてから変換しています(表1)。
  • 従業者割合は「外国人労働者数が比較的多い産業」として原論文が選んだ11産業。辞書+forループで11列を一気に作っています。
  • 人口密度は可住地面積あたり(総面積ではない)、農家数は販売農家、完全失業率は 完全失業者数/(完全失業者数+就業者数) — いずれも原論文 表1 の定義どおり。
💡 Python TIPS for name, code in emp.items(): — 辞書の「キーと値」を同時に取り出すループ。列の量産に便利です。
やってみよう欠損の除外と標準化(平均0・分散1)
📝 コード
86
87
88
89
90
91
92
93
# 総人口ゼロ(2020年国勢調査の福島県双葉町)と欠損値のある行を除外
df = df.dropna().reset_index(drop=True)
X_cols = [c for c in df.columns if c not in ('都道府県', '市区町村', '外国人人口')]
print(f"\n分析対象: {len(df)}市区町村 / 説明変数 {len(X_cols)}個")

# 原論文と同じく全変数を平均0・分散1に標準化
Z = df[X_cols + ['外国人人口']].copy()
Z = (Z - Z.mean()) / Z.std(ddof=0)
▼ 実行結果
分析対象: 1740市区町村 / 説明変数 25個
💡 解説
  • 2020年国勢調査で総人口が0人の福島県双葉町などは欠損になり除外されます。原論文(2015年国勢調査ベース)は総人口ゼロの市区町村と、農林業センサスが実施されなかった福島県7町村を除外しました。
  • (Z - Z.mean()) / Z.std(ddof=0) — 全変数を平均0・分散1に標準化。原論文と同じ処理で、これにより回帰係数の絶対値の大小で関係の強さを直接比較できるようになります。
💡 Python TIPS DataFrame同士の演算は列ごとに一括適用されます。26列の標準化も1行で書けます。

主要な分析結果

4.1 重回帰分析 — 残差プロットによる外れ値の確認(図1)

原論文はまず全29変数の重回帰モデルを推定し、残差プロット(原論文 図1)で外れ値と考えられる6箇所を確認してデータから除外した。比較の公平のため、以降のすべての手法で同じデータを用いている。本ページの図1は SSDSE-A-2025(25変数)による実データ部分再現で、|スチューデント化残差|>4 を基準にしたところ同じく6件が外れ値として検出された。

重回帰(25変数)の残差プロット(SSDSE-A-2025による実データ部分再現)
図1:重回帰の残差プロット。SSDSE-A-2025・25変数による実データ部分再現(原論文 図1 は SSDSE-2019A・29変数)。赤い円は外れ値として除外した6市区町村(西目屋村・大鰐町・檜枝岐村・青ヶ島村・川上村・北山村)。原論文も6箇所を除外しているが、同じ市区町村かは原論文に記載がない。
📌 この残差プロットの読み方
このグラフは
横軸にモデルの予測値、縦軸に残差(実際の値 − 予測値)を取り、各市区町村を点で描いたグラフ。
読み方
残差が0の水平線のまわりに均等に散らばっていればモデルの当てはまりに大きな問題はない。下に大きく外れた点は「モデルの予測よりも外国人人口がはるかに少ない」市区町村。
なぜそう解釈できるか
外れ値は少数でも回帰係数の推定を大きく歪めることがある。除外の判断とその理由を示すのが分析の透明性につながる。
やってみよう重回帰(全変数)と残差プロット → 図1
📝 コード
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# ===== ステップ2: 重回帰(全変数)と残差プロット → 図1 =====
X_full = sm.add_constant(Z[X_cols])
ols_full = sm.OLS(Z['外国人人口'], X_full).fit()
stud = ols_full.get_influence().resid_studentized_external
out_mask = np.abs(stud) > 4      # 外れ値: スチューデント化残差 |t|>4
print('\n=== 残差プロットによる外れ値の確認(原論文 4.1節の手順) ===')
print(f"外れ値と判定: {out_mask.sum()}市区町村(|スチューデント化残差|>4)")
print(df.loc[out_mask, ['都道府県', '市区町村']].to_string(index=False))
print('  ※ 原論文はSSDSE-2019Aの残差プロットで6箇所を外れ値として除外')

fig1, ax1 = plt.subplots(figsize=(8, 6))
ax1.scatter(ols_full.fittedvalues, ols_full.resid, s=12, alpha=0.5,
            color='#3F51B5', label='市区町村')
ax1.scatter(ols_full.fittedvalues[out_mask], ols_full.resid[out_mask],
            s=140, facecolors='none', edgecolors='#C62828', linewidths=1.8,
            label=f'外れ値として除外({out_mask.sum()}件)')
ax1.axhline(0, color='gray', linewidth=1)
ax1.set_xlabel('予測値(標準化後)')
ax1.set_ylabel('残差')
ax1.set_title('図1: 重回帰(25変数)の残差プロット\n'
              '【SSDSE-A-2025 による実データ部分再現。原論文 図1 は'
              'SSDSE-2019A・29変数】', fontsize=11)
ax1.legend()
fig1.tight_layout()
fig1.savefig(os.path.join(FIG_DIR, '2019_U5_2_fig1.png'), bbox_inches='tight')
plt.close(fig1)
print('図1 保存完了(実データ部分再現)')

# 外れ値を除いて以降の分析に使う(原論文と同じく全手法で共通のデータ)
dfc = df.loc[~out_mask].reset_index(drop=True)
Zc = Z.loc[~out_mask].reset_index(drop=True)
y = Zc['外国人人口']
X = Zc[X_cols]
▼ 実行結果
=== 残差プロットによる外れ値の確認(原論文 4.1節の手順) ===
外れ値と判定: 6市区町村(|スチューデント化残差|>4)
都道府県 市区町村
 青森県 西目屋村
 青森県  大鰐町
 福島県 檜枝岐村
 東京都 青ヶ島村
 長野県  川上村
和歌山県  北山村
  ※ 原論文はSSDSE-2019Aの残差プロットで6箇所を外れ値として除外
図1 保存完了(実データ部分再現)
💡 解説
  • sm.OLS(y, X).fit() — 最小二乗法による重回帰。sm.add_constant で切片を追加します。
  • get_influence().resid_studentized_external — スチューデント化残差。原論文は残差プロットを目視して6箇所を外れ値として除外しました。本再現では |スチューデント化残差|>4 を基準にしたところ、偶然にも同じ6件が検出されました(ただし原論文と同じ市区町村とは限りません)。
  • 外れ値を除いたデータを、原論文と同じく以降の全手法で共通に使います(比較の公平性のため)。
💡 Python TIPS df.loc[~out_mask]~ はブール値の反転。「外れ値ではない行」だけを残します。

4.1 重回帰分析 — 推定結果

外れ値除去後のデータで重回帰モデルを推定した結果(原論文 表2)では、さまざまな分野の項目の係数が有意に推定された。全変数が標準化されているため、係数の絶対値の大小で目的変数との関係の強さを比較できる

重回帰分析の主要な推定結果(原論文 表2 の報告値)
変数 回帰係数 P値 解釈
人口密度+0.3752.44E-16絶対値が最大。都市的な地域ほど外国人人口が多い
従業者割合(製造業)+0.2872.69E-09製造業が盛んな地域で外国人人口が多い
課税対象所得+0.2367.95E-12所得水準の高い地域で多い(SSDSE-A-2025未収録)
未婚者割合+0.1967.82E-11未婚者の多い都市的地域で多い(同上)
単独世帯割合+0.1571.93E-09単身世帯が多い地域で多い
農家数+0.1416.04E-06販売農家が多い地域でも多い(農業分野の労働)
従業者割合(宿泊業、飲食サービス業)+0.1388.76E-06宿泊・飲食業の集積地で多い
従業者割合(農業、林業)+0.1211.18E-06農林業比率の高い地域で多い
完全失業率−0.1232.76E-08失業率が低い(=働き手が不足する)地域で外国人人口が多い
自然人口増減率−0.1051.01E-04自然減の進む地域で外国人人口が多い
核家族世帯割合−0.0837.63E-04核家族中心の住宅地的な地域では少ない
図書館数+0.0440.009文化施設の多い地域で多い(正で有意)

値はいずれも原論文 表2 の報告値(標準化データでの回帰係数)。このほか刑法犯認知件数(+0.059)・歳出における教育費割合(+0.047)・従業者割合(情報通信業)(−0.047)・従業者割合(医療、福祉)(−0.067)なども5%水準で有意。総人口・社会的人口増減率・経常収支比率・医師数・学歴割合(大卒)などは非有意だった。

図2:重回帰分析(29変数)の推定係数の全体像

重回帰分析(29変数)の推定係数(原論文 表2 の報告値の可視化)
図2:重回帰分析(29変数)の推定係数。原論文 表2 の報告値の可視化であり、再計算ではない。赤=正で有意(P<0.05)、青=負で有意、灰=非有意。※印の4変数は SSDSE-A-2025 未収録の e-Stat 追加変数。なお「従業者割合(卸売業、小売業)」の行は、原論文 表2 では行ラベルが「宿泊、飲食サービス」と表記されているが、表1・表3 の変数順との対応から卸売業、小売業の誤記とみられる(値は表2のまま)。
📌 この係数プロットの読み方
このグラフは
重回帰分析の各説明変数係数(関係の強さと向き)を横棒で表したグラフ。
読み方
右(プラス方向)に伸びる棒は「その特性が大きい市区町村ほど外国人人口も多い」正の関係。左(マイナス方向)は逆。
なぜそう解釈できるか
全変数が標準化されているので、棒の長さ=関係の強さとして直接比較できる。色付き(赤・青)が統計的に有意(P<0.05)な変数。
やってみよう重回帰の推定結果(実データ部分再現)
📝 コード
129
130
131
132
133
134
135
136
137
# ===== ステップ3: 重回帰の推定(実データ部分再現) =====
ols = sm.OLS(y, sm.add_constant(X)).fit()
coef = pd.DataFrame({'係数': ols.params, 'P値': ols.pvalues}).drop('const')
coef_sorted = coef.reindex(coef['係数'].abs().sort_values(ascending=False).index)
print('\n=== 重回帰の推定結果(実データ部分再現・係数の絶対値順) ===')
print(coef_sorted.round(4).to_string())
print(f"決定係数 R2 = {ols.rsquared:.4f} / N = {len(y)}")
print('  ※ 原論文(29変数)の報告値では 人口密度 0.375 が最大で、')
print('    製造業 0.287・課税対象所得 0.236・未婚者割合 0.196 が続く')
▼ 実行結果
=== 重回帰の推定結果(実データ部分再現・係数の絶対値順) ===
                      係数      P値
人口密度              0.3763  0.0000
従業者割合(製造業)        0.2661  0.0000
単独世帯割合            0.2363  0.0000
従業者割合(農業林業)       0.2046  0.0000
総人口               0.1757  0.0000
従業者割合(医療福祉)      -0.1218  0.0011
従業者割合(建設業)       -0.1181  0.0005
自然人口増減率           0.1172  0.0000
核家族世帯割合          -0.0911  0.0012
従業者割合(宿泊飲食サービス業)  0.0865  0.0193
従業者割合(運輸郵便業)      0.0809  0.0007
経常収支比率           -0.0794  0.0001
従業者割合(卸売小売業)     -0.0737  0.0161
農家数               0.0532  0.0771
完全失業率            -0.0490  0.0124
従業者割合(学術研究専門技術)  -0.0367  0.0859
図書館数              0.0337  0.0578
社会的人口増減率         -0.0335  0.1128
従業者割合(情報通信業)     -0.0236  0.3190
医師数              -0.0163  0.4601
従業者割合(教育学習支援業)   -0.0124  0.5845
教育費割合             0.0122  0.5098
保育所等数             0.0115  0.5325
従業者割合(サービス業他)    -0.0076  0.7579
土木費割合            -0.0064  0.7232
決定係数 R2 = 0.4218 / N = 1734
  ※ 原論文(29変数)の報告値では 人口密度 0.375 が最大で、
    製造業 0.287・課税対象所得 0.236・未婚者割合 0.196 が続く
💡 解説
  • 係数の絶対値順に並べています。標準化済みなので絶対値が大きいほど外国人人口との関係が強いと読めます。
  • 人口密度(0.376)と従業者割合(製造業)(0.266)が上位で、原論文の報告値(人口密度 0.375057・製造業 0.287207)と符号・大きさともよく一致しています。
  • 一方、自然人口増減率は本再現では正(+0.117)で、原論文の報告値(−0.10529)と符号が逆です。使用年次(2015年→2020年国勢調査)と変数構成(29→25変数)の違いによるもので、結果を比べることそのものが学びになります。
💡 Python TIPS coef.reindex(coef['係数'].abs().sort_values(ascending=False).index) — 「絶対値でソートした順番」を reindex で適用する小技。
やってみよう図2:原論文 表2 の報告値の可視化(再計算ではない)
📝 コード
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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
# ===== ステップ4: 図2 原論文 表2 の報告値の可視化(再計算ではない) =====
# 原論文 表2「重回帰分析の推定結果」の29変数の係数とP値。
# ※印は SSDSE-A-2025 未収録(e-Stat追加)の4変数。
# 「従業者割合(卸売業、小売業)」は原論文表2では行ラベルが
# 「宿泊、飲食サービス」と表記されているが、表1・表3の変数順との
# 対応から卸売業、小売業の誤記とみられる(値はそのまま用いる)。
paper_tab2 = [  # (変数名, 係数, P値)
    ('人口密度', 0.375057, 2.44e-16),
    ('従業者割合(製造業)', 0.287207, 2.69e-09),
    ('課税対象所得※', 0.236293, 7.95e-12),
    ('未婚者割合※', 0.196142, 7.82e-11),
    ('単独世帯割合', 0.156925, 1.93e-09),
    ('農家数', 0.141056, 6.04e-06),
    ('従業者割合(宿泊業、飲食サービス業)', 0.137586, 8.76e-06),
    ('完全失業率', -0.123417, 2.76e-08),
    ('従業者割合(農業、林業)', 0.120916, 1.18e-06),
    ('自然人口増減率', -0.10529, 0.000101),
    ('核家族世帯割合', -0.08347, 0.000763),
    ('従業者割合(医療、福祉)', -0.067113, 0.034773),
    ('刑法犯認知件数※', 0.059249, 0.008059),
    ('総人口', 0.050128, 0.101313),
    ('歳出における教育費割合', 0.047338, 0.007494),
    ('従業者割合(情報通信業)', -0.047043, 0.036935),
    ('図書館数', 0.043784, 0.009019),
    ('従業者割合(運輸業、郵便業)', 0.04116, 0.053491),
    ('従業者割合(建設業)', -0.038802, 0.178217),
    ('従業者割合(教育、学習支援業)', -0.038387, 0.08657),
    ('経常収支比率', -0.032771, 0.103782),
    ('社会的人口増減率', -0.03223, 0.105888),
    ('学歴割合(大卒)※', -0.026888, 0.497624),
    ('保育所等数', 0.025764, 0.150709),
    ('従業者割合(サービス業他)', -0.011944, 0.573534),
    ('従業者割合(卸売業、小売業)', 0.010875, 0.696603),
    ('従業者割合(学術研究、専門・技術)', -0.005469, 0.78124),
    ('医師数', 0.005705, 0.792476),
    ('歳出における土木費割合', 0.002082, 0.902164),
]
labels = [t[0] for t in paper_tab2][::-1]
betas = [t[1] for t in paper_tab2][::-1]
pvals = [t[2] for t in paper_tab2][::-1]
colors = ['#C62828' if (p < 0.05 and b > 0) else
          '#1565C0' if (p < 0.05 and b < 0) else '#B0BEC5'
          for b, p in zip(betas, pvals)]
fig2, ax2 = plt.subplots(figsize=(9, 10))
ax2.barh(range(len(labels)), betas, color=colors)
ax2.set_yticks(range(len(labels)))
ax2.set_yticklabels(labels, fontsize=9)
ax2.axvline(0, color='gray', linewidth=1)
ax2.set_xlabel('標準化データでの回帰係数(原論文 表2 の報告値)')
ax2.set_title('図2: 重回帰分析(29変数)の推定係数\n'
              '【原論文 表2 の報告値の可視化(再計算ではない)。'
              '赤=正で有意・青=負で有意(P<0.05)・灰=非有意】\n'
              '※印は SSDSE-A-2025 未収録の e-Stat 追加変数', fontsize=11)
fig2.tight_layout()
fig2.savefig(os.path.join(FIG_DIR, '2019_U5_2_fig2.png'), bbox_inches='tight')
plt.close(fig2)
print('\n図2 保存完了(原論文 表2 の報告値の可視化)')
▼ 実行結果
図2 保存完了(原論文 表2 の報告値の可視化)
💡 解説
  • paper_tab2 のリストは原論文 表2 に記載された29変数の係数とP値をそのまま転記したもの。本スクリプトで計算した値ではありません。
  • ※印の4変数(課税対象所得・未婚者割合・刑法犯認知件数・学歴割合(大卒))は SSDSE-A-2025 未収録で、実データ再現には含められない変数です。
  • 赤=正で有意(P<0.05)、青=負で有意、灰=非有意。有意な正の係数の上位は 人口密度・製造業・課税対象所得・未婚者割合、負の側は 完全失業率・自然人口増減率・核家族世帯割合 など。
💡 Python TIPS タプルのリスト [(名前, 係数, P値), ...] は、小さな表データをコード内に埋め込むときの定番の書き方です。

4.2 Best Subset Selection(Cp基準の変数選択)

説明変数が29と多いため、そのすべてが外国人人口と関係するとは限らず、パラメータが多すぎると過適合を招く。原論文は Best Subset Selection により Cp基準(AICに基づく変数選択と同様の結果になることが知られる)で、目的変数をよく説明する変数の部分集合を選んだ。

変数選択の結果(原論文 4.2節・表3の報告)
  • Cpが最小となる23変数のモデルが最良と判定された
  • 除外されたのは 歳出における土木費割合・医師数・学歴割合(大卒)・従業者割合(卸売業、小売業/学術研究、専門・技術サービス/サービス業(他に分類されないもの)) の6変数
  • 最良モデルの係数(原論文 表3)は重回帰分析と似た結果:人口密度 +0.366(P<2E-16)、製造業 +0.286(P<2E-16)、課税対象所得 +0.222、未婚者割合 +0.192、完全失業率 −0.120 など
⚠ Cpプロット(原論文 図2)について 横軸に説明変数、縦軸に Cp を取り、選択された変数を黒く塗った変数選択の図は、全部分集合の探索(229通り)を行う R の leaps に固有の出力であり、本ページでは再現していない。グラフは原論文(図2)を参照
やってみようBest Subset Selection(原論文 4.2節の結果の要約)
📝 コード
197
198
199
200
201
202
# ===== ステップ5: Best Subset Selection の結果(原論文の報告) =====
print('\n=== Best Subset Selection(原論文 4.2節の報告) ===')
print('  原論文はRのleapsで全29変数からCp基準の変数選択を行い、')
print('  23変数のモデルが最良(Cp最小)。除外されたのは 歳出の土木費割合・')
print('  医師数・大卒者割合・従業者割合(卸売、学術研究、サービス) の6つ。')
print('  Cpプロット(原論文 図2)は本スクリプトでは再現しない(原論文参照)')
▼ 実行結果
=== Best Subset Selection(原論文 4.2節の報告) ===
  原論文はRのleapsで全29変数からCp基準の変数選択を行い、
  23変数のモデルが最良(Cp最小)。除外されたのは 歳出の土木費割合・
  医師数・大卒者割合・従業者割合(卸売、学術研究、サービス) の6つ。
  Cpプロット(原論文 図2)は本スクリプトでは再現しない(原論文参照)
💡 解説
  • 原論文は R の leaps で全29変数から Cp 基準の変数選択を行い、23変数のモデルが最良となりました。
  • 除外されたのは 歳出の土木費割合・医師数・大卒者割合・従業者割合(卸売、学術研究、サービス)の6変数 — いずれも重回帰で非有意だった変数です。
  • 全部分集合の探索(229≒5.4億通り)は分枝限定法を実装した専用ライブラリが必要なため、本再現では実行せず、Cpプロット(原論文 図2)は原論文を参照してください。
💡 Python TIPS Pythonで変数選択をするなら sklearn.feature_selection.SequentialFeatureSelector(逐次選択)が手軽な代替になります。

4.3 決定木分析(図3)

重回帰は目的変数と説明変数の線形関係を仮定する。原論文はこの仮定を置かない機械学習手法として、データを段階的に分割する木構造に基づく決定木回帰を追加した。図の上にある変数ほど早い段階で分割に使われ、重要度が高い。

原論文の決定木(原論文 図3・4.3節の報告)
  • 最初に課税対象所得で分割され、次に大卒割合・未婚割合で分割が進む
  • ほかに使われた変数:従業者割合(製造業、医療・福祉)、農家数、完全失業率、核家族世帯割合
  • 外国人人口が最も多いのは「所得がおよそ平均以上 × 未婚割合が高い × 農家数がかなり低い」グループ
  • 最も少ないのは「所得が平均以下 × 大卒割合が低い × 製造業割合も低い」ケース
決定木回帰(25変数)の推定された木(SSDSE-A-2025による実データ部分再現)
図3:決定木回帰で推定された木(葉9個)。SSDSE-A-2025・25変数による実データ部分再現。原論文の木で上位に来る課税対象所得・大卒割合・未婚割合は SSDSE-A-2025 未収録のため、本再現の木構造は原論文 図3 とは一致しない(原論文の木は原論文を参照)。本再現では従業者割合(建設業)・単独世帯割合・自然人口増減率・製造業・医療福祉などで分割された。
📌 この決定木の読み方
このグラフは
データを「はい/いいえ」の条件で順に分割し、似た市区町村のグループを作る木構造の図。
読み方
上のノードほど重要な分割条件。各ノードの value がそのグループの外国人人口(標準化値)の平均、samples が市区町村数。色が濃いほど外国人人口が多いグループ。
なぜそう解釈できるか
決定木は変数間の非線形な関係や組み合わせ効果を捉えられる。「所得が高くても農家数が多いと少ない」のような条件つきの関係が読み取れるのが回帰との違い。
やってみよう決定木回帰 → 図3(実データ部分再現)
📝 コード
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# ===== ステップ6: 決定木回帰 → 図3(実データ部分再現) =====
tree = DecisionTreeRegressor(max_leaf_nodes=9, random_state=0).fit(X, y)
fig3, ax3 = plt.subplots(figsize=(13, 7))
plot_tree(tree, feature_names=X_cols, filled=True, rounded=True,
          fontsize=8, impurity=False, ax=ax3)
ax3.set_title('図3: 決定木回帰(25変数・葉9個)\n'
              '【SSDSE-A-2025 による実データ部分再現。原論文 図3 の木'
              '(最初の分割は課税対象所得)とは変数構成が異なる】',
              fontsize=11)
fig3.tight_layout()
fig3.savefig(os.path.join(FIG_DIR, '2019_U5_2_fig3.png'), bbox_inches='tight')
plt.close(fig3)
used = [X_cols[i] for i in sorted(set(tree.tree_.feature)) if i >= 0]
print('\n=== 決定木回帰(実データ部分再現) ===')
print(f"分割に使われた変数: {'、'.join(used)}")
print('  ※ 原論文の木は 課税対象所得 → 大卒割合・未婚割合 の順に分割し、')
print('    ほかに製造業・医療福祉・農家数・完全失業率・核家族世帯割合を使用。')
print('    課税対象所得・大卒割合・未婚割合は SSDSE-A-2025 未収録')
print('図3 保存完了(実データ部分再現)')
▼ 実行結果
=== 決定木回帰(実データ部分再現) ===
分割に使われた変数: 自然人口増減率、単独世帯割合、従業者割合(建設業)、従業者割合(製造業)、従業者割合(教育学習支援業)、従業者割合(医療福祉)
  ※ 原論文の木は 課税対象所得 → 大卒割合・未婚割合 の順に分割し、
    ほかに製造業・医療福祉・農家数・完全失業率・核家族世帯割合を使用。
    課税対象所得・大卒割合・未婚割合は SSDSE-A-2025 未収録
図3 保存完了(実データ部分再現)
💡 解説
  • DecisionTreeRegressor(max_leaf_nodes=9) — 葉の数を原論文の木(葉9個程度)に合わせています。原論文は R の tree パッケージを使用。
  • plot_tree(..., filled=True) — 色が濃いノードほど予測値(外国人人口)が高いグループ。
  • 原論文の木は課税対象所得で最初に分割され、大卒割合・未婚割合が続きますが、この3変数は SSDSE-A-2025 に未収録。本再現の木は従業者割合(建設業)から分割が始まり、構造が異なります。原論文の木構造そのものは原論文 図3 を参照
💡 Python TIPS tree.tree_.feature には各ノードの分割に使った変数の番号が入っています(葉は−2)。set で重複を除いて「使われた変数」を一覧できます。

4.4 ランダムフォレスト(図4)

ランダムフォレストは複数の木の平均で予測を改善する。決定木の長所であるモデルの説明力(構造の見やすさ)は失われるが、変数をモデルから外した場合に予測がどれだけ悪化するかに基づいて各説明変数の重要度を計算できる。

原論文の変数重要度(原論文 図4・4.4節の報告)
  • 課税対象所得の重要度が最も高い
  • 未婚割合、従業者割合(製造業、医療・福祉)、犯罪認知件数、核家族割合、完全失業率、大卒割合、人口密度なども比較的高い
  • 重回帰では選択されなかった大卒割合が木に基づく手法では重要と認識された → 大卒割合と外国人人口の間に非線形な関係が存在する可能性(原論文の解釈)
ランダムフォレストの変数重要度(SSDSE-A-2025による実データ部分再現)
図4:ランダムフォレストによる各説明変数の重要度。SSDSE-A-2025・25変数による実データ部分再現(不純度減少に基づく重要度)。原論文 図4 は R の RandomForest・29変数によるもので、課税対象所得が最重要(原論文の図は原論文を参照)。本再現でも製造業・医療福祉・人口密度・単独世帯割合が上位に入る点は原論文と共通する。
やってみようランダムフォレスト → 図4(実データ部分再現)
📝 コード
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# ===== ステップ7: ランダムフォレスト → 図4(実データ部分再現) =====
rf = RandomForestRegressor(n_estimators=500, random_state=0,
                           n_jobs=-1).fit(X, y)
imp = pd.Series(rf.feature_importances_, index=X_cols).sort_values()
fig4, ax4 = plt.subplots(figsize=(9, 8))
ax4.barh(range(len(imp)), imp.values, color='#2E7D32')
ax4.set_yticks(range(len(imp)))
ax4.set_yticklabels(imp.index, fontsize=9)
ax4.set_xlabel('変数重要度(不純度減少に基づく)')
ax4.set_title('図4: ランダムフォレストの変数重要度(25変数)\n'
              '【SSDSE-A-2025 による実データ部分再現。原論文 図4 は'
              'R の RandomForest・29変数で、課税対象所得が最重要】',
              fontsize=11)
fig4.tight_layout()
fig4.savefig(os.path.join(FIG_DIR, '2019_U5_2_fig4.png'), bbox_inches='tight')
plt.close(fig4)
print('\n=== ランダムフォレストの変数重要度(実データ部分再現・上位8) ===')
print(imp.sort_values(ascending=False).head(8).round(4).to_string())
print('  ※ 原論文(29変数)では 課税対象所得 が最重要、未婚割合、')
print('    従業者割合(製造業、医療・福祉)、犯罪認知件数などが続く')
print('図4 保存完了(実データ部分再現)')
▼ 実行結果
=== ランダムフォレストの変数重要度(実データ部分再現・上位8) ===
従業者割合(建設業)      0.1944
従業者割合(医療福祉)     0.0960
単独世帯割合          0.0626
人口密度            0.0561
従業者割合(製造業)      0.0529
自然人口増減率         0.0515
農家数             0.0356
従業者割合(卸売小売業)    0.0353
  ※ 原論文(29変数)では 課税対象所得 が最重要、未婚割合、
    従業者割合(製造業、医療・福祉)、犯罪認知件数などが続く
図4 保存完了(実データ部分再現)
💡 解説
  • RandomForestRegressor(n_estimators=500) — 500本の木の平均で予測。原論文は R の RandomForest ライブラリを使用しています。
  • feature_importances_ は「その変数での分割が不純度(分散)をどれだけ減らしたか」に基づく重要度。原論文の図4(Rの重要度)とは定義が完全には一致しない点に注意。
  • 本再現では 従業者割合(建設業)・従業者割合(医療福祉)・単独世帯割合・人口密度・製造業 が上位。原論文では課税対象所得が最重要で、未婚割合・製造業・医療福祉・犯罪認知件数が続きました(両者とも製造業・医療福祉が上位に入る点は共通)。
💡 Python TIPS n_jobs=-1 で全CPUコアを使って並列学習。500本の木でも数秒で終わります。

4.5 10-fold クロスバリデーションによる手法比較

最後に原論文は10-fold クロスバリデーションで4手法の妥当性を比較した。

平均二乗誤差の平均値(原論文 表4 の報告値)
手法重回帰分析Best Subset Selection決定木分析ランダムフォレスト
原論文 表4(29変数・R) 0.4686977 0.4641824 0.527091 0.4305073
本再現(25変数・Python) 0.5125672 —(未実施) 0.6266032 0.4904763

どちらでもランダムフォレストが最小=最も妥当、決定木が最大。原論文は「決定木は使用する説明変数が少なくデータの構造を捉えるには不十分な可能性がある。Best Subset Selection は変数選択の分だけ重回帰より予測が少し改善。ランダムフォレストと Best Subset Selection の差はそれほど大きくなく、線形回帰モデルでもデータの関係性をある程度うまく捉えられている」と解釈している。

全手法を通した解釈(原論文 4.5節) すべての手法で重要度が高い変数は従業者割合(製造業)・課税対象所得・未婚者割合・農家数・完全失業率など。人口密度は決定木では選ばれなかったが、線形モデルで最重要かつ決定木のCV成績が悪いことを踏まえると重要度が高いと考えられる。まとめると、都市化(人口密度・課税対象所得・未婚者割合)、働き手不足(完全失業率)、特定産業(農業・製造業)が外国人人口と比較的強い結びつきを持つと解釈できる。
やってみよう10-fold クロスバリデーションで4手法を比較
📝 コード
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# ===== ステップ8: 10-fold クロスバリデーションで手法を比較 =====
cv = KFold(n_splits=10, shuffle=True, random_state=1)
models = {'重回帰分析': LinearRegression(),
          '決定木分析': DecisionTreeRegressor(max_leaf_nodes=9,
                                              random_state=0),
          'ランダムフォレスト': RandomForestRegressor(
              n_estimators=500, random_state=0, n_jobs=-1)}
print('\n=== 10-fold クロスバリデーション: 平均二乗誤差の平均値 ===')
print('【SSDSE-A-2025・25変数による実データ部分再現】')
for name, model in models.items():
    mse = -cross_val_score(model, X, y, cv=cv,
                           scoring='neg_mean_squared_error').mean()
    print(f"  {name:<12s}: {mse:.7f}")
print('【原論文 表4 の報告値(SSDSE-2019A・29変数、R による)】')
print('  重回帰分析: 0.4686977 / Best Subset Selection: 0.4641824')
print('  決定木分析: 0.527091  / ランダムフォレスト: 0.4305073')
print('  → 原論文でも本再現でもランダムフォレストが最小(=最も妥当)。')
print('    Best Subset Selection は本再現では実行していない(原論文参照)')
▼ 実行結果
=== 10-fold クロスバリデーション: 平均二乗誤差の平均値 ===
【SSDSE-A-2025・25変数による実データ部分再現】
  重回帰分析       : 0.5125672
  決定木分析       : 0.6266032
  ランダムフォレスト   : 0.4904763
【原論文 表4 の報告値(SSDSE-2019A・29変数、R による)】
  重回帰分析: 0.4686977 / Best Subset Selection: 0.4641824
  決定木分析: 0.527091  / ランダムフォレスト: 0.4305073
  → 原論文でも本再現でもランダムフォレストが最小(=最も妥当)。
    Best Subset Selection は本再現では実行していない(原論文参照)
💡 解説
  • KFold(n_splits=10, shuffle=True) — データを10分割し、9割で学習・1割で検証を10回繰り返して平均二乗誤差(MSE)を平均します。
  • 実データ部分再現でも原論文の報告値でも、ランダムフォレストが最小=最も予測が妥当、決定木が最大という順位は同じでした。
  • 原論文は「ランダムフォレストと Best Subset Selection の差はそれほど大きくなく、線形回帰モデルでもデータの関係性をある程度うまく捉えられている」と解釈しています。
💡 Python TIPS cross_val_score は「大きいほど良い」スコアを返す設計なので、誤差系は neg_mean_squared_error(負のMSE)を指定し、符号を反転して使います。

統計的手法の解説

1
重回帰分析標準化係数

個々の特性と外国人人口の相関係数を1つずつ計算する方法では、説明変数同士の相関を無視することになる。重回帰分析はすべての特性の関係を同時に推定することでこの問題に対処する。

外国人人口ᵢ = β₀ + β₁x₁ᵢ + β₂x₂ᵢ + … + β₂₉x₂₉ᵢ + εᵢ

原論文は分析前に全変数を平均0・分散1に標準化しているため、推定された係数は標準化係数に相当し、単位の異なる変数どうしでも絶対値の大小で関係の強さを比較できる

DS LEARNING POINT 1

標準化してから回帰する意味

人口密度(人/ha)と完全失業率(%)の係数は、そのままでは単位が違って比べられない。標準化後の係数は「その変数が1標準偏差増えると目的変数が何標準偏差変わるか」を表し、横並びの比較が可能になる。

Z = (df - df.mean()) / df.std(ddof=0) # 平均0・分散1に model = sm.OLS(Z['外国人人口'], sm.add_constant(Z[X_cols])).fit() # 係数の絶対値順に並べる = 関係の強さランキング coef = model.params.drop('const') print(coef.reindex(coef.abs() .sort_values(ascending=False).index))
2
Best Subset Selection と Cp基準

説明変数のすべての組み合わせ(229通り)についてモデルを評価し、最良の部分集合を選ぶ方法。評価には Mallows の Cp を使う。変数を増やすと当てはまり(RSS)は必ず良くなるが、Cp変数の数 p にペナルティを課すことで過適合を防ぐ。

Cp = RSSp / σ̂² − n + 2(p + 1) (小さいほど良いモデル)

Cp基準による選択はAICに基づく変数選択と同様の結果になることが知られている(原論文 4.2節)。原論文では29変数中23変数のモデルが最良となった。

3
決定木回帰とランダムフォレスト

決定木回帰は「変数xがc以上か未満か」でデータを再帰的に分割し、各グループ(葉)の平均値で予測する。線形性を仮定しないため、非線形な関係や変数の組み合わせ効果を捉えられる。ランダムフォレストは、ブートストラップ標本と変数のランダムな部分集合で育てた多数の木の予測を平均することで、単一の木より予測を安定させる。

DS LEARNING POINT 2

線形モデルと木、それぞれの得意技

原論文の面白い発見:大卒割合は重回帰・変数選択では選ばれない(非有意)のに、決定木・ランダムフォレストでは重要変数と認識された。原論文はここから「大卒割合と外国人人口の間には非線形な関係が存在するのかもしれない」と考察している。手法によって見えるものが違う——だから複数の手法で見るのが探索的データ分析の鉄則。

tree = DecisionTreeRegressor(max_leaf_nodes=9).fit(X, y) rf = RandomForestRegressor(n_estimators=500, n_jobs=-1).fit(X, y) # 重要度 = その変数を使った分割が # 予測誤差をどれだけ減らしたか pd.Series(rf.feature_importances_, index=X_cols)\ .sort_values(ascending=False).head(8)
4
10-fold クロスバリデーション

データを10個のブロックに分け、9ブロックで学習・残り1ブロックで検証を10回繰り返し、平均二乗誤差(MSE)の平均で手法を比較する。学習に使っていないデータで測ることで、過適合したモデルを不当に高評価することを避けられる。

DS LEARNING POINT 3

「当てはまりの良さ」と「予測の良さ」は別物

29変数の重回帰はR²(当てはまり)では複雑なモデルほど有利。しかしCVで測る「未知データへの予測力」では、変数選択したモデル(Best Subset)が全変数モデルを上回った——これが過適合の実例。原論文の表4はこの教科書的な現象を実データで示している。

cv = KFold(n_splits=10, shuffle=True, random_state=1) mse = -cross_val_score(model, X, y, cv=cv, scoring='neg_mean_squared_error').mean() # モデルを差し替えて mse を比較するだけで # 「どの手法が最も妥当か」を公平に測れる

発展的学習

市区町村データ×多変数分析の注意点

課題内容対処・考え方
過適合 説明変数が30近くあると、データへの当てはまり過ぎで汎化性能が落ちる Best Subset Selection・AIC/Cp基準、交差検証での評価(原論文の設計そのもの)
因果ではなく相関 「製造業割合が高い→外国人が増える」とは限らない(逆・共通要因もあり得る) 傾向スコアなど因果推論の手法(原論文 5節が指摘)
欠落変数 大学の有無・家賃水準など、外国人人口と関係が深そうな変数が含まれていない 変数を追加した場合、大卒割合や犯罪認知件数の係数が変化する可能性に留意(原論文 5節)
一時点データ 社会構造は時間と共に変化するが、分析は一時点の断面のみ 複数時点のデータセットで時間構造を明示的に取り込む(原論文 5節)
統計間の乖離 国勢調査の外国人数は在留外国人統計の78.5%(2015年)に留まる 使用統計の定義・捕捉率の違いを明記して解釈する(原論文 5節)
生態学的誤謬 市区町村集計の知見を個人(個々の外国人の行動)に一般化する危険 分析単位を明記し、個人レベルの推論は避ける

DS LEARNING POINT 4

探索的分析(EDA)としての価値

原論文は仮説検証型ではなく探索型の設計:多数の変数×複数の手法で「どの特性が効いていそうか」の地図を描き、都市化・働き手不足・特定産業という3つの解釈仮説に絞り込んだ。審査会コメントも「機械学習による政策分析の可能性を示す論文」と評価している。次の段階は、この仮説を因果推論の設計(傾向スコア・パネルデータなど)で検証すること。

# 探索 → 仮説 → 検証 のサイクル # 1. 重回帰・RF重要度で候補変数を洗い出す(本論文) # 2. 社会学・人口学の理論と突き合わせる # 3. 因果推論デザインで政策効果を検証する

本再現と原論文の結果の違いから学ぶ

同じ設計・違うデータで何が変わったか
  • 頑健だった結果:人口密度と製造業従業者割合が最上位(符号・大きさともほぼ一致)。ランダムフォレストがCVで最良という手法間の順位。
  • 変わった結果:自然人口増減率の符号(原論文 −0.105 → 本再現 +0.117)。2015年→2020年の5年間の変化(コロナ禍を含む)と、未婚者割合・課税対象所得など4変数の欠落が影響した可能性がある。
  • 再現で結果が変わること自体が発見であり、「どの結論が時点や変数構成に対して頑健か」を知る手がかりになる。

まとめ

原論文の結論

  1. 都市化・働き手不足・特定産業が外国人人口と強く結びつく: 重回帰・変数選択・決定木・ランダムフォレストのすべてで、都市化(人口密度・課税対象所得・未婚者割合)、働き手不足(完全失業率の低さ)、特定産業(農業・製造業)に関わる変数の重要度が高かった。
  2. 手法の妥当性はランダムフォレストが最良: 10-fold クロスバリデーションの平均二乗誤差はランダムフォレスト(0.4305)< Best Subset Selection(0.4642)< 重回帰(0.4687)< 決定木(0.5271)(いずれも原論文 表4 の報告値)。ただし線形モデルとの差は大きくなく、線形回帰でも関係性をある程度捉えられている。
  3. 政策への含意: これらの特性の変化を注視することで今後の外国人人口の増減傾向を掴める可能性があり、特に増加が予測される市区町村にとって、外国人のための生活環境改善(多言語対応・就学支援など)に取り組むきっかけになり得る。

原論文が挙げる今後の課題(5節)

原論文自身による限界の整理
  • 理論的裏付け:統計的に選ばれた特性が、社会学・人口学の蓄積された研究成果と整合的かは未検証
  • 欠落変数:大学など高等教育・研究機関の有無、家賃水準などが説明変数に含まれていない。追加すれば大卒割合や犯罪認知件数の係数の解釈が変わり得る
  • 相関であって因果ではない:特定の政策(例:教育費割合の変更)の効果を知るには傾向スコアなど因果推論の手法が必要
  • 一時点のデータ:時間的な構造変化は分析できていない。複数時点のデータセットによる分析が今後の課題
  • 統計間の乖離:国勢調査の外国人数は在留外国人統計の78.5%(2015年)で、両統計の外国人数は大きく異なる

本分析の学習ポイント

この分析から学べる統計的思考
  • 標準化してから回帰 → 単位の異なる約30変数の「関係の強さ」を横並びで比較する方法
  • 変数選択(CpAIC) → 「変数は多いほど良い」ではなく、過適合とのトレードオフを基準で裁く
  • 線形モデルと木ベースの手法の両方を使う → 大卒割合のように片方でしか見えない関係がある
  • クロスバリデーション → 「当てはまり」ではなく「未知データへの予測力」で手法を選ぶ
  • 報告値と再現値の区別 → 他人の分析を再現するとき、何が再現でき何ができないかを明示する誠実さ
教育的価値(この分析の面白さ)
  • 身近で今日的なテーマ:外国人住民の増加は多くの読者の生活圏で進行中の変化。統計でその「地図」を描く実例。
  • 1つのデータに4つの手法:重回帰 → 変数選択 → 決定木 → ランダムフォレスト → CV比較、という探索的分析のフルコースを1本で学べる。
  • 約1,700市区町村の大標本:都道府県データ(N=47)ではできない、多変数・機械学習的なアプローチが活きる規模感。

参考文献・データ出典

分析スクリプト(2019_U5_2_shorei.py)

データ出典

データ名収録内容出典機関
SSDSE-2019A(原論文が使用) 市区町村別の社会・人口統計(2015年国勢調査ほか) 独立行政法人統計センター(教育用標準データセット SSDSE
SSDSE-A-2025(本ページの再現が使用) 市区町村別の社会・人口統計(2020年国勢調査ほか、1,741市区町村) 独立行政法人統計センター(教育用標準データセット SSDSE
都道府県・市区町村のすがた(社会・人口統計体系) 原論文が追加した4変数:未婚者割合(2015)・課税対象所得(2017)・学歴割合(大卒)(2010)・刑法犯認知件数(2008) 総務省統計局(e-Stat

参考文献(原論文の参考文献より主要なもの)

  1. 石川義孝・竹下修子・花岡和聖 (2014)「2005-2010年における新規流入移動と国内移動からみた外国人の目的地選択」京都大學文學部研究紀要, 53, 293–318.
  2. 清水昌人 (2017)「市区町村における外国人の社会増加と日本人の社会減少」E-journal GEO, 12(1), 85–100.
  3. 是川夕 (2008)「外国人の居住地選択におけるエスニック・ネットワークの役割」社会学評論, 59(3), 495–513.
  4. 中川雅貴・山内昌和・菅桂太・鎌田健司・小池司朗 (2018)「都道府県別にみた外国人の自然動態」人口問題研究, 74(4), 293–319.
  5. James, G., Witten, D., Hastie, T., & Tibshirani, R. (2017). An Introduction to Statistical Learning: with Applications in R. Springer.(重回帰・変数選択・決定木・ランダムフォレストの標準テキスト)
  6. 前田泰伸 (2019)「都道府県別に見た外国人労働者と経済の関係」経済のプリズム, 177, 11–19.(従業者割合の産業選択の根拠)
  7. 星野嵩宏 (2009)『調査観察データの統計科学 因果推論・選択バイアス・データ融合』岩波書店.(原論文の参考文献表記のまま)
  8. 石川義孝 (2019)『地図で見る日本の外国人 改訂版』ナカニシヤ出版, pp.2–3.(国勢調査と在留外国人統計の乖離=78.5%の出典)
  9. 独立行政法人統計センター「教育用標準データセット(SSDSE)」https://www.nstac.go.jp/use/literacy/ssdse/

本ページの図1・図3・図4と「実行結果」はすべて SSDSE-A-2025 の実データによる部分再現(25変数)です。図2および本文中の「原論文の報告値」(回帰係数・P値・CVの平均二乗誤差・変数選択の結果)は原論文の記載値をそのまま転記したもので、本ページで再計算したものではありません。原論文はRによる29変数の分析であり、本再現の数値は原論文と一致しません。合成データ・架空の数値は一切含みません。

教育用解説ページ | 2019年度 統計データ分析コンペティション 特別賞(大学生・一般の部)「外国人人口と市区町村の特性との関係性」| 実データ部分再現:SSDSE-A-2025 | 29変数モデルの数値は原論文の報告値

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

この論文(と同種の探索的分析)を読むときに陥りやすい誤解を整理します。

❌ 「製造業割合が高いと外国人が増える(因果)」ではない
本論文が示したのは相関関係であり、因果関係の証明ではない。原論文自身が「特定の政策が外国人人口に与える影響を分析するためには傾向スコアなどの因果推論に適切な統計手法を用いる必要がある」と明記している。
❌ 「P値が小さい=実質的に重要な変数」ではない
N≈1,700の大標本では小さな効果でもP値は容易に小さくなる。本論文が係数の絶対値(標準化済み)で関係の強さを比較しているのはこのため。有意性と効果の大きさは別々に読む。
❌ 「変数は多く入れるほど良いモデル」ではない
説明変数を増やすと当てはまり(R²)は必ず改善するが、過適合で未知データへの予測は悪化し得る。原論文はまさにこの理由で Best Subset Selection を行い、CVでは23変数モデルが29変数モデルを上回った
❌ 「変数選択で除外された変数は無関係」ではない
大卒割合は変数選択で除外されたが、決定木・ランダムフォレストでは重要変数だった。線形モデルで選ばれない=関係がない、ではなく非線形な関係の可能性がある(原論文4.4節の考察)。
❌ 「外れ値は機械的に消してよい」ではない
原論文は残差プロットを確認した上で6箇所を除外し、すべての手法で同じデータを使うと明記した。除外の基準・件数・影響を報告することが分析の透明性。黙って消すのは操作と紙一重。
❌ 「CVで最良のランダムフォレストだけ使えばよい」ではない
ランダムフォレストは予測は良いが構造の説明力を失う。原論文は解釈しやすい線形モデル・決定木と、予測が良いRFを組み合わせて結論を導いた。目的(解釈か予測か)で手法の価値は変わる。
❌ 「市区町村の傾向=個人の傾向」ではない
これは生態学的誤謬。「未婚者割合が高い自治体で外国人人口が多い」ことは「未婚者が外国人の近くに住む」ことを意味しない。集計データの知見は集計レベルでのみ解釈する。
❌ 「外国人人口の統計は1つ」ではない
本論文の外国人人口は国勢調査による。在留外国人統計と比べると2015年時点で国勢調査は78.5%しか捕捉していない(原論文5節)。どの統計の「外国人」かで数値は大きく変わる。

📖 用語集(この論文を読むための最小セット)

本文中の枠線付き用語はクリックすると詳しい解説がポップアップします。ここでは特に重要な用語をまとめます。

標準化
変数を平均0・分散1に変換すること。単位の異なる変数の回帰係数を「絶対値の大小=関係の強さ」として比較できるようになる。本論文の分析の大前提。
対数変換
分布が大きく歪んだ非負データを log で変換して歪みを緩和する処理。0を含む変数には+1してから変換(本論文 表1)。
重回帰分析
複数の説明変数で1つの目的変数を同時に説明する手法。説明変数間の相関を考慮できる点が、1対1の相関係数を並べる方法との違い。
Best Subset Selection
説明変数のすべての組み合わせを評価し、Cpなどの基準が最良となる部分集合を選ぶ変数選択法。Rでは leaps パッケージが分枝限定法で効率的に探索する。
Cp基準
Mallows の Cp。当てはまりの良さ(RSS)に変数の数のペナルティを加えたモデル評価指標で、小さいほど良い。AICによる選択とほぼ同等の結果になる。
決定木回帰
「変数xが閾値c以上か」でデータを再帰的に分割し、葉ごとの平均で予測する手法。上位の分割変数ほど重要。非線形関係を捉えられるが単体では予測が不安定。
ランダムフォレスト
ブートストラップ標本×変数のランダム選択で多数の決定木を育て、予測を平均するアンサンブル手法。変数重要度が計算できる。
変数重要度
その変数をモデルから外した(または分割に使った)ときに予測がどれだけ悪化(改善)するかで測る、変数の貢献度。定義は実装によって異なる点に注意。
10-fold クロスバリデーション
データを10分割し「9割で学習・1割で検証」を10回繰り返して予測誤差を平均する評価法。学習に使っていないデータで測るのがポイント。
平均二乗誤差(MSE)
予測誤差の2乗の平均。小さいほど予測が良い。本論文の手法比較の物差し。
外れ値
他の観測から大きく離れた値。回帰係数を歪めるため、本論文は残差プロットで確認した6箇所を除外した。
過適合
手元のデータに合わせ込みすぎて未知データへの予測が悪化すること。変数が多いモデルほど危険。変数選択とCVが対策。

📐 この論文の手法ガイド

本論文で使われた統計・機械学習手法を「何?」「どう使う?」「注意点は?」の順で整理します。注意点は手法ごとに異なります。

🧭 前提となる考え方:P値
何?
「本当は関係がない(係数=0)としたら、観測された結果かそれ以上に極端な結果が偶然得られる確率」。
読み方
P < 0.05 を「統計的に有意」とするのが慣例。ただし大標本では小さな効果も有意になるため、係数の大きさとセットで読む。
📈 重回帰分析(標準化データ)
何?
複数の説明変数が1つの目的変数にどう関係するかを同時に推定する手法。
どう使う?
全変数を標準化してから最小二乗法でフィット。係数の絶対値=関係の強さとして比較する。
何がわかる?
説明変数間の相関を考慮した上で、どの特性が外国人人口と強く結びつくか。
結果の読み方
係数が正なら「その特性が大きい自治体ほど外国人人口が多い」。P<0.05で有意。
⚠️ 注意点
(1) 標準化しないと係数の大小比較は無意味(単位に依存する)。(2) 説明変数同士の強い相関(多重共線性)があると係数が不安定になる——本論文のように産業割合を多数入れる場合は特に注意。(3) 係数は「他の変数を一定とした場合」の関係で、単純相関とは意味が違う。(4) 外れ値の影響が大きいので残差プロットの確認が必須(原論文も実施)。
🎛️ Best Subset Selection(Cp基準の変数選択)
何?
説明変数のすべての組み合わせからCp最小のモデルを選ぶ変数選択法。
どう使う?
Rの leaps などで全部分集合を探索し、Cp(またはAIC・BIC)が最小のモデルを採用する。
何がわかる?
「29変数のうち本当に説明に効く23変数はどれか」を客観基準で決められる。過適合の抑制。
結果の読み方
選ばれた変数の係数は通常の重回帰と同様に読む。除外=無関係ではない点に注意。
⚠️ 注意点
(1) 組み合わせは2変数の数で爆発する——29変数で約5.4億通り。分枝限定法の専用実装が必要で、Pythonでは逐次選択(forward/backward)で近似するのが現実的。(2) 選択後のP値は「選択」の影響で楽観的になる(選択後推論の問題)。(3) データが少し変わると選ばれる変数集合も変わり得る。安定性の確認を。
🌳 決定木回帰
何?
データを「はい/いいえ」の条件で再帰的に分割し、葉ごとの平均値で予測する手法。
どう使う?
Rの tree / sklearn の DecisionTreeRegressor。木の深さや葉の数で複雑さを制御する。
何がわかる?
非線形関係・変数の組み合わせ効果。「所得が高く未婚割合が高く農家が少ない地域で外国人人口が最多」のような条件つきの構造。
結果の読み方
上位ノードの分割変数ほど重要。葉の値がそのグループの予測値。
⚠️ 注意点
(1) 単体の木は不安定——データの少しの違いで構造が大きく変わる(本論文でもCV誤差は4手法中最悪)。(2) 深くしすぎると過適合、浅すぎると構造を捉えられない。葉の数・深さの制御が必須。(3) 連続的な線形関係は階段状にしか近似できず、線形モデルより不利な場面もある。
🌲 ランダムフォレスト
何?
ブートストラップ標本+変数のランダム選択で育てた多数の木の平均で予測するアンサンブル手法。
どう使う?
Rの RandomForest / sklearn の RandomForestRegressor。木の本数は数百本が目安。
何がわかる?
単一の木より安定した予測と、変数重要度による「効いている変数」のランキング。
結果の読み方
重要度が高い変数=それを除くと予測が悪化する変数。符号(正負の向き)は分からない点に注意。
⚠️ 注意点
(1) モデルの内部構造は読めない(説明力とのトレードオフ)。(2) 重要度の定義は実装で異なる(Rの%IncMSE と sklearn の不純度減少は別物)。比較時は定義を明記。(3) 不純度ベースの重要度は水準数の多い変数に偏るバイアスがある。permutation importance での確認が望ましい。
🔁 10-fold クロスバリデーション
何?
データを10分割して学習と検証を繰り返し、未知データへの予測誤差を推定する評価法。
どう使う?
各手法で同じ分割を使いMSEの平均を比較する。sklearn なら cross_val_score。
何がわかる?
「どの手法がこのデータに最も妥当か」を当てはまりではなく予測力で判定できる。
結果の読み方
MSEが小さいほど良い。差が小さい場合は単純で解釈しやすい手法を選ぶのも合理的(原論文の姿勢)。
⚠️ 注意点
(1) 標準化や外れ値除去を「全データで先に」行うと情報漏えい(リーク)になり得る——厳密には各foldの学習データ内で行う。(2) 分割の乱数によって結果が変わるので、乱数シードの固定や繰り返しCVで安定させる。(3) 地理データでは近隣自治体が学習と検証に分かれて誤差を過小評価する可能性(空間的相関)。

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

この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。

① 時間的拡張:一時点の断面から構造変化の分析へ
結果 X
本論文は一時点(2015年国勢調査ベース)の断面データで外国人人口と自治体特性の関係を捉えた。本ページの部分再現(2020年ベース)では自然人口増減率の符号が反転するなど、時点による違いも見えた。
新仮説 Y
特定技能制度(2019年〜)やコロナ禍を挟んで、外国人人口と結びつく自治体特性は変化した——例えば農業・製造業の結びつきが強まった/弱まった。
課題 Z
(1)SSDSE-A の複数年版(2019A と 2025 など)で同じ変数を作り、係数の変化を比較する。(2)パネルデータ化して時間構造を明示的に取り込む(原論文5節が挙げる方向性)。(3)変化が大きい変数について制度変更との対応を考察する。
② 手法の発展:探索的分析から因果推論へ
結果 X
都市化・働き手不足・特定産業が外国人人口と相関することは分かったが、因果の向きは不明。
新仮説 Y
「歳出における教育費割合を上げると外国人世帯の定住が進む」のような政策操作可能な変数の効果は、因果推論のデザインで検証できる(原論文5節が傾向スコアを示唆)。
課題 Z
(1)傾向スコアマッチングで「教育費割合が高い自治体」と特性の似た「低い自治体」を比べる。(2)LASSO・Ridge など正則化回帰で変数選択の頑健性を確認し、Best Subset の結果と比較する。(3)隣接自治体の影響(空間的自己相関)を空間回帰モデルで考慮する。
③ 政策提言・実践への応用
結果 X
特性の変化を注視すれば外国人人口の増加が見込まれる市区町村を先回りして把握できる可能性がある。
新仮説 Y
製造業集積×失業率低下×都市化が同時進行する自治体では、多言語対応・就学支援の需要が数年内に急増する。
課題 Z
(1)本論文のモデルで「今後増加が予測される自治体」リストを作り、実際の生活環境整備の状況(多言語窓口の有無など)と突き合わせる。(2)在留外国人統計(在留資格別)と組み合わせ、必要な支援の種類(労働・留学・家族帯同)まで踏み込む。(3)自治体の多文化共生担当者に提言できる1枚資料にまとめる。

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

学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本ページのスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。

★☆☆☆☆ 入門
CH1. 同じデータで分析を再現する
付属の Python スクリプトをそのまま実行し、図1〜図4を再現してみてください。
ポイント: 実行結果のどこまでが「実データによる計算」で、どこからが「原論文の報告値」かを意識しながら出力を読む。
★★☆☆☆ 初級
CH2. 外れ値の基準を変えて頑健性を確かめる
スクリプトの外れ値基準(|スチューデント化残差|>4)を 3 や 5 に変えて再実行し、除外件数と回帰係数の変化を観察してください。
ポイント: 上位の変数(人口密度・製造業)の係数は基準を変えても安定しているか? 安定していればその結論は頑健。
★★★☆☆ 中級
CH3. 決定木の複雑さとCV誤差の関係を調べる
max_leaf_nodes を 3〜50 まで動かして10-fold CVのMSEをプロットしてください。
ポイント: 葉を増やすとMSEはどこまで下がり、どこから上がる(=過適合)か。「ちょうど良い複雑さ」を自分の目で確認する。
★★★★☆ 上級
CH4. LASSOで変数選択して原論文のBest Subsetと比較
sklearn.linear_model.LassoCV で係数が0にならなかった変数と、原論文のBest Subset Selectionが選んだ23変数(本ページ4.2節)を見比べてください。
ポイント: 手法が違っても共通して残る変数(人口密度・製造業・完全失業率など)は「本当に効いている」候補。
★★★★★ 発展
CH5. 目的変数を差し替えてオリジナル分析
同じ25の説明変数で、目的変数を「転入超過数」「単独世帯割合」「合計特殊出生率(SSDSE-B)」などに差し替えて分析してください。
ポイント: 問い・データ・手法・結論を1ページのレポートにまとめる。重回帰→変数選択→木→CVという本論文の型は、どんな目的変数にもそのまま使える。
💡 ヒント: 詰まったら本サイトの他の論文(同じ手法を使っている)のスクリプトをコピーして組み合わせるのが効率的です。手法ガイド・用語集も参考に。

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

本論文で学んだ手法(重回帰+変数選択+木ベースの機械学習+CV)は、行政・企業・研究の現場で広く使われています。

🏛️
自治体の多文化共生政策
外国人住民の増加が見込まれる地域の予測は、多言語窓口・日本語教育・就学支援などの計画に直結します。本論文はまさに「どの自治体特性を注視すべきか」の候補リストを提供しています。
🏢
企業の出店・人材戦略
地域特性(人口構成・産業構造・所得)と売上・応募数の関係を重回帰+ランダムフォレストで分析し、出店候補地や採用拠点を選ぶ手法は小売・人材業界の定番です。
📊
政策研究・シンクタンク
「探索的に候補要因を洗い出し(本論文の型)→ 因果推論で検証」という2段構えは、EBPM(証拠に基づく政策立案)の実務でも標準的なワークフローです。
🤖
機械学習の実務全般
「線形モデルと木ベースモデルを両方試し、CVで比較する」のは Kaggle から企業のデータサイエンスまで共通の基本動作。本論文はその教科書的な実践例です。
🎓
学術研究(人口学・地域科学)
外国人の居住地選択・国内移動の研究では、地域特性との関連分析が基礎になります。本論文の先行研究リスト(石川・清水・是川ほか)はこの分野への入口です。
💰
不動産・金融
地域の人口動態予測は不動産価値評価や住宅ローン審査の基礎データ。外国人人口の増減は賃貸需要の先行指標として注目されています。

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

この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。

Q1. この分析、自分でもできますか?
はい。SSDSE-A(市区町村データ)は無料で公開されており、本ページ付属のスクリプトを実行するだけで図1・図3・図4と実行結果を再現できます。ただし原論文の29変数のうち4変数(未婚者割合・課税対象所得・大卒割合・刑法犯認知件数)は現行SSDSEに未収録のため、完全な再現には e-Stat「都道府県・市区町村のすがた」から自分でダウンロードして結合する必要があります。それ自体が良い演習になります。
Q2. なぜ相関係数を1つずつ計算するだけではダメなのですか?
説明変数同士が相関しているからです。例えば人口密度が高い地域は単独世帯割合も高い傾向があるため、単純相関では「どちらが効いているのか」が分離できません。重回帰は他の変数を一定とした上での関係を推定します(原論文2節がこの理由を明記しています)。
Q3. 結論は「因果関係」を示していますか?
いいえ。本論文が示したのは相関関係で、原論文自身が「因果関係ではないことに注意が必要」と明記しています。政策の効果を知りたい場合は、傾向スコアなど因果推論に適した手法が必要です(原論文5節)。
Q4. 審査会コメントの「47件に対して29変数」とは何のことですか?
原論文1ページ目の審査会コメントに記載されている表現をそのまま引用したものです。本文の分析対象は約1,700市区町村であり、47という数字は本文の記述とは対応しません(都道府県数の47を指した可能性がありますが、原資料からは確定できません)。いずれにせよ「観測数に対して説明変数が多すぎないか」という指摘は、変数選択やCVの重要性を示す本質的な論点です。
Q5. 実データ再現の結果が原論文と違うのはなぜですか?
主な理由は3つ。(1)データの年次が違う(原論文=2015年国勢調査ベース、本再現=2020年ベース)。(2)変数構成が違う(29変数 vs 25変数。特に課税対象所得と未婚者割合という原論文の重要変数が欠けている)。(3)実装が違う(R vs Python。決定木や重要度の定義が異なる)。それでも人口密度・製造業が上位、ランダムフォレストがCV最良という骨格は共通しており、頑健な結論とそうでない結論を区別する材料になります。

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

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

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

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

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