このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
「体力」と「基礎学力」はどのような関係にあるのか。全国体力・運動能力調査や全国学力・学習状況調査の都道府県別集計データは、体力指数と学力スコアの間に一定の正の相関があることを示唆している。本研究はこの関係を統計的に検証し、背景にある教育環境要因を明らかにしようとしたものである。
まず「体力と基礎学力の関係都道府県別教育指標の相関・回帰分析」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
教育データ分析では「体力」「学力」を直接測定した都道府県別統計が常に利用可能とは限らない。そのため、本教育用再現コードでは SSDSE-B(都道府県別統計体系データ) に含まれる教育関連指標(教育費・師弟比・保育所密度・進学率等)を代理変数として用い、同様の分析フレームワークを適用している。
相関分析 OLS回帰 Ward法クラスタリング 散布図 SSDSE-B
使用データは SSDSE-B-2026.csv(社会・人口統計体系、都道府県別パネルデータ)の2022年度分、47都道府県。
| 変数名 | 計算式 | 単位 | 想定する役割 |
|---|---|---|---|
| 大学進学率 | 高等学校卒業者のうち進学者数 / 高等学校卒業者数 × 100 | % | 目的変数(学力・教育成果の代理) |
| 教育費_万円 | 教育費(二人以上の世帯)/ 10,000 | 万円/月 | 家庭の教育投資水準 |
| 師弟比_小学 | 小学校児童数 / 小学校教員数 | 児童/教員 | 小学校の教育環境(少ないほど良い) |
| 師弟比_中学 | 中学校生徒数 / 中学校教員数 | 生徒/教員 | 中学校の教育環境 |
| 保育所密度 | 保育所等数 / 総人口 × 10,000 | 箇所/万人 | 就学前教育・子育て支援環境 |
| 高齢化率 | 65歳以上人口 / 総人口 × 100 | % | 地域の人口構造(若年人口の少なさ) |
| 変数 | 平均 | 標準偏差 | 最小 | 最大 |
|---|---|---|---|---|
| 大学進学率(%) | 約 57 | 約 9 | 約 40 | 約 77 |
| 教育費_万円 | 約 1.1 | 約 0.3 | 約 0.6 | 約 2.0 |
| 師弟比_小学(人) | 約 14 | 約 1.5 | 約 11 | 約 17 |
| 師弟比_中学(人) | 約 13 | 約 1.2 | 約 10 | 約 15 |
| 保育所密度(箇所/万人) | 約 5 | 約 2 | 約 2 | 約 11 |
| 高齢化率(%) | 約 30 | 約 4 | 約 22 | 約 38 |
※ 記述統計の数値は実データから自動計算(SSDSE-B-2026 の 2022年度 47都道府県より)
DS POINT 1理想的なデータが手元にない場合、分析者は代理変数(proxy variable)を設計する。 代理変数は「本来測りたい概念」と相関が高いと合理的に期待される別の変数であり、 設計の妥当性は以下の観点から評価する。
【代理変数の評価基準】
1. 概念的妥当性:理論的に関連が期待できるか
2. 相関的妥当性:実際に本来変数と相関するか(検証可能な場合)
3. 測定誤差:代理変数自体に固有の誤差がないか
4. 解釈上の限界:結論を述べる際に代理変数の限界を明記しているか
複数の教育指標の間にどのような相関関係が存在するかを俯瞰するために、Pearson相関係数のヒートマップを作成する。これは多変量回帰分析の前段として重要な探索的分析ステップである。
| 変数ペア | 相関の方向 | 解釈 |
|---|---|---|
| 大学進学率 ↔ 教育費 | 正 | 家庭の教育投資が多いほど進学率が高い傾向 |
| 大学進学率 ↔ 高齢化率 | 負 | 高齢化が進む県ほど進学率が低い(若年層の少なさと関連) |
| 大学進学率 ↔ 保育所密度 | 負 | 都市部より農村部に保育所が多く分布する逆説的関係 |
| 師弟比_小学 ↔ 師弟比_中学 | 強い正 | 小中の教育環境は地域で連動する(多重共線性に注意) |
| 保育所密度 ↔ 高齢化率 | 正 | 過疎・高齢化県では保育所の人口あたり数が多くなる |
相関係数 r が「偶然ゼロと異なる」かどうかを検定するには t 統計量を使う。 N=47 では自由度 45 の t 分布を用い、|t| > 2.01 程度で p < 0.05 となる。 また Fisher の z 変換で 95% 信頼区間も求めることができる。
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 | import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from sklearn.preprocessing import StandardScaler from scipy.cluster.hierarchy import dendrogram, linkage from scipy import stats import statsmodels.api as sm 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_2022 = df_b[df_b['年度'] == 2022].copy() |
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) — 列を整数に変換(年度などを数値比較するため)。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 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 76 77 78 | # 変数生成 df_2022['大学進学率'] = df_2022['高等学校卒業者のうち進学者数'] / df_2022['高等学校卒業者数'].replace(0, np.nan) * 100 df_2022['教育費_万円'] = df_2022['教育費(二人以上の世帯)'] / 10000 df_2022['師弟比_小学'] = df_2022['小学校児童数'] / df_2022['小学校教員数'].replace(0, np.nan) df_2022['師弟比_中学'] = df_2022['中学校生徒数'] / df_2022['中学校教員数'].replace(0, np.nan) df_2022['保育所密度'] = df_2022['保育所等数'] / df_2022['総人口'] * 10000 df_2022['高齢化率'] = df_2022['65歳以上人口'] / df_2022['総人口'] * 100 df_2022['消費支出_log'] = np.log(df_2022['消費支出(二人以上の世帯)'].clip(lower=1)) region_map = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄', } df_2022['地域'] = df_2022['都道府県'].map(region_map) region_colors = { '北海道・東北': '#4e9af1', '関東': '#e05c5c', '中部': '#f0a500', '近畿': '#5cb85c', '中国・四国': '#9b59b6', '九州・沖縄': '#f39c12', } analysis_vars = ['大学進学率', '教育費_万円', '師弟比_小学', '師弟比_中学', '保育所密度', '高齢化率'] df_corr = df_2022[analysis_vars].dropna() corr = df_corr.corr() fig, ax = plt.subplots(figsize=(8, 6)) im = ax.imshow(corr, cmap='RdBu_r', vmin=-1, vmax=1) ax.set_xticks(range(len(analysis_vars))) ax.set_yticks(range(len(analysis_vars))) ax.set_xticklabels(analysis_vars, rotation=45, ha='right', fontsize=9) ax.set_yticklabels(analysis_vars, fontsize=9) for i in range(len(analysis_vars)): for j in range(len(analysis_vars)): val = corr.iloc[i, j] ax.text(j, i, f'{val:.2f}', ha='center', va='center', fontsize=8, color='white' if abs(val) > 0.5 else 'black') plt.colorbar(im, ax=ax, label='Pearson相関係数') ax.set_title('教育指標間の相関ヒートマップ(2022年, N=47)', fontsize=13, fontweight='bold') plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_H1_fig1_corr.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig1 saved") |
Fig1 saved
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。相関ヒートマップで確認された「教育費と大学進学率の正の相関」を地域別に可視化する。散布図は相関の方向性・外れ値・地域パターンを同時に読み取ることができる。
| 地域 | 教育費の傾向 | 大学進学率の傾向 | 特徴 |
|---|---|---|---|
| 関東(赤) | 高い | 高い | 東京・神奈川等の都市部が牽引 |
| 近畿(緑) | やや高い | やや高い | 京都・大阪等の大学集積地 |
| 北海道・東北(青) | 低い | 低い | 農村部多く、経済的制約 |
| 九州・沖縄(橙) | 低い | 中程度 | 沖縄は特殊(進学率低め) |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | df_sc = df_2022[['都道府県', '教育費_万円', '大学進学率', '地域']].dropna() fig, ax = plt.subplots(figsize=(9, 6)) for reg, grp in df_sc.groupby('地域'): ax.scatter(grp['教育費_万円'], grp['大学進学率'], color=region_colors.get(reg, 'gray'), label=reg, s=70, alpha=0.8) for _, row in df_sc.iterrows(): ax.annotate(row['都道府県'][:2], (row['教育費_万円'], row['大学進学率']), fontsize=7, alpha=0.7, xytext=(3, 3), textcoords='offset points') slope, intercept, r, p, _ = stats.linregress(df_sc['教育費_万円'], df_sc['大学進学率']) xr = np.linspace(df_sc['教育費_万円'].min(), df_sc['教育費_万円'].max(), 100) ax.plot(xr, slope * xr + intercept, 'k--', linewidth=1.5, label=f'回帰直線 (r={r:.2f}, p={p:.3f})') ax.set_xlabel('教育費(万円/月)', fontsize=12) ax.set_ylabel('大学進学率(%)', fontsize=12) ax.set_title('教育費 vs 大学進学率(2022年, N=47)', fontsize=13, fontweight='bold') ax.legend(fontsize=8, ncol=2) ax.grid(alpha=0.3) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_H1_fig2_scatter.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig2 saved") |
Fig2 saved
df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。stats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。複数の教育指標を同時に投入した多変量OLS回帰(最小二乗法)で、大学進学率の決定要因を推定する。各変数を標準化した「標準化回帰係数(β係数)」を用いることで、異なる単位・スケールの変数間で効果の大きさを比較できる。
| 変数 | β係数(標準化) | p値 | 有意性 | 解釈 |
|---|---|---|---|---|
| 教育費_万円 | 正(小~中) | ~ 0.36 | n.s. | 他の変数を統制すると有意でなくなる |
| 師弟比_小学 | 負(小) | ~ 0.25 | n.s. | 単独では効果が見えにくい |
| 師弟比_中学 | 正(小) | ~ 0.22 | n.s. | 小学師弟比と相関(多重共線性) |
| 保育所密度 | 負(中) | < 0.05 | * | 過疎・農村地域と強く連動 |
| 高齢化率 | 負(中) | ~ 0.09 | n.s.* | 高齢化 → 教育資源の競合 |
※ 係数・p値は実データの分析結果(SSDSE-B 2022年度)。モデル全体: R²=0.533, F検定 p < 0.001
OLS の非標準化係数は「Xが1単位変化したときのyの変化量」だが、 単位が異なる変数(万円 vs % vs 人)を直接比較することはできない。 標準化係数(β)は全変数を標準化(平均0・標準偏差1)してから回帰した係数であり、 「どの変数が最も強く y に影響するか」を同一スケールで比較できる。
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 | xvars = ['教育費_万円', '師弟比_小学', '師弟比_中学', '保育所密度', '高齢化率'] df_reg = df_2022[['大学進学率'] + xvars].dropna() X = sm.add_constant(df_reg[xvars]) res = sm.OLS(df_reg['大学進学率'], X).fit() print(res.summary()) # 標準化係数 from sklearn.preprocessing import StandardScaler as SS sc = SS() X_std = pd.DataFrame(sc.fit_transform(df_reg[xvars]), columns=xvars) y_arr = df_reg['大学進学率'].values y_std = pd.Series((y_arr - y_arr.mean()) / y_arr.std()) res_std = sm.OLS(y_std, sm.add_constant(X_std)).fit() fig, ax = plt.subplots(figsize=(8, 5)) coefs = res_std.params.drop('const') ses = res_std.bse.drop('const') pvals = res.pvalues.drop('const') colors_c = ['#e05c5c' if p < 0.05 else '#888888' for p in pvals] ax.barh(range(len(coefs)), coefs, xerr=1.96 * ses, color=colors_c, alpha=0.8, error_kw={'elinewidth': 1.5, 'capsize': 4}) ax.set_yticks(range(len(coefs))) ax.set_yticklabels(coefs.index, fontsize=10) ax.axvline(0, color='black', linewidth=0.8) ax.set_xlabel('標準化回帰係数(β)', fontsize=12) ax.set_title(f'大学進学率の決定要因(標準化OLS, N=47)\nR²={res.rsquared:.3f}(赤=p<0.05)', fontsize=12, fontweight='bold') ax.grid(axis='x', alpha=0.3) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_H1_fig3_ols.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig3 saved") |
OLS Regression Results
==============================================================================
Dep. Variable: 大学進学率 R-squared: 0.533
Model: OLS Adj. R-squared: 0.476
Method: Least Squares F-statistic: 9.368
Date: Mon, 18 May 2026 Prob (F-statistic): 5.19e-06
Time: 11:24:01 Log-Likelihood: -139.78
No. Observations: 47 AIC: 291.6
Df Residuals: 41 BIC: 302.7
Df Model: 5
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 83.8532 26.064 3.217 0.003 31.216 136.491
教育費_万円 2.0644 2.217 0.931 0.357 -2.414 6.543
師弟比_小学 -1.5796 1.343 -1.176 0.246 -4.292 1.133
師弟比_中学 1.9672 1.591 1.236 0.223 -1.246 5.181
保育所密度 -3.2069 1.329 -2.412 0.020 -5.892 -0.522
高齢化率 -0.7330 0.425 -1.725 0.092 -1.591 0.125
==============================================================================
Omnibus: 1.950 Durbin-Watson: 1.463
Prob(Omnibus): 0.377 Jarque-Bera (JB): 1.738
Skew: 0.459 Prob(JB): 0.419
Kurtosis: 2.791 Cond. No. 1.28e+03
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.28e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
Fig3 savedimport pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。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() でメモリ解放。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。回帰分析では「平均的な効果」しか把握できないが、Ward法クラスタリングでは教育環境が似た都道府県をグループ化することで、地域類型を発見できる。政策立案においては、同じグループ内の成功事例が参考になる。
| 手法 | 距離基準 | 特徴 | 適切な場面 |
|---|---|---|---|
| Ward法 | クラスタ内分散の増加量を最小化 | コンパクトで均等なクラスタ。最もよく使われる | 本分析のような多変数・小N |
| 完全連結法 | クラスタ間の最大距離 | コンパクトなクラスタ、外れ値に敏感 | 均等サイズのクラスタを作りたい場合 |
| 単連結法 | クラスタ間の最小距離 | 鎖効果が生じやすい | 非球状クラスタの検出 |
| k-means法 | ユークリッド距離 | クラスタ数 k を事前に指定 | 大規模データ・クラスタ数が既知 |
Ward法は scipy.cluster.hierarchy.linkage(X, method='ward') で実装できる。
最適クラスタ数の決定には エルボー法(距離の急激な変化点を探す)や
デンドログラムの目視確認が使われる。
クラスタリング後は各グループの特徴をプロファイル比較で解釈する。
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | cluster_vars = ['大学進学率', '教育費_万円', '師弟比_小学', '保育所密度', '高齢化率'] df_clust = df_2022[['都道府県'] + cluster_vars].dropna().set_index('都道府県') scaler = StandardScaler() X_sc = scaler.fit_transform(df_clust) Z = linkage(X_sc, 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_H1_fig4_cluster.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig4 saved") print("All done!") |
Fig4 saved All done!
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。SSDSE-B 2022年度の47都道府県データを用い、教育関連指標の相関・OLS回帰・クラスタリングを行った結果:
| データ・資料 | 出典・説明 |
|---|---|
| SSDSE-B-2026.csv(都道府県別データ) | 統計数理研究所 SSDSE(社会・人口統計体系)— 都道府県別パネルデータ |
| 全国体力・運動能力・運動習慣等調査 | 文部科学省 — 都道府県別体力合計点(元論文の主要データ) |
| 全国学力・学習状況調査 | 文部科学省・国立教育政策研究所 — 都道府県別正答率(元論文の主要データ) |
本教育用コードは SSDSE-B-2026.csv の実データのみを使用(合成データ・乱数生成を一切使用しない)。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。