このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
日本の大学進学率は1990年代以降に急上昇し、2022年には全国平均で約56.6%に達した。しかし、この「高い進学率」という集計数値の背後には、都道府県間で最大27ポイント以上に達する大きな地域格差が隠れている。
まず「大学進学率の地域格差地理的異質性と集積効果のパネル分析」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
本研究は、地理的異質性(都道府県の位置・周辺環境)と集積効果(大学集中による進学促進効果)の2つの視点からこの格差を解剖する。SSDSE都道府県別パネルデータ(2012〜2023年)を活用し、OLS回帰、地域別時系列分析、Ward法クラスタリングを組み合わせた多角的なアプローチを取る。
SSDSE-B(都道府県) OLS回帰 地域別分析 Ward法クラスタリング 時系列分析
本分析では、統計数理研究所が公開するSSDSE-B-2026(社会・人口統計体系データセット・都道府県版)を使用する。47都道府県 × 12年度(2012〜2023)の計564レコードを含む縦断(パネル)データである。
| 項目 | 内容 |
|---|---|
| データソース | SSDSE-B-2026.csv(社会・人口統計体系) |
| 対象 | 全47都道府県 |
| 期間 | 2012〜2023年度(12年間) |
| 総レコード数 | 564件(47都道府県 × 12年) |
| 欠損値 | 主要変数は欠損なし |
進学率は以下の式で計算する比率変数である。分母に0が入らないよう前処理を行う。
| 変数名 | 元データ列 | 変換 | 想定される効果 |
|---|---|---|---|
| 大学数 | 大学数 | そのまま(校) | 正(集積効果:大学が多いほど進学しやすい) |
| 高齢化率 | 65歳以上人口 / 総人口 | × 100 (%) | 負(高齢化地域ほど若年人口が少なく進学率低下) |
| 消費支出_log | 消費支出(二人以上の世帯) | 自然対数変換 | 正(消費水準が高い地域ほど教育投資が多い) |
| 教育費_千円 | 教育費(二人以上の世帯) | ÷ 1000(千円) | 正(教育支出が多い世帯ほど進学促進) |
比率変数(割合・率)を正しく定義することは、教育統計分析の出発点である。「進学率」のように「分母が何か」によって数値の意味が変わる点に注意。
.replace(0, np.nan) でゼロをNaNに変換し、後続のdropnaで対処1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | df_b['大学進学率'] = df_b['高等学校卒業者のうち進学者数'] / df_b['高等学校卒業者数'].replace(0, np.nan) * 100 df_b['高齢化率'] = df_b['65歳以上人口'] / df_b['総人口'] * 100 df_b['消費支出_log'] = np.log(df_b['消費支出(二人以上の世帯)'].clip(lower=1)) df_b['教育費_千円'] = df_b['教育費(二人以上の世帯)'] / 1000 df_b['総人口_千人'] = df_b['総人口'] / 1000 # 地域区分 region_map = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄', } df_b['地域'] = df_b['都道府県'].map(region_map) region_colors = { '北海道・東北': '#4e9af1', '関東': '#e05c5c', '中部': '#f0a500', '近畿': '#5cb85c', '中国・四国': '#9b59b6', '九州・沖縄': '#f39c12', } |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。2012〜2023年の12年間にわたる都道府県別大学進学率を、6つの地域区分(北海道・東北、関東、中部、近畿、中国・四国、九州・沖縄)で集計した地域平均を折れ線グラフで示す。
| 地域 | 含まれる都道府県 |
|---|---|
| 北海道・東北 | 北海道・青森・岩手・宮城・秋田・山形・福島 |
| 関東 | 茨城・栃木・群馬・埼玉・千葉・東京・神奈川 |
| 中部 | 新潟・富山・石川・福井・山梨・長野・岐阜・静岡・愛知 |
| 近畿 | 三重・滋賀・京都・大阪・兵庫・奈良・和歌山 |
| 中国・四国 | 鳥取・島根・岡山・広島・山口・徳島・香川・愛媛・高知 |
| 九州・沖縄 | 福岡・佐賀・長崎・熊本・大分・宮崎・鹿児島・沖縄 |
31 32 33 34 35 36 37 38 39 40 41 42 43 44 | fig, ax = plt.subplots(figsize=(10, 5)) yearly = df_b.groupby(['年度', '地域'])['大学進学率'].mean().reset_index() for reg, grp in yearly.groupby('地域'): ax.plot(grp['年度'], grp['大学進学率'], marker='o', markersize=4, label=reg, color=region_colors.get(reg, 'gray')) ax.set_xlabel('年度', fontsize=12) ax.set_ylabel('大学進学率(%)', fontsize=12) ax.set_title('地域別 大学進学率の推移(2012〜2023年)', fontsize=14, fontweight='bold') ax.legend(fontsize=9) ax.grid(alpha=0.3) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_U5_10_fig1_ts.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig1 saved") |
Fig1 saved
df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。2022年時点の47都道府県の大学進学率を横棒グラフでランキング表示する。色は地域区分を表し、赤の破線は全国平均(56.6%)を示す。
| 順位 | 都道府県 | 地域 | 大学進学率(%) | 全国平均比 |
|---|---|---|---|---|
| 1位 | 京都府 | 近畿 | 73.0% | +16.4ポイント |
| 2位 | 東京都 | 関東 | 高位 | 全国有数 |
| — | 全国平均 | — | 56.6% | — |
| 最低 | 沖縄県 | 九州・沖縄 | 46.2% | -10.4ポイント |
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | df_2022 = df_b[df_b['年度'] == 2022].copy() df_sorted = df_2022.sort_values('大学進学率', ascending=True).dropna(subset=['大学進学率']) fig, ax = plt.subplots(figsize=(8, 12)) colors = [region_colors.get(df_sorted[df_sorted['都道府県'] == pref]['地域'].values[0], 'gray') if pref in df_sorted['都道府県'].values else 'gray' for pref in df_sorted['都道府県']] bars = ax.barh(df_sorted['都道府県'], df_sorted['大学進学率'], color=colors, alpha=0.8) ax.set_xlabel('大学進学率(%)', fontsize=12) ax.set_title('都道府県別 大学進学率ランキング(2022年)', fontsize=13, fontweight='bold') ax.axvline(df_2022['大学進学率'].mean(), color='red', linestyle='--', linewidth=1.5, label=f'全国平均: {df_2022["大学進学率"].mean():.1f}%') ax.legend(fontsize=10) ax.grid(axis='x', alpha=0.3) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_U5_10_fig2_rank.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig2 saved") |
Fig2 saved
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。2022年の横断データ(47都道府県)を用いたOLS(普通最小二乗法)回帰で、大学進学率の決定要因を特定する。左パネルに回帰係数(95%信頼区間付き)、右パネルにVIF(分散拡大要因)を示す。
| 変数 | 回帰係数 | p値 | 有意性 | VIF | 解釈 |
|---|---|---|---|---|---|
| 大学数 | +0.100 | 0.028 | **(p<0.05) | 2.59 | 大学が1校増えると進学率が0.10%上昇(集積効果) |
| 高齢化率 | -0.574 | 0.090 | †(p<0.10) | 182.2 | 高齢化が進むほど進学率が低下(符号は想定通り) |
| 消費支出_log | +17.06 | 0.261 | ns | 239.3 | 有意でないが、多重共線性の疑いあり(VIF極大) |
| 教育費_千円 | +0.190 | 0.460 | ns | 10.63 | 単変量では関連があるが、他変数と重複 |
| (定数項) | -143.7 | 0.446 | ns | — | — |
N=47, R²=0.480, Adj.R²=0.431, F(4,42)=9.70, p=0.0000120. **: p<0.05, †: p<0.10, ns: 有意でない
VIF(Variance Inflation Factor)は、ある説明変数が他の説明変数で「どれだけ説明されるか」を測る指標で、多重共線性の深刻さを診断する。
対処法としては、(1) 相関の高い変数を1つ除外、(2) 主成分分析で次元圧縮、(3) リッジ回帰などの正則化手法が有効。
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 100 101 102 103 | xvars = ['大学数', '高齢化率', '消費支出_log', '教育費_千円'] df_reg = df_2022[['大学進学率'] + xvars].dropna() X = sm.add_constant(df_reg[xvars]) res = sm.OLS(df_reg['大学進学率'], X).fit() # VIF計算 vif_df = pd.DataFrame({ '変数': xvars, 'VIF': [variance_inflation_factor(df_reg[xvars].values, i) for i in range(len(xvars))] }) print(vif_df) print(res.summary()) coefs = res.params.drop('const') ses = res.bse.drop('const') pvals = res.pvalues.drop('const') fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) # 係数プロット colors_c = ['#e05c5c' if p < 0.05 else '#888888' for p in pvals] ax1.barh(range(len(coefs)), coefs, xerr=1.96 * ses, color=colors_c, alpha=0.8, error_kw={'elinewidth': 1.5, 'capsize': 4}) ax1.set_yticks(range(len(coefs))) ax1.set_yticklabels(coefs.index, fontsize=10) ax1.axvline(0, color='black', linewidth=0.8) ax1.set_xlabel('回帰係数', fontsize=12) ax1.set_title(f'OLS回帰係数(R²={res.rsquared:.3f})\n(赤=p<0.05)', fontsize=12, fontweight='bold') ax1.grid(axis='x', alpha=0.3) # VIFテーブル ax2.axis('off') tdata = [[v, f'{vf:.2f}'] for v, vf in zip(vif_df['変数'], vif_df['VIF'])] table = ax2.table(cellText=tdata, colLabels=['変数', 'VIF'], cellLoc='center', loc='center', bbox=[0.1, 0.2, 0.8, 0.6]) table.auto_set_font_size(False) table.set_fontsize(10) ax2.set_title('分散拡大要因(VIF)\nVIF > 10 は多重共線性の懸念', fontsize=12, fontweight='bold') plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_U5_10_fig3_ols.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig3 saved") |
変数 VIF
0 大学数 2.586116
1 高齢化率 182.180150
2 消費支出_log 239.309028
3 教育費_千円 10.626274
OLS Regression Results
==============================================================================
Dep. Variable: 大学進学率 R-squared: 0.480
Model: OLS Adj. R-squared: 0.431
Method: Least Squares F-statistic: 9.695
Date: Mon, 18 May 2026 Prob (F-statistic): 1.20e-05
Time: 11:24:17 Log-Likelihood: -142.31
No. Observations: 47 AIC: 294.6
Df Residuals: 42 BIC: 303.9
Df Model: 4
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const -143.6831 186.590 -0.770 0.446 -520.237 232.871
大学数 0.0995 0.044 2.269 0.028 0.011 0.188
高齢化率 -0.5741 0.330 -1.738 0.090 -1.241 0.092
消費支出_log 17.0643 14.973 1.140 0.261 -13.153 47.282
教育費_千円 0.1903 0.255 0.746 0.460 -0.324 0.705
==============================================================================
Omnibus: 0.649 Durbin-Watson: 1.865
Prob(Omnibus): 0.723 Jarque-Bera (JB): 0.693
Skew: 0.257 Prob(JB): 0.707
Kurtosis: 2.701 Cond. No. 9.88e+03
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 9.88e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
Fig3 savedfig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。大学進学率・高齢化率・消費支出・教育費の4変数を標準化し、Ward法(階層型クラスタリング)で47都道府県を類型化する。デンドログラム(樹形図)によって都道府県間の類似性を可視化する。
Ward法は階層型クラスタリングの一手法で、「グループ内分散を最小化」するようにクラスターを結合していく。手順は以下の通り:
標準化(StandardScaler)は変数間のスケール差をなくすための必須前処理。単位の異なる変数(%と千円など)をそのまま使うとスケールの大きい変数が距離計算を支配してしまう。
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.ticker as mticker from scipy.cluster.hierarchy import dendrogram, linkage, fcluster from scipy.spatial.distance import pdist from sklearn.preprocessing import StandardScaler import statsmodels.api as sm from statsmodels.stats.outliers_influence import variance_inflation_factor import warnings warnings.filterwarnings('ignore') plt.rcParams['font.family'] = 'Hiragino Sans' plt.rcParams['axes.unicode_minus'] = False plt.rcParams['figure.dpi'] = 150 import os FIG_DIR = 'html/figures' DATA_B = 'data/raw/SSDSE-B-2026.csv' os.makedirs(FIG_DIR, exist_ok=True) df_b = pd.read_csv(DATA_B, encoding='cp932', header=1) df_b = df_b[df_b['地域コード'].str.match(r'^R\d{5}$', na=False)].copy() df_b['年度'] = df_b['年度'].astype(int) df_b = df_b.sort_values(['都道府県', '年度']).reset_index(drop=True) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。matplotlib.use('Agg') — グラフを画面表示せずファイルに保存するためのおまじない。plt.rcParams['font.family'] — グラフの日本語表示用フォント指定(Macは Hiragino Sans、Windowsなら Yu Gothic 等)。os.makedirs('html/figures', exist_ok=True) — 図の保存先フォルダを作る(既にあってもOK)。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。.astype(int) — 列を整数に変換(年度などを数値比較するため)。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | cluster_vars = ['大学進学率', '高齢化率', '消費支出_log', '教育費_千円'] df_clust = df_2022[['都道府県'] + cluster_vars].dropna().set_index('都道府県') scaler = StandardScaler() X_scaled = scaler.fit_transform(df_clust) Z = linkage(X_scaled, method='ward') fig, ax = plt.subplots(figsize=(12, 6)) dendrogram(Z, labels=df_clust.index.tolist(), ax=ax, color_threshold=Z[-3, 2], leaf_rotation=90, leaf_font_size=8) ax.set_title('Ward法クラスタリング:大学進学率・高齢化・消費水準(2022年)', fontsize=13, fontweight='bold') ax.set_xlabel('都道府県', fontsize=11) ax.set_ylabel('距離(Ward法)', fontsize=11) ax.grid(axis='y', alpha=0.3) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_U5_10_fig4_cluster.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig4 saved") print("All figures saved!") |
Fig4 saved All figures saved!
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。本研究はSSDSE都道府県別パネルデータ(2012〜2023年)を用い、大学進学率の地域格差を多角的に分析した。主な発見は以下の通りである。
「格差」を定量化する際には、複数の指標を使い分けることが重要。それぞれが「格差のどの側面」を捉えているかを理解したうえで使う。
| データ | 出典 | 備考 |
|---|---|---|
| SSDSE-B-2026.csv | 統計数理研究所 SSDSE(社会・人口統計体系)都道府県版 | 47都道府県 × 2012〜2023年 |
| 高等学校卒業者のうち進学者数 | 文部科学省 学校基本調査(SSDSE-B収録) | 大学進学率の分子 |
| 高等学校卒業者数 | 文部科学省 学校基本調査(SSDSE-B収録) | 大学進学率の分母 |
| 大学数・消費支出・教育費等 | SSDSE-B-2026.csv(総務省・文部科学省 等) | 説明変数として使用 |
| ライブラリ | 用途 | インストール |
|---|---|---|
| pandas / numpy | データ操作・数値計算 | pip install pandas numpy |
| matplotlib | グラフ描画 | pip install matplotlib |
| statsmodels | OLS回帰・VIF計算 | pip install statsmodels |
| scipy | Ward法クラスタリング | pip install scipy |
| scikit-learn | StandardScaler(標準化) | pip install scikit-learn |
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。