このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
日本における「学力の地域格差」は、都市部と地方の間で長年指摘されてきた社会的課題である。全国学力・学習状況調査の都道府県別ランキングが毎年注目を集めるように、教育の地域格差は教育機会の均等化という観点から重要な政策課題である。
まず「地域の学力差と教育環境教員配置・教育費の影響分析」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
本研究は、教員の配置状況(教員配置充実度)と家計の教育費支出が学力の地域格差にどのように関連しているかを統計的に分析する。ただし、都道府県別の学力データは公表されていないため、大学進学率を学力の代理変数として用いる。
SSDSE-B 相関分析 OLS回帰 時系列分析 地域比較
SSDSE-B-2026(社会・人口統計体系 都道府県別データ)を使用。47都道府県 × 12年間(2012〜2023年)の時系列横断面データ(計564行)を分析に用いた。
| 変数名 | 計算式 | SSDSE列 | 役割 |
|---|---|---|---|
| 大学進学率(%) | 高校卒業者のうち進学者数 / 高校卒業者数 × 100 | E4602 / E4601 | 目的変数(代理) |
| 教員配置充実度(小)(%) | 小学校教員数 / 小学校児童数 × 100 | E2401 / E2501 | 説明変数 |
| 教員配置充実度(中)(%) | 中学校教員数 / 中学校生徒数 × 100 | E3401 / E3501 | 説明変数 |
| 教育費_万円 | 教育費(二人以上の世帯)/ 10000 | L322108 | 説明変数 |
| 高齢化率(%) | 65歳以上人口 / 総人口 × 100 | A1303 / A1101 | 説明変数(統制変数) |
| 消費支出_log | log(消費支出(二人以上の世帯)) | L3221 | 説明変数(経済水準) |
| 変数 | 平均 | 標準偏差 | 最小値 | 最大値 |
|---|---|---|---|---|
| 大学進学率(%) | 56.6 | 7.0 | 46.2 | 73.0 |
| 教員配置充実度_小(%) | 7.52 | 0.89 | 5.77 | 9.38 |
| 教員配置充実度_中(%) | 8.44 | 1.14 | 6.45 | 11.91 |
| 教育費_万円 | 1.06 | 0.43 | 0.55 | 2.80 |
| 高齢化率(%) | 31.4 | 3.3 | 22.8 | 38.6 |
「大学進学率」を学力の代理変数として使う場合、いくつかの重要な限界がある。第一に、進学率は学力だけでなく家庭の経済力・地域の大学へのアクセシビリティ・職業観の地域差にも依存する。第二に、四年制大学と短期大学を区別するかによって結果が変わりうる。代理変数を用いる際は常にその限界を明示することが科学的誠実さの基本である。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | df_raw = pd.read_csv(DATA_B, encoding='cp932', header=1) # 都道府県のみ(地域コードが R + 5桁数字) pref_mask = df_raw['地域コード'].str.match(r'^R\d{5}$', na=False) df_all = df_raw[pref_mask].copy().reset_index(drop=True) # 数値変換 num_cols = [ '総人口', '65歳以上人口', '小学校教員数', '小学校児童数', '中学校教員数', '中学校生徒数', '高等学校卒業者数', '高等学校卒業者のうち進学者数', '教育費(二人以上の世帯)', '消費支出(二人以上の世帯)', ] for c in num_cols: df_all[c] = pd.to_numeric(df_all[c], errors='coerce') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # ── 派生変数を計算 ───────────────────────────────────────────── df_all['大学進学率'] = (df_all['高等学校卒業者のうち進学者数'] / df_all['高等学校卒業者数'] * 100) df_all['教員配置充実度_小'] = (df_all['小学校教員数'] / df_all['小学校児童数'] * 100) df_all['教員配置充実度_中'] = (df_all['中学校教員数'] / df_all['中学校生徒数'] * 100) df_all['教育費_万円'] = df_all['教育費(二人以上の世帯)'] / 10000 df_all['高齢化率'] = df_all['65歳以上人口'] / df_all['総人口'] * 100 df_all['消費支出_log'] = np.log(df_all['消費支出(二人以上の世帯)']) print("=" * 65) print(f"■ 全データ: {len(df_all)}行(47都道府県 × 12年間)") print("=" * 65) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。32 33 34 35 36 37 38 39 40 41 42 43 | # 2022年断面 df2022 = df_all[df_all['年度'] == 2022].copy().reset_index(drop=True) print(f" 2022年データ: {len(df2022)}都道府県") # 欠損除外(2022年) key_vars = ['大学進学率', '教員配置充実度_小', '教員配置充実度_中', '教育費_万円', '高齢化率', '消費支出_log'] df2022_clean = df2022.dropna(subset=key_vars).reset_index(drop=True) N = len(df2022_clean) print(f" 欠損除外後: N={N}都道府県") print() print(df2022_clean[['都道府県'] + key_vars].describe().round(3)) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.describe() — 件数・平均・標準偏差・四分位・最大/最小を一括計算。データの素性チェックに必須。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | # ── 地域ブロック区分(全国6ブロック)──────────────────────────── region_map = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄', } region_order = ['北海道・東北', '関東', '中部', '近畿', '中国・四国', '九州・沖縄'] region_colors = { '北海道・東北': '#1565C0', '関東': '#C62828', '中部': '#2E7D32', '近畿': '#E65100', '中国・四国': '#6A1B9A', '九州・沖縄': '#00838F', } df_all['地域ブロック'] = df_all['都道府県'].map(region_map) df2022_clean['地域ブロック'] = df2022_clean['都道府県'].map(region_map) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。76 77 78 79 80 81 82 83 84 | # ── 時系列用データ(全年度)──────────────────────────────────── df_ts = df_all.dropna(subset=['大学進学率', '地域ブロック']).copy() # ── 相関確認(2022年)──────────────────────────────────────── print("\n■ 2022年 主要変数間の相関(vs 大学進学率)") for v in ['教員配置充実度_小', '教員配置充実度_中', '教育費_万円', '高齢化率', '消費支出_log']: r, p = stats.pearsonr(df2022_clean[v], df2022_clean['大学進学率']) sig = '***' if p < 0.001 else '**' if p < 0.01 else '*' if p < 0.05 else 'n.s.' print(f" {v:<22} r={r:>7.4f} p={p:.4f} {sig}") |
=================================================================
■ 全データ: 564行(47都道府県 × 12年間)
=================================================================
2022年データ: 47都道府県
欠損除外後: N=47都道府県
大学進学率 教員配置充実度_小 教員配置充実度_中 教育費_万円 高齢化率 消費支出_log
count 47.000 47.000 47.000 47.000 47.000 47.000
mean 56.623 7.520 8.445 1.065 31.350 12.574
std 7.006 0.888 1.136 0.434 3.269 0.067
min 46.199 5.772 6.446 0.554 22.810 12.409
25% 50.761 7.093 7.792 0.776 29.847 12.531
50% 56.768 7.338 8.338 0.979 31.421 12.570
75% 61.330 8.044 9.095 1.180 33.720 12.619
max 72.986 9.375 11.911 2.796 38.602 12.691
■ 2022年 主要変数間の相関(vs 大学進学率)
教員配置充実度_小 r=-0.5243 p=0.0002 ***
教員配置充実度_中 r=-0.5919 p=0.0000 ***
教育費_万円 r= 0.4945 p=0.0004 ***
高齢化率 r=-0.5879 p=0.0000 ***
消費支出_log r= 0.4394 p=0.0020 **stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。まず、大学進学率が過去12年間でどのように変化してきたかを地域ブロック別に確認する。地域格差の縮小・拡大トレンドを把握することが、政策評価の出発点となる。
| 地域ブロック | 2012年(参考) | 2022年 | 傾向 |
|---|---|---|---|
| 関東 | 高め | 高め | 一貫して上位 |
| 近畿 | 中程度 | 中程度 | 安定 |
| 中部 | 中程度 | 中程度 | 安定 |
| 北海道・東北 | 低め | 低め | 全国平均以下が継続 |
| 中国・四国 | 低め | 中程度 | やや改善 |
| 九州・沖縄 | 低め | 低め | 格差が持続 |
86 87 88 89 90 91 92 93 94 95 | fig1, ax1 = plt.subplots(figsize=(11, 6)) for region in region_order: df_r = (df_ts[df_ts['地域ブロック'] == region] .groupby('年度')['大学進学率'].mean().sort_index()) if len(df_r) == 0: continue ax1.plot(df_r.index, df_r.values, color=region_colors[region], linewidth=2.0, marker='o', markersize=5, label=region) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | # 全国平均を太破線で重ね書き df_nat = df_ts.groupby('年度')['大学進学率'].mean().sort_index() ax1.plot(df_nat.index, df_nat.values, color='black', linewidth=2.5, linestyle='--', marker='D', markersize=5, label='全国平均', zorder=10) ax1.set_xlabel('年度', fontsize=12) ax1.set_ylabel('大学進学率(%)\n[高校卒業者のうち進学者 / 卒業者 × 100]', fontsize=11) ax1.set_title('大学進学率の地域別推移(2012〜2023年)\n' '6地域ブロック平均値(SSDSE-B実データ)', fontsize=13, fontweight='bold') ax1.legend(fontsize=10, loc='upper left') ax1.grid(True, alpha=0.3) ax1.set_xticks(range(2012, 2024, 2)) plt.tight_layout() fig1_path = os.path.join(FIG_DIR, '2022_H5_9_fig1_timeseries.png') fig1.savefig(fig1_path, bbox_inches='tight', dpi=150) plt.close(fig1) print(f"\n図1保存: {os.path.basename(fig1_path)}") |
図1保存: 2022_H5_9_fig1_timeseries.png
df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。家計が教育に投資する金額(家計の教育費支出)と大学進学率の関係を2022年断面データで散布図により可視化する。教育費は「家計の教育への意欲・能力」を反映する重要な説明変数候補である。
| 説明変数 | 相関係数 r | p値 | 有意性 | 解釈 |
|---|---|---|---|---|
| 教員配置充実度(小) | -0.524 | 0.0002 | *** | 逆説的な負の相関(後述) |
| 教員配置充実度(中) | -0.592 | <0.0001 | *** | 逆説的な負の相関(後述) |
| 教育費_万円 | +0.495 | 0.0004 | *** | 教育費が高い都市部で進学率高 |
| 高齢化率 | -0.588 | <0.0001 | *** | 高齢化地域ほど進学率低 |
| 消費支出_log | +0.439 | 0.0020 | ** | 経済的豊かさと正の相関 |
「教員配置充実度 = 教員数 / 生徒数 × 100」は、よく使われる「生徒1人あたり教員数」の百分率表現である。逆数にあたる「教員1人あたり生徒数」(学級規模の代理)との違いに注意しよう。充実度が高い(数値が大きい)ほど、教員1人が担当する生徒が少なく、手厚い指導が期待できる。
117 118 119 120 121 122 123 124 | fig2, ax2 = plt.subplots(figsize=(12, 8)) for region in region_order: mask = df2022_clean['地域ブロック'] == region ax2.scatter(df2022_clean.loc[mask, '教育費_万円'], df2022_clean.loc[mask, '大学進学率'], color=region_colors[region], s=65, alpha=0.85, label=region, zorder=3) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。125 126 127 128 129 130 | # 都道府県ラベル for _, row in df2022_clean.iterrows(): ax2.annotate(row['都道府県'], (row['教育費_万円'], row['大学進学率']), fontsize=7.5, alpha=0.85, xytext=(3, 3), textcoords='offset points') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | # 単回帰直線 x_vals = df2022_clean['教育費_万円'].values y_vals = df2022_clean['大学進学率'].values z = np.polyfit(x_vals, y_vals, 1) xs = np.linspace(x_vals.min() - 0.05, x_vals.max() + 0.05, 200) ax2.plot(xs, np.poly1d(z)(xs), color='gray', linewidth=1.8, linestyle='--', alpha=0.7, zorder=2) r2, p2 = stats.pearsonr(x_vals, y_vals) ax2.set_xlabel('教育費(万円/月)[家計の二人以上世帯]', fontsize=12) ax2.set_ylabel('大学進学率(%)', fontsize=12) ax2.set_title(f'家計教育費 vs 大学進学率(2022年・47都道府県)\n' f'Pearson r = {r2:.3f}(p = {p2:.4f})', fontsize=13, fontweight='bold') ax2.legend(fontsize=10, loc='lower right') ax2.grid(True, alpha=0.3) plt.tight_layout() fig2_path = os.path.join(FIG_DIR, '2022_H5_9_fig2_scatter.png') fig2.savefig(fig2_path, bbox_inches='tight', dpi=150) plt.close(fig2) print(f"図2保存: {os.path.basename(fig2_path)}") |
図2保存: 2022_H5_9_fig2_scatter.png
stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。相関分析で有意な関連が確認された5変数を同時に投入したOLS重回帰(通常最小二乗法)を実施し、各変数の独立した効果を推定する。複数の変数を同時に考慮することで、交絡因子の影響を統制できる。
| 変数 | 偏回帰係数 | 標準誤差 | p値 | 有意性 |
|---|---|---|---|---|
| 教員配置充実度(小) | +2.12 | 2.48 | 0.397 | n.s. |
| 教員配置充実度(中) | -2.57 | 2.06 | 0.219 | n.s. |
| 教育費_万円 | +2.25 | 2.71 | 0.410 | n.s. |
| 高齢化率 | -0.74 | 0.44 | 0.101 | n.s. |
| 消費支出_log | +14.22 | 16.79 | 0.402 | n.s. |
| モデル全体 | R² = 0.438、F統計量 p = 0.0002(N=47) | |||
SSDSE-B の「教育費(二人以上の世帯)」は家計調査に基づく家計の教育費支出であり、国や自治体が投じる「公教育支出」とは根本的に異なる。家計の教育費には学習塾・習い事・受験料などが含まれ、都市部の富裕世帯ほど高くなる傾向がある。一方、公教育支出は地方交付税などで農村部に手厚く配分される場合もある。この違いを混同すると「教育への投資を増やせば格差が縮小する」という誤った政策解釈につながりかねない。
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 | fig3, ax3 = plt.subplots(figsize=(9, 5)) n_vars = len(ols_varnames) y_pos = np.arange(n_vars) bar_colors = ['#C62828' if p < 0.01 else '#FF8F00' if p < 0.05 else '#9E9E9E' for p in pvals] ax3.barh(y_pos, coefs, color=bar_colors, alpha=0.78, edgecolor='white', height=0.55) ax3.errorbar(coefs, y_pos, xerr=1.96 * ses, fmt='none', color='#333333', capsize=5, linewidth=1.4) ax3.axvline(0, color='gray', linestyle='--', linewidth=1.0) ax3.set_yticks(y_pos) ax3.set_yticklabels(ols_varnames, fontsize=11) ax3.set_xlabel('回帰係数(±1.96×SE)', fontsize=12) ax3.set_title(f'大学進学率(%)の決定要因 — OLS回帰係数\n' f'R² = {ols_model.rsquared:.3f}、N = {N}都道府県(2022年)', fontsize=12, fontweight='bold') ax3.invert_yaxis() ax3.grid(axis='x', alpha=0.3) legend_handles = [ Patch(color='#C62828', alpha=0.78, label='p < 0.01(高有意)'), Patch(color='#FF8F00', alpha=0.78, label='p < 0.05(有意)'), Patch(color='#9E9E9E', alpha=0.78, label='n.s.(非有意)'), ] ax3.legend(handles=legend_handles, fontsize=9, loc='lower right') for i, (c, p) in enumerate(zip(coefs, pvals)): sig = '***' if p < 0.001 else '**' if p < 0.01 else '*' if p < 0.05 else '' if sig: offset = max(abs(coefs)) * 0.03 ax3.text(c + (offset if c >= 0 else -offset), i, sig, va='center', ha='left' if c >= 0 else 'right', fontsize=10, fontweight='bold') plt.tight_layout() fig3_path = os.path.join(FIG_DIR, '2022_H5_9_fig3_coef.png') fig3.savefig(fig3_path, bbox_inches='tight', dpi=150) plt.close(fig3) print(f"図3保存: {os.path.basename(fig3_path)}") |
図3保存: 2022_H5_9_fig3_coef.png
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。教員配置充実度(小学校・中学校)の地域差を箱ひげ図で可視化する。地域ブロック間の中央値・四分位範囲の違いを確認し、教員配置が地域格差の縮小にどう関わりうるかを考察する。
本分析から得られる政策的示唆は、単純に「教員を増やせば進学率が上がる」ではない。重要なのは地域の社会経済的文脈を考慮した総合的なアプローチである。大学進学率の地域格差は、教員配置よりもむしろ「その地域の経済水準・高齢化率・大学へのアクセシビリティ」といった構造的要因に強く規定されている可能性が示された。
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.patches import Patch import statsmodels.api as sm from scipy import stats 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) |
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)。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。215 216 217 218 219 220 221 222 223 224 225 226 | y_ols = df2022_clean['大学進学率'].values ols_varnames = ['教員配置充実度_小', '教員配置充実度_中', '教育費_万円', '高齢化率', '消費支出_log'] X_ols = df2022_clean[ols_varnames].values X_ols_c = sm.add_constant(X_ols) ols_model = sm.OLS(y_ols, X_ols_c).fit() print("\n■ OLS回帰結果(目的変数: 大学進学率)") print(ols_model.summary2()) coefs = ols_model.params[1:] ses = ols_model.bse[1:] pvals = ols_model.pvalues[1:] |
■ OLS回帰結果(目的変数: 大学進学率)
Results: Ordinary least squares
=================================================================
Model: OLS Adj. R-squared: 0.370
Dependent Variable: y AIC: 300.2773
Date: 2026-05-18 11:24 BIC: 311.3781
No. Observations: 47 Log-Likelihood: -144.14
Df Model: 5 F-statistic: 6.392
Df Residuals: 41 Prob (F-statistic): 0.000179
R-squared: 0.438 Scale: 30.946
------------------------------------------------------------------
Coef. Std.Err. t P>|t| [0.025 0.975]
------------------------------------------------------------------
const -95.6123 210.1284 -0.4550 0.6515 -519.9752 328.7507
x1 2.1218 2.4800 0.8555 0.3972 -2.8868 7.1303
x2 -2.5745 2.0639 -1.2474 0.2193 -6.7426 1.5937
x3 2.2504 2.7050 0.8320 0.4103 -3.2124 7.7132
x4 -0.7407 0.4413 -1.6783 0.1009 -1.6320 0.1506
x5 14.2233 16.7854 0.8474 0.4017 -19.6754 48.1220
-----------------------------------------------------------------
Omnibus: 1.184 Durbin-Watson: 1.071
Prob(Omnibus): 0.553 Jarque-Bera (JB): 0.598
Skew: 0.256 Prob(JB): 0.742
Kurtosis: 3.207 Condition No.: 9299
=================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the
errors is correctly specified.
[2] The condition number is large, 9.3e+03. This might indicate
that there are strong multicollinearity or other numerical
problems.sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | fig4, axes4 = plt.subplots(1, 2, figsize=(13, 6), sharey=False) for ax_idx, (var, label) in enumerate( [('教員配置充実度_小', '小学校'), ('教員配置充実度_中', '中学校')]): ax = axes4[ax_idx] box_data = [] box_labels = [] for region in region_order: vals = (df2022_clean.loc[df2022_clean['地域ブロック'] == region, var] .dropna().values) box_data.append(vals) box_labels.append(f'{region}\n(n={len(vals)})') bp = ax.boxplot( box_data, patch_artist=True, notch=False, medianprops=dict(color='black', linewidth=2.0), flierprops=dict(marker='o', markersize=5, alpha=0.6), whiskerprops=dict(linewidth=1.4), capprops=dict(linewidth=1.4), ) for patch, region in zip(bp['boxes'], region_order): patch.set_facecolor(region_colors[region]) patch.set_alpha(0.65) # 全国平均線 nat_mean = df2022_clean[var].mean() ax.axhline(nat_mean, color='black', linestyle='--', linewidth=1.5, label=f'全国平均 {nat_mean:.2f}%') ax.set_xticklabels(box_labels, fontsize=8) ax.set_ylabel(f'教員配置充実度(%)\n[教員数 / 生徒数 × 100]', fontsize=11) ax.set_title(f'{label}の教員配置充実度(2022年)', fontsize=12, fontweight='bold') ax.grid(axis='y', alpha=0.3) ax.legend(fontsize=9) fig4.suptitle('地域別 教員配置充実度の分布(2022年・6地域ブロック)\n' '左: 小学校、右: 中学校(SSDSE-B実データ)', fontsize=13, fontweight='bold', y=1.01) plt.tight_layout() fig4_path = os.path.join(FIG_DIR, '2022_H5_9_fig4_boxplot.png') fig4.savefig(fig4_path, bbox_inches='tight', dpi=150) plt.close(fig4) print(f"図4保存: {os.path.basename(fig4_path)}") |
図4保存: 2022_H5_9_fig4_boxplot.png
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | print("\n" + "=" * 65) print("■ 分析完了サマリー") print("=" * 65) print(f" 全データ行数 : {len(df_all)}(47都道府県 × 12年間)") print(f" 2022年 N : {N}都道府県") print(f" OLS R² : {ols_model.rsquared:.4f}") print(f" OLS Adj.R² : {ols_model.rsquared_adj:.4f}") print(f" OLS F-stat p値 : {ols_model.f_pvalue:.4f}") print() print(" ── 2022年 相関係数 vs 大学進学率 ──") for v in ['教員配置充実度_小', '教員配置充実度_中', '教育費_万円', '高齢化率', '消費支出_log']: r, p = stats.pearsonr(df2022_clean[v], df2022_clean['大学進学率']) sig = '***' if p < 0.001 else '**' if p < 0.01 else '*' if p < 0.05 else 'n.s.' print(f" {v:<22} r={r:>7.4f} {sig}") print() print(" ── OLS 回帰係数(標準化なし)──") for name, c, s, p in zip(ols_varnames, coefs, ses, pvals): sig = '***' if p < 0.001 else '**' if p < 0.01 else '*' if p < 0.05 else 'n.s.' print(f" {name:<22} β={c:>8.4f} SE={s:.4f} {sig}") print() print(" 保存図:") for path in [fig1_path, fig2_path, fig3_path, fig4_path]: print(f" {os.path.basename(path)}") print() print("処理正常終了。合成データは一切使用していません。") |
=================================================================
■ 分析完了サマリー
=================================================================
全データ行数 : 564(47都道府県 × 12年間)
2022年 N : 47都道府県
OLS R² : 0.4381
OLS Adj.R² : 0.3695
OLS F-stat p値 : 0.0002
── 2022年 相関係数 vs 大学進学率 ──
教員配置充実度_小 r=-0.5243 ***
教員配置充実度_中 r=-0.5919 ***
教育費_万円 r= 0.4945 ***
高齢化率 r=-0.5879 ***
消費支出_log r= 0.4394 **
── OLS 回帰係数(標準化なし)──
教員配置充実度_小 β= 2.1218 SE=2.4800 n.s.
教員配置充実度_中 β= -2.5745 SE=2.0639 n.s.
教育費_万円 β= 2.2504 SE=2.7050 n.s.
高齢化率 β= -0.7407 SE=0.4413 n.s.
消費支出_log β= 14.2233 SE=16.7854 n.s.
保存図:
2022_H5_9_fig1_timeseries.png
2022_H5_9_fig2_scatter.png
2022_H5_9_fig3_coef.png
2022_H5_9_fig4_boxplot.png
処理正常終了。合成データは一切使用していません。stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。SSDSE-B の47都道府県データ(2012〜2023年)を用いた学力代理変数(大学進学率)の分析から、以下の知見が得られた。
| データ・資料 | 出典 |
|---|---|
| SSDSE-B 都道府県別統計データ(2012〜2023年) | 統計数理研究所 SSDSE(社会・人口統計体系) |
| 小学校・中学校・高等学校の教員数・生徒数 | 文部科学省 学校基本調査(SSDSE-B 列E2401等に収録) |
| 高等学校卒業者の進学者数 | 文部科学省 学校基本調査(SSDSE-B 列E4601, E4602) |
| 家計の消費支出・教育費(二人以上の世帯) | 総務省 家計調査(SSDSE-B 列L3221, L322108) |
| 人口・高齢化率 | 総務省 人口推計(SSDSE-B 列A1101, A1303) |
本教育用コードは SSDSE-B-2026.csv の実データのみを使用しています(合成データ・np.random.seed() の使用なし)。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。