このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
日本では都道府県ごとの大学進学率に大きな差異が存在し、教育環境と経済的格差が相互に連動していることが指摘されてきた。特に地方と都市部では、教育費の支出額・学校施設の密度・家計の経済力などが大きく異なり、これが教育機会の不平等につながっている可能性がある。
SSDSE-B 重回帰分析 標準化係数 地域比較 相関分析
本分析では総務省統計局が提供する SSDSE-B(都道府県データ) を使用した。2022年度(令和4年度)の47都道府県横断データを用い、以下の変数を構築した。
| 変数名 | 定義 | SSDSE-B 列名 | 単位 |
|---|---|---|---|
| 大学進学率 | 高等学校卒業者のうち大学・短大への進学者割合 | 高等学校卒業者のうち進学者数 ÷ 高等学校卒業者数 | % |
| カテゴリ | 変数名 | 定義 | SSDSE-B 元変数 | 単位 |
|---|---|---|---|---|
| 教育環境 | 教育費 | 二人以上世帯の消費支出中の教育費(月額) | 教育費(二人以上の世帯) | 円/月 |
| 学校数/万人 | 幼小中高合計学校数を総人口1万人で割った値 | 幼稚園数・小学校数・中学校数・高等学校数 | 校/万人 | |
| 経済環境 | 消費支出 | 二人以上世帯の月間消費支出(経済力の代理) | 消費支出(二人以上の世帯) | 円/月 |
| 少子化・人口 | 合計特殊出生率 | その都道府県の出生率 | 合計特殊出生率 | 人 |
| 15歳未満比率 | 総人口に占める15歳未満の割合 | 15歳未満人口 ÷ 総人口 | % |
生のデータをそのまま使うのではなく、分析目的に合わせて変数を変換・合成することを特徴量エンジニアリングという。例えば「学校数」は人口の大きい都道府県ほど多くなるため、「人口1万人あたり学校数」に変換することで都道府県間を公平に比較できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 scipy import stats plt.rcParams['font.family'] = 'Hiragino Sans' plt.rcParams['axes.unicode_minus'] = False plt.rcParams['figure.dpi'] = 150 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) # 2022年断面 df = df_b[df_b['年度'] == 2022].copy().reset_index(drop=True) assert len(df) == 47, f"都道府県数が47ではありません: {len(df)}" |
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) — 列を整数に変換(年度などを数値比較するため)。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。25 26 27 28 29 30 31 32 33 34 | df['大学進学率'] = df['高等学校卒業者のうち進学者数'] / df['高等学校卒業者数'] * 100 # 教育費(円/月, 二人以上世帯) df['教育費'] = df['教育費(二人以上の世帯)'].astype(float) # 人口1万人あたり学校数(幼小中高合計) df['学校数_万人あたり'] = ( (df['幼稚園数'] + df['小学校数'] + df['中学校数'] + df['高等学校数']) / df['総人口'] * 10000 ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。35 36 37 38 39 40 41 42 | # 消費支出(円/月): 経済力の代理 df['消費支出'] = df['消費支出(二人以上の世帯)'].astype(float) # 合計特殊出生率 df['出生率'] = df['合計特殊出生率'].astype(float) # 15歳未満人口比率(%) df['子供比率'] = df['15歳未満人口'] / df['総人口'] * 100 |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | # 地域区分 region_map = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄' } region_colors = { '北海道・東北': '#4e9af1', '関東': '#e05c5c', '中部': '#f0a500', '近畿': '#5cb85c', '中国・四国': '#9b59b6', '九州・沖縄': '#f39c12' } df['地域'] = df['都道府県'].map(region_map) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。65 66 67 68 | # 分析用データフレーム(欠損除去) vars_use = ['大学進学率', '教育費', '学校数_万人あたり', '消費支出', '出生率', '子供比率'] df_ana = df[['都道府県', '地域'] + vars_use].dropna().copy() print(f"分析対象都道府県数: {len(df_ana)}") |
分析対象都道府県数: 47
r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。まず変数の分布と2変数の関係を散布図で確認することが有効だと考えられる。 その理由は回帰分析に進む前に外れ値や非線形性、地域の傾向を視覚的に把握しておく必要があるからである。 ここでは教育費と大学進学率に着目し、散布図と地域別ランキングという手法を用いる。
全国平均 56.6% に対し、最高の京都府(73.0%)と最低の沖縄県(46.2%)の差は 26.8ポイント にのぼる。
70 71 72 73 74 75 76 | fig1, ax1 = plt.subplots(figsize=(10, 7)) for region, grp in df_ana.groupby('地域'): ax1.scatter( grp['教育費'], grp['大学進学率'], c=region_colors[region], label=region, s=60, zorder=3, alpha=0.85 ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。77 78 79 80 81 82 83 84 | # 都道府県ラベル for _, row in df_ana.iterrows(): ax1.annotate( row['都道府県'], (row['教育費'], row['大学進学率']), fontsize=6.5, ha='left', va='bottom', xytext=(2, 2), textcoords='offset points', color='#333333' ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | # 回帰線 x_reg = np.linspace(df_ana['教育費'].min(), df_ana['教育費'].max(), 200) slope, intercept, rval, pval, _ = stats.linregress(df_ana['教育費'], df_ana['大学進学率']) ax1.plot(x_reg, slope * x_reg + intercept, color='#333', linewidth=1.5, linestyle='--', zorder=2, label=f'回帰線 r={rval:.2f}') ax1.set_xlabel('教育費(円/月, 二人以上世帯)', fontsize=12) ax1.set_ylabel('大学進学率(%)', fontsize=12) ax1.set_title('図1: 教育費と大学進学率の関係(2022年・47都道府県)', fontsize=13, pad=12) ax1.legend(fontsize=9, loc='upper left', framealpha=0.9) ax1.grid(True, alpha=0.3) fig1.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2021_H1_fig1.png'), bbox_inches='tight') plt.close(fig1) print("fig1 saved") |
fig1 saved
stats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。前節の散布図とランキングで示された地域差を踏まえると、 教育費だけでなく学校密度や経済状況など複数要因が同時に影響していると考えられる。 これを検証する必要があるが、その手法として標準化偏回帰係数を用いた重回帰分析に着目した。 どの変数が独立に進学率を説明しているかが明確になることが期待される。
変数を標準化(Zスコア変換)したうえで最小二乗法(OLS)で推定し、標準化偏回帰係数(β)を算出した。β の大きさが各変数の「相対的な説明力」を示す。
| 説明変数 | 標準化係数 β | 95%信頼区間 | p値 | 有意 |
|---|---|---|---|---|
| 学校数/万人 | −0.420 | [−0.759, −0.081] | 0.016 | * |
| 教育費(円/月) | +0.222 | [−0.109, +0.554] | 0.183 | — |
| 合計特殊出生率 | −0.135 | [−0.583, +0.314] | 0.547 | — |
| 15歳未満人口比率 | −0.070 | [−0.459, +0.320] | 0.719 | — |
| 消費支出(円/月) | +0.056 | [−0.263, +0.374] | 0.726 | — |
注)*: p<0.05。目的変数・説明変数はすべてZスコア標準化済み。OLSによる推定。n=47。
モデル全体:F検定 p = 5.48×10⁻⁵(有意)、R² = 0.472、調整済みR² = 0.408
単位が異なる変数(円/月・%・校/万人など)を直接比較するには、すべての変数を平均0・標準偏差1に揃える標準化(Zスコア変換)を行う。標準化後の回帰係数β を比べることで「どの変数が目的変数に最も影響しているか」がわかる。
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 128 129 130 131 132 133 | var_labels = { '大学進学率': '大学\n進学率', '教育費': '教育費', '学校数_万人あたり': '学校数\n/万人', '消費支出': '消費\n支出', '出生率': '出生率', '子供比率': '子供\n比率' } corr_disp = corr_mat.copy() corr_disp.index = [var_labels[v] for v in corr_disp.index] corr_disp.columns = [var_labels[v] for v in corr_disp.columns] fig2, ax2 = plt.subplots(figsize=(7, 6)) n = len(corr_disp) im = ax2.imshow(corr_disp.values, cmap='RdBu_r', vmin=-1, vmax=1, aspect='auto') plt.colorbar(im, ax=ax2, shrink=0.8) for i in range(n): for j in range(n): val = corr_disp.values[i, j] color = 'white' if abs(val) > 0.6 else 'black' ax2.text(j, i, f'{val:.2f}', ha='center', va='center', fontsize=10, color=color, fontweight='bold') ax2.set_xticks(range(n)) ax2.set_yticks(range(n)) ax2.set_xticklabels(corr_disp.columns, fontsize=10) ax2.set_yticklabels(corr_disp.index, fontsize=10) ax2.set_title('図2: 教育・経済関連変数の相関行列(2022年)', fontsize=12, pad=12) fig2.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2021_H1_fig2.png'), bbox_inches='tight') plt.close(fig2) print("fig2 saved") |
fig2 saved
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。47都道府県を6地域ブロックに分類して教育指標を比較した。
| 地域 | 都道府県数 | 大学進学率平均 | 教育費平均(円/月) | 消費支出平均(円/月) |
|---|---|---|---|---|
| 近畿 | 7 | 63.5% | 13,040 | 311,000 |
| 関東 | 7 | 62.5% | 15,080 | 323,000 |
| 中部 | 9 | 58.7% | 11,260 | 306,000 |
| 中国・四国 | 9 | 55.6% | 9,680 | 280,000 |
| 北海道・東北 | 7 | 50.6% | 8,100 | 268,000 |
| 九州・沖縄 | 8 | 49.6% | 7,950 | 255,000 |
都道府県を地域ブロックに分けて集計(groupby)すると、全国一律では見えなかった構造的な格差が浮かびあがる。都道府県単位の散布図と地域ブロック単位の棒グラフを併用することで、マクロ・ミクロ両方の視点を持つことができる。
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | var_name_map = { '教育費': '教育費(円/月)', '学校数_万人あたり': '学校数/万人', '消費支出': '消費支出(円/月)', '出生率': '合計特殊出生率', '子供比率': '15歳未満人口比率(%)' } coef_df['変数名'] = coef_df['変数'].map(var_name_map) colors_bar = ['#e05c5c' if c > 0 else '#4e9af1' for c in coef_df['係数']] sig_mark = ['*' if p < 0.05 else '' for p in coef_df['p値']] fig3, ax3 = plt.subplots(figsize=(8, 5)) bars = ax3.barh( coef_df['変数名'], coef_df['係数'], color=colors_bar, alpha=0.8, edgecolor='white', linewidth=0.5 ) # 95%CI for i, (_, row) in enumerate(coef_df.iterrows()): ax3.plot( [row['CI_lo'], row['CI_hi']], [i, i], color='#333', linewidth=1.5, zorder=5 ) ax3.plot([row['CI_lo']], [i], '|', color='#333', markersize=7) ax3.plot([row['CI_hi']], [i], '|', color='#333', markersize=7) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | # 係数値とp値マーク for i, (_, row) in enumerate(coef_df.iterrows()): offset = 0.005 sign = 1 if row['係数'] >= 0 else -1 ax3.text( row['CI_hi'] + offset if row['係数'] >= 0 else row['CI_lo'] - offset, i, f'{row["係数"]:.3f}{sig_mark[i]}', va='center', ha='left' if row['係数'] >= 0 else 'right', fontsize=9, color='#333' ) ax3.axvline(0, color='#333', linewidth=0.8, linestyle='-') ax3.set_xlabel('標準化偏回帰係数(β)', fontsize=11) ax3.set_title('図3: 標準化偏回帰係数と95%信頼区間\n(目的変数:大学進学率)', fontsize=12, pad=10) ax3.set_xlim(coef_df['CI_lo'].min() - 0.15, coef_df['CI_hi'].max() + 0.2) note = f'R²={r2:.3f} 調整済みR²={r2_adj:.3f} *p<0.05' ax3.text(0.98, 0.02, note, transform=ax3.transAxes, fontsize=9, ha='right', va='bottom', color='#555') ax3.grid(axis='x', alpha=0.3) fig3.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2021_H1_fig3.png'), bbox_inches='tight') plt.close(fig3) print("fig3 saved") |
fig3 saved
ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。本分析の結果を踏まえ、教育格差を縮小するための政策的な方向性を提案する。
統計分析の結論を社会政策に活かすには、「相関関係」と「因果関係」の区別が重要である。本研究で発見した「教育費が高い地域は進学率が高い」という相関は、「教育費を増やせば進学率が上がる」という因果を直接意味しない。逆の因果(進学率が高い地域に住む家庭が教育費を増やす)や第三の変数(所得水準)が媒介している可能性もある。政策検討では、これらの代替仮説を丁寧に検討することが求められる。
183 184 185 186 187 188 189 190 191 192 193 194 195 | Y_col = '大学進学率' X_cols = ['教育費', '学校数_万人あたり', '消費支出', '出生率', '子供比率'] Y = df_ana[Y_col] X = df_ana[X_cols] # 標準化 Y_z = (Y - Y.mean()) / Y.std() X_z = (X - X.mean()) / X.std() X_z_sm = sm.add_constant(X_z) model = sm.OLS(Y_z, X_z_sm).fit() print(model.summary()) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。196 197 198 199 200 201 202 203 204 205 206 | # 標準化偏回帰係数(切片除く) coef_df = pd.DataFrame({ '変数': X_cols, '係数': model.params[X_cols].values, 'CI_lo': model.conf_int().loc[X_cols, 0].values, 'CI_hi': model.conf_int().loc[X_cols, 1].values, 'p値': model.pvalues[X_cols].values, }) coef_df = coef_df.sort_values('係数') print("\n標準化偏回帰係数:") print(coef_df) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。207 208 209 210 211 212 213 214 215 | # 相関行列(ピアソン) corr_mat = df_ana[vars_use].corr() print("\n相関行列:") print(corr_mat.round(3)) # R²・調整済みR² r2 = model.rsquared r2_adj = model.rsquared_adj print(f"\nR² = {r2:.3f}, 調整済みR² = {r2_adj:.3f}") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。216 217 218 219 220 221 222 223 | # 都道府県別進学率ランキング df_rank = df_ana.sort_values('大学進学率', ascending=False).reset_index(drop=True) top10 = df_rank.head(10) bot10 = df_rank.tail(10) print("\n上位10都道府県:") print(top10[['都道府県', '大学進学率', '地域']].to_string(index=False)) print("\n下位10都道府県:") print(bot10[['都道府県', '大学進学率', '地域']].to_string(index=False)) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。224 225 226 227 228 | # 教育費と大学進学率の相関係数 r_edu, p_edu = stats.pearsonr(df_ana['教育費'], df_ana['大学進学率']) r_sho, p_sho = stats.pearsonr(df_ana['消費支出'], df_ana['大学進学率']) print(f"\n教育費×大学進学率: r={r_edu:.3f}, p={p_edu:.4f}") print(f"消費支出×大学進学率: r={r_sho:.3f}, p={p_sho:.4f}") |
OLS Regression Results
==============================================================================
Dep. Variable: 大学進学率 R-squared: 0.472
Model: OLS Adj. R-squared: 0.408
Method: Least Squares F-statistic: 7.334
Date: Mon, 18 May 2026 Prob (F-statistic): 5.48e-05
Time: 11:23:47 Log-Likelihood: -51.171
No. Observations: 47 AIC: 114.3
Df Residuals: 41 BIC: 125.4
Df Model: 5
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 2.501e-15 0.112 2.23e-14 1.000 -0.227 0.227
教育費 0.2224 0.164 1.355 0.183 -0.109 0.554
学校数_万人あたり -0.4201 0.168 -2.505 0.016 -0.759 -0.081
消費支出 0.0556 0.158 0.353 0.726 -0.263 0.374
出生率 -0.1348 0.222 -0.607 0.547 -0.583 0.314
子供比率 -0.0698 0.193 -0.362 0.719 -0.459 0.320
==============================================================================
Omnibus: 1.376 Durbin-Watson: 1.125
Prob(Omnibus): 0.502 Jarque-Bera (JB): 1.376
Skew: 0.360 Prob(JB): 0.503
Kurtosis: 2.571 Cond. No. 4.32
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
標準化偏回帰係数:
変数 係数 CI_lo CI_hi p値
1 学校数_万人あたり -0.420050 -0.758675 -0.081426 0.016306
3 出生率 -0.134796 -0.583118 0.313527 0.547060
4 子供比率 -0.069810 -0.459474 0.319854 0.719353
2 消費支出 0.055598 -0.262780 0.373975 0.726144
0 教育費 0.222413 -0.109044 0.553870 0.182791
相関行列:
大学進学率 教育費 学校数_万人あたり 消費支出 出生率 子供比率
大学進学率 1.000 0.494 -0.620 0.446 -0.493 -0.148
教育費 0.494 1.000 -0.468 0.634 -0.336 0.075
学校数_万人あたり -0.620 -0.468 1.000 -0.466 0.521 -0.001
消費支出 0.446 0.634 -0.466 1.000 -0.336 -0.123
出生率 -0.493 -0.336 0.521 -0.336 1.000 0.658
子供比率 -0.148 0.075 -0.001 -0.123 0.658 1.000
R² = 0.472, 調整済みR² = 0.408
上位10都道府県:
都道府県 大学進学率 地域
京都府 72.985627 近畿
東京都 72.706896 関東
神奈川県 68.015451 関東
大阪府 67.528420 近畿
兵庫県 67.035355 近畿
広島県 64.611260 中国・四国
埼玉県 64.542577 関東
奈良県 63.881636 近畿
愛知県 62.791165 中部
福井県 62.606870 中部
下位10都道府県:
都道府県 大学進学率 地域
熊本県 48.968373 九州・沖縄
山形県 48.819437 北海道・東北
宮崎県 48.482857 九州・沖縄
長崎県 48.385622 九州・沖縄
佐賀県 47.857143 九州・沖縄
岩手県 47.521866 北海道・東北
秋田県 47.518238 北海道・東北
山口県 46.883768 中国・四国
鹿児島県 46.331032 九州・沖縄
沖縄県 46.199002 九州・沖縄
教育費×大学進学率: r=0.494, p=0.0004
消費支出×大学進学率: r=0.446, p=0.0017stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。229 230 231 232 233 234 235 236 237 | top10_disp = df_rank.head(10).copy() bot10_disp = df_rank.tail(10).copy() rank_df = pd.concat([top10_disp, bot10_disp]).reset_index(drop=True) rank_df['色'] = rank_df['地域'].map(region_colors) fig4, ax4 = plt.subplots(figsize=(10, 6)) x_pos = list(range(10)) + [v + 11.5 for v in range(10)] colors_rank = [region_colors[r] for r in rank_df['地域']] bars4 = ax4.bar(x_pos, rank_df['大学進学率'], color=colors_rank, alpha=0.85, edgecolor='white') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。238 239 240 241 242 243 244 245 | # 値ラベル for bar, val in zip(bars4, rank_df['大学進学率']): ax4.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.3, f'{val:.1f}%', ha='center', va='bottom', fontsize=7.5, color='#333') # x軸ラベル ax4.set_xticks(x_pos) ax4.set_xticklabels(rank_df['都道府県'], rotation=45, ha='right', fontsize=9) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。246 247 248 249 250 251 | # 区切り線 ax4.axvline(10.25, color='#aaa', linewidth=1.5, linestyle='--') ax4.text(4.5, ax4.get_ylim()[1] * 0.97, '上位10都道府県', ha='center', fontsize=10, color='#c0392b', fontweight='bold') ax4.text(16, ax4.get_ylim()[1] * 0.97, '下位10都道府県', ha='center', fontsize=10, color='#2980b9', fontweight='bold') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。np.cumsum(arr) は累積和、np.linspace(a, b, n) は「aからbを等間隔でn個」。NumPyの定石です。252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | # 凡例 from matplotlib.patches import Patch legend_elements = [Patch(facecolor=c, label=r) for r, c in region_colors.items()] ax4.legend(handles=legend_elements, fontsize=8, loc='upper right', framealpha=0.9, ncol=2) ax4.set_ylabel('大学進学率(%)', fontsize=11) ax4.set_title('図4: 都道府県別大学進学率ランキング(2022年)', fontsize=13, pad=10) ax4.set_ylim(0, rank_df['大学進学率'].max() * 1.12) ax4.grid(axis='y', alpha=0.3) fig4.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2021_H1_fig4.png'), bbox_inches='tight') plt.close(fig4) print("fig4 saved") print("\n=== 統計サマリー ===") print(f"大学進学率 全国平均: {df_ana['大学進学率'].mean():.1f}%") print(f"大学進学率 最高: {df_ana.loc[df_ana['大学進学率'].idxmax(), '都道府県']} " f"{df_ana['大学進学率'].max():.1f}%") print(f"大学進学率 最低: {df_ana.loc[df_ana['大学進学率'].idxmin(), '都道府県']} " f"{df_ana['大学進学率'].min():.1f}%") print(f"教育費 全国平均: {df_ana['教育費'].mean():.0f}円/月") print(f"出生率 全国平均: {df_ana['出生率'].mean():.2f}") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。{値:.2f}(小数2桁)、{値:,}(3桁区切り)、{値:>10}(右寄せ10桁)など、覚えると出力が一気に整います。275 276 277 | # 地域別平均 print("\n地域別大学進学率平均:") print(df_ana.groupby('地域')['大学進学率'].mean().sort_values(ascending=False).round(1)) |
fig4 saved === 統計サマリー === 大学進学率 全国平均: 56.6% 大学進学率 最高: 京都府 73.0% 大学進学率 最低: 沖縄県 46.2% 教育費 全国平均: 10646円/月 出生率 全国平均: 1.36 地域別大学進学率平均: 地域 近畿 63.5 関東 62.5 中部 58.7 中国・四国 55.6 北海道・東北 50.6 九州・沖縄 49.6 Name: 大学進学率, dtype: float64
df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。本研究では SSDSE-B(都道府県別統計・2022年)を用いて、都道府県別の大学進学率を目的変数とし、教育費・学校数/人口・消費支出・合計特殊出生率・15歳未満人口比率を説明変数とする重回帰分析を実施した。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。