この教材は、原論文が使ったデータそのものを使えていません。そこで代わりのデータで同じ問いを追いかけ、結論の向き(増える/減る、強い/弱い)が原論文と一致するかを確かめます。「同じ数値が出る」ことは目標にしていません。
| 原論文が使ったデータ | SSDSE-A・令和3年衆院選市区町村別得票数・全市町村の主要財政指標(令和2年度) 分析単位:市区町村 中核手法:相関分析・重回帰分析 |
|---|---|
| この教材が使うデータ |
|
| 原論文(PDF) | 市区町村というミクロ的視点から投票率の実態を探る 統計数理賞/林 蔚欣(茨城県立並木中等教育学校) |
原論文と同じ粒度のデータは、この教材にも同梱しています。これを読み込めば、原論文と同じ細かさで分析をやり直せます(下の「🐍 ブラウザで動かす」でコードを書き換えて試せます)。ただし原論文が使った項目がすべて収録されているとは限りません。足りない項目は、上の「できないこと」に書いた出典から取ってくる必要があります。
▶ ここに書いてある分析は、ページ下部の「🐍 ブラウザで動かす」でそのまま実行できます(インストール不要)。動かしているのは code/2022_H3_suri.py(291 行)そのものです。
このページの離婚率ランキング(図3)と説明変数間の相関ヒートマップ(図4)は、以下の手順で自分で再現できます。コードの編集は不要です。(都道府県別・市区町村別の投票率はSSDSE-Bに無いため、投票率に関わる図1・図2は原論文の報告値を可視化します。)
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
著者は高校で「民主主義の探究」に取り組み、その集大成として本研究を行った。民主主義は「参加と責任のシステム」と捉えられ、参加の代表格が選挙である。近年は投票率の低下や若者の政治離れなど、政治への「諦めの感情」が指摘される。18歳選挙権が始まった今、著者は「高校生自身が当事者意識を持って投票率を考える」ことを動機とした。
探究の当初は、世界167か国・地域の民主主義指数と経済・社会指標の相関というマクロ的視点で分析していた。しかし民主主義は一概に定義できないため、マクロ指数だけに頼るのは危険で、ミクロ的視点で客観的な定量データを可視化することが重要だと考え直した。そこで本研究は、第49回衆議院議員総選挙(小選挙区)を対象に、市区町村レベルで投票率の実態を調べ、どんな地域属性が投票率に効くのかを明らかにすることを目的とする。
高校生の部 SSDSE-A・総務省得票数・財政力指数 探索的相関解析 多重共線性・VIF 重回帰分析
著者は3種類のデータを組み合わせ、投票率との関連解析に用いる地域属性データセット(94項目×1682市区町村)を自作した。年度の異なるデータを組み合わせている点には注意が必要、と著者自身も明記している。
| データ | 内容 | 出典 |
|---|---|---|
| SSDSE-A-2022 | 市区町村の地域属性(人口・世帯/経済基盤/行政基盤/教育/労働/医療 等124項目)。総人口に占める割合などに加工。 | 独立行政法人統計センター |
| 令和3年衆院選 市区町村別得票数 | 46都道府県の元ファイルから1682市区町村の小選挙区得票数を抽出。投票率の分子に使用。 | 総務省 |
| 市区町村の財政力指数 | 「全市町村の主要財政指標(令和2年度)」から抽出。 | 総務省 |
まず1682市区町村の投票率のヒストグラムと基本統計量を作り、次に都道府県ごとに投票率の平均や分散を計算して、県内の市区町村間のばらつきを確認した。
縦軸に94項目の地域属性、横軸に投票率を取った散布図を一覧で作り、投票率に効きそうな32項目を目視スクリーニングで抽出。都道府県別に属性と投票率の相関係数表を作成した。
32変数の相関行列から、多重共線性を持つ19変数(|r|≥0.9が10個、0.65≤|r|<0.9が9個)を除去。残った変数にVIFを計算し、「15〜64歳人口割合」と「65歳以上人口割合」でVIF>10となったため、相関の高い「65歳以上人口割合」を外した。最終的に全VIFが6未満になったところで重回帰へ進んだ。
市区町村レベルで見ると、投票率の最高は熊本県球磨村(94.74)、最低は東京都稲城市(35.91)で、レンジは58.83ポイント。これは都道府県レベルのレンジ15.25ポイント(山形66.34−茨城51.09)よりはるかに大きい。次に、各県内で市区町村の投票率がどれだけばらつくかを分散で表したのが原論文の図2である。この図は再計算ではなく、原論文が報告した46都道府県の分散値をそのまま可視化したもの(市区町村別投票率はSSDSE-Bに無い)。
=== [1] 都道府県レベル投票率の分散(原論文 図2 の報告値・市区町村粒度)=== 対象: 46都道府県(福島県は原論文で解析対象外) / 値は県内の市区町村投票率の分散 分散が大きい上位5県(県内で高低の差が大きい): 宮崎 分散 165.75 奈良 分散 97.81 岐阜 分散 88.94 石川 分散 83.83 熊本 分散 80.90 分散が小さい下位5県(県内一律の傾向): 栃木 分散 17.34 福岡 分散 17.25 埼玉 分散 15.66 佐賀 分散 15.09 茨城 分散 14.03 ※ 全市区町村の投票率: 平均58.77・標準偏差8.15・範囲58.83(原論文 表3 の報告値) ※ 最高=熊本県球磨村94.74 / 最低=東京都稲城市35.91(原論文 報告値)
多重共線性を除いた変数で重回帰した結果、有意(P<0.05)だった10変数の偏回帰係数が原論文 表7 にまとめられている。この図はその報告値をそのまま可視化したものである(投票率=目的変数がSSDSE-Bに無いため再計算不可)。
=== [2] 重回帰の偏回帰係数(原論文 表7・式1 の報告値・市区町村粒度)=== 切片 = 83.333 / 重相関R = 0.775 / 補正R² = 0.597 / 有意F = 0.000 / 観測数 = 1682 説明変数 係数 P値 向き 離婚件数の割合% -16.552 0.000 -(負) 財政力指数 -3.421 0.000 -(負) 完全失業者数の割合% -2.897 0.000 -(負) 医師数の割合% -2.486 0.001 -(負) 教員数(小中義務)の割合% 1.444 0.000 +(正) 15歳未満人口の割合% 0.369 0.000 +(正) 民生費の占める割合% -0.361 0.000 -(負) 15〜64歳人口の割合% -0.317 0.000 -(負) 非労働力人口の割合% 0.166 0.001 +(正) 人口密度(可住地面積) 0.065 0.000 +(正) ※ 影響の大きい順は 離婚率 > 財政力指数 > 完全失業率 …(原論文は因果でなく参考程度と明記)
以下の相関の向き・数値はすべて原論文の報告値である。探索的相関解析(表5)と重回帰(表7)から、著者は次のように整理した。
| 地域属性のグループ | 投票率との関係 | 解釈 |
|---|---|---|
| 人口世帯・行政財政 | 相関が高い傾向 | 投票率に効く候補として重回帰へ |
| 自然環境・医療健康 | 負の相関 | 人口過疎地・医療従事者の多い地域は投票率が低い傾向 |
| 教育(教員数など) | 正の相関 | 教員数が多いほど投票率が高い傾向 |
投票率に負の影響:離婚件数割合(−16.552)・財政力指数(−3.421)・完全失業者数割合(−2.897)・医師数割合(−2.486)・民生費割合(−0.361)・15〜64歳人口割合(−0.317)。投票率に正の影響:教員数割合(+1.444)・15歳未満人口割合(+0.369)・非労働力人口割合(+0.166)・人口密度(+0.065)。
原論文の目的変数(市区町村別投票率)はSSDSE-Bに無い。しかし説明変数の一部(離婚件数・婚姻件数・小中教員数・年齢別人口)はSSDSE-Bにも収録されている。そこで、原論文と同じ「総人口に対する割合」の作り方で、これらの変数を都道府県粒度で構築してみる。
header=1 で読み込み、都道府県行(地域コード R+5桁、全国を除外)の2023年を残す。原論文と同じ「総人口に対する割合」の作り方で、離婚率・婚姻率・教員数割合・年齢別人口割合を構築する(完全失業率・医師数・財政力指数はSSDSE-Bに無いため作れない)。136 137 138 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 | df = pd.read_csv(DATA_B, encoding='cp932', header=1) df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy() df = df[df['都道府県'] != '全国'].copy() df['年度'] = df['年度'].astype(int) d = df[df['年度'] == 2023].copy().reset_index(drop=True) # 原論文と同じ「総人口に対する割合」の作り方で SSDSE-B から構築 d['離婚率'] = d['離婚件数'] / d['総人口'] * 1000 # 人口千対 d['婚姻率'] = d['婚姻件数'] / d['総人口'] * 1000 # 人口千対 d['教員数割合'] = (d['小学校教員数'] + d['中学校教員数']) / d['総人口'] * 1000 # 人口千対 d['若年人口割合'] = d['15歳未満人口'] / d['総人口'] * 100 # % d['生産年齢割合'] = d['15~64歳人口'] / d['総人口'] * 100 # % d['高齢化率'] = d['65歳以上人口'] / d['総人口'] * 100 # % repro_vars = ['離婚率', '婚姻率', '教員数割合', '若年人口割合', '生産年齢割合', '高齢化率', '合計特殊出生率'] print('=== [3] SSDSE-B から原論文の説明変数を構築(実再現・2023年・都道府県)===') print(f'対象: {len(d)}都道府県 / 原論文の SSDSE-A(市区町村)に対し SSDSE-B(都道府県)で構築') print('SSDSE-B に収録がある変数のみ(完全失業率・医師数・財政力指数などは SSDSE-B に無く除外)') print(d[['都道府県'] + repro_vars].round(2).head(6).to_string(index=False)) dr = d.sort_values('離婚率', ascending=False) print('離婚率が高い上位5県(人口千対):') for _, r in dr.head(5).iterrows(): print(f" {r['都道府県']:<5} {r['離婚率']:.2f}") print('離婚率が低い下位5県(人口千対):') for _, r in dr.tail(5).iterrows(): print(f" {r['都道府県']:<5} {r['離婚率']:.2f}") |
=== [3] SSDSE-B から原論文の説明変数を構築(実再現・2023年・都道府県)=== 対象: 47都道府県 / 原論文の SSDSE-A(市区町村)に対し SSDSE-B(都道府県)で構築 SSDSE-B に収録がある変数のみ(完全失業率・医師数・財政力指数などは SSDSE-B に無く除外) 都道府県 離婚率 婚姻率 教員数割合 若年人口割合 生産年齢割合 高齢化率 合計特殊出生率 北海道 1.69 3.39 5.90 10.09 56.89 33.01 1.06 青森県 1.41 2.81 6.14 9.97 54.81 35.22 1.23 岩手県 1.28 2.90 6.23 10.32 54.69 35.00 1.16 宮城県 1.39 3.49 5.64 11.04 59.72 29.24 1.07 秋田県 1.26 2.52 5.50 9.08 51.86 39.06 1.10 山形県 1.19 2.90 5.82 10.62 54.19 35.19 1.22 離婚率が高い上位5県(人口千対): 沖縄県 2.16 宮崎県 1.72 北海道 1.69 福岡県 1.67 大阪府 1.66 離婚率が低い下位5県(人口千対): 島根県 1.23 石川県 1.22 山形県 1.19 新潟県 1.18 富山県 1.12
原論文で投票率への負の影響が最大だった変数は離婚率だった。その離婚率を、SSDSE-Bの離婚件数と総人口から都道府県別に構築してランキングにする。これは実データからの再計算(実再現)だが、原論文の市区町村粒度に対して都道府県粒度である点に注意(地図の代わりにランキングで地域差を表現)。
原論文の統計数理的な見どころは、多重共線性を相関行列とVIFで丁寧に除去した点にある。SSDSE-Bで構築した説明変数どうしの相関を計算し、その多重共線性を自分の手で確かめる。
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | corr = d[repro_vars].corr() print('=== [4] 説明変数間の相関ヒートマップ(実再現・多重共線性の確認)===') print('原論文は32変数の相関行列とVIFで多重共線性の強い変数を除いた。ここでは') print('SSDSE-B で作れる変数どうしの相関を実計算し、その多重共線性を実演する。') print(corr.round(2).to_string()) # 絶対値の最も大きい相関ペア(対角除く)を抽出 pairs = [] for i in range(len(repro_vars)): for j in range(i + 1, len(repro_vars)): pairs.append((repro_vars[i], repro_vars[j], corr.iloc[i, j])) pairs.sort(key=lambda t: abs(t[2]), reverse=True) a, b, r = pairs[0] print(f'最も強い相関ペア: {a} × {b} → r = {r:.3f}') print('→ これほど相関が強い変数を同時に重回帰へ入れると多重共線性が生じる。') print(' 原論文が相関行列とVIF(10未満・最終は6未満)で変数を絞った狙いが分かる。') |
=== [4] 説明変数間の相関ヒートマップ(実再現・多重共線性の確認)===
原論文は32変数の相関行列とVIFで多重共線性の強い変数を除いた。ここでは
SSDSE-B で作れる変数どうしの相関を実計算し、その多重共線性を実演する。
離婚率 婚姻率 教員数割合 若年人口割合 生産年齢割合 高齢化率 合計特殊出生率
離婚率 1.00 0.43 0.24 0.59 0.16 -0.33 0.27
婚姻率 0.43 1.00 -0.40 0.45 0.84 -0.90 -0.10
教員数割合 0.24 -0.40 1.00 0.40 -0.70 0.50 0.77
若年人口割合 0.59 0.45 0.40 1.00 0.16 -0.46 0.70
生産年齢割合 0.16 0.84 -0.70 0.16 1.00 -0.95 -0.47
高齢化率 -0.33 -0.90 0.50 -0.46 -0.95 1.00 0.20
合計特殊出生率 0.27 -0.10 0.77 0.70 -0.47 0.20 1.00
最も強い相関ペア: 生産年齢割合 × 高齢化率 → r = -0.949
→ これほど相関が強い変数を同時に重回帰へ入れると多重共線性が生じる。
原論文が相関行列とVIF(10未満・最終は6未満)で変数を絞った狙いが分かる。
著者は、全1682市区町村から得た重回帰式を、投票率の分散が最大の宮崎県と、分散が最小かつ平均最下位の茨城県に当てはめて予測精度を比べた(原論文 図4)。
茨城県への当てはまりは低かった(R²≈0.26)。県内の市町村で人口や属性に差があるのに投票率に差が出ない=属性で説明できない一律の低さがあることを意味する。著者は「茨城県のように属性差があるのに投票率が一律に低い県には、外部から投票のためのインセンティブが必要ではないか」と示唆した。
宮崎県への当てはまりは高かった(R²≈0.83)。ただし投票率の高い複数の町村では最大20ポイントほど低く予測される傾向もあった。宮崎県内の代表的な市町村を細かく見ると、投票率ベスト3(西米良村・諸塚村・椎葉村)とワースト3(都城市・三股町・小林市)の間で、教員数・離婚率・民生費・財政力指数などに整合的な差が見られた。
原論文のタイトルは「市区町村というミクロ的視点から投票率の実態を探る」。投票率(選管データ)は SSDSE に無いため、市区町村データで「なぜミクロ視点が必要か」を確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | a = pd.read_csv('data/raw/SSDSE-A-2025.csv', encoding='cp932', header=2) a = a[a['地域コード'].str.match(r'^R\d+', na=False)].copy() a = a[pd.to_numeric(a['総人口'], errors='coerce') > 0] num = lambda c: pd.to_numeric(a[c], errors='coerce') d2 = pd.DataFrame({'市区町村': (a['都道府県'] + a['市区町村']).values}) d2['高齢化率'] = (num('65歳以上人口') / num('総人口') * 100).values d2['単独世帯割合'] = (num('単独世帯数') / num('一般世帯数') * 100).values d2 = d2.dropna() print(f'市区町村数: {len(d2)}') print(f'高齢化率のばらつき: 最小 {d2["高齢化率"].min():.1f}%(若い自治体)〜 最大 {d2["高齢化率"].max():.1f}%') print('高齢化率 上位3:', '、'.join(d2.nlargest(3, '高齢化率')['市区町村'])) print('高齢化率 下位3:', '、'.join(d2.nsmallest(3, '高齢化率')['市区町村'])) r, p = stats.pearsonr(d2['高齢化率'], d2['単独世帯割合']) print(f'高齢化率 × 単独世帯割合: r = {r:+.3f}') print('→ 都道府県平均では見えない市区町村間の大きな差。原論文が「ミクロ的視点」を選んだ理由') |
本研究は、46都道府県1682市区町村というミクロな単位で投票率と地域属性の関係を解析し、散布図スクリーニング→相関行列→VIF→重回帰という手順で、離婚率・教員数割合・財政力指数・民生費割合・15〜64歳人口割合など、先行研究に見られなかった多くの地域属性と投票率の関連を示した(補正R²=0.597)。県内で属性差があるのに一律に投票率が低い茨城県には、外部インセンティブが必要と示唆した。
このページの離婚率ランキング(図3)と説明変数間の相関ヒートマップ(図4)は、以下から再現できます。
🐍 再現コード(.py) 📊 SSDSE-B-2026.csv
※ 図1(都道府県別投票率分散)と図2(偏回帰係数)は、市区町村別投票率・得票数・財政力指数がSSDSE-B外のため、原論文の報告値(市区町村粒度)を可視化したものです。図3・図4はSSDSE-Bの離婚件数・年齢別人口などからの実再現ですが、原論文の市区町村粒度に対して都道府県粒度であり、投票率が無いため「説明変数の作り方と多重共線性」の再現です。
この研究を読むとき・まねするときに陥りやすい誤解を整理する。
クリックすると各用語の詳しい解説ページに移動できます。
この研究で使われている手法を、手を動かす順に説明する。
この研究の「関連は見つけたが因果は不明・1年分のみ」という結論は、次の研究の出発点になる。
再現コードを少し変えるだけで試せる課題を、易しい順に用意した。
d = df[df['年度'] == 2023] を 2015 や 2020 に変えて、離婚率の都道府県ランキングが年で変わるか確かめよう。'離婚率' を '婚姻率' に変えて、離婚率と婚姻率で上位県・下位県がどう違うか比べよう。repro_vars に '合計特殊出生率' 以外の列(例:'着工新設住宅床面積' を人口で割った指標)を加え、多重共線性の強いペアが増えるか観察しよう。statsmodels の variance_inflation_factor を使って、図4の説明変数のVIFを計算し、10を超える変数を1つ外して再計算しよう。原論文の変数選択を追体験できる。from statsmodels.stats.outliers_influence import variance_inflation_factor。定数項を sm.add_constant で入れてから計算する。「地域単位のデータで社会現象の要因を重回帰で探る」発想は、行政や研究で広く使われている。
この研究を読んで浮かびやすい疑問に答える。
この論文を理解できたか、クリックで確認しましょう。間違えても解説が出ます。
このページの分析は、この画面の中でそのまま実行できます。
Python をインストールする必要も、CSV をダウンロードする必要もありません。
下のセルの 「▶ ブラウザで実行」 を上から順に押すか、
「▶ 最初から全部実行」 で一気に流してください。
表示されるのは、本文の図表とまったく同じ計算の結果です
(動かしているのは再現スクリプト code/2022_H3_suri.py そのもの)。
コードは書き換えられます。「✏️ 書き換える」で数字や変数を変えて ▶ を押すと、 結果がどう変わるかをその場で確かめられます(元に戻すボタンつき)。 ページを開いた時点で裏で実行環境の準備が始まっているので、待ち時間はほとんどありません。 初回だけ実行環境の取得にインターネット接続が必要です。