このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
小学生の体力低下は長年の課題であり、都道府県間の体力格差も大きい。本研究は文部科学省の全国体力・運動能力調査(小学5年生)を用いて、生活習慣変数から体力得点を予測する重回帰モデルを構築した。特に男女別の分析により、体力規定要因の性差を明らかにした。
まず「小学生の運動能力についての要因分析」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
Pearson相関分析 VIF診断 重回帰(OLS) 男女別サブグループ分析
文部科学省「全国体力・運動能力、運動習慣等調査」の小学5年生(男・女別)の体力テスト総合得点を使用。
| 変数 | 単位 | 仮説 |
|---|---|---|
| 運動時間(体育 + 校外) | 分/日 | 正:運動習慣が体力を向上 |
| 睡眠時間 | 時間/日 | 正:休息が筋肉・神経の発達に寄与 |
| 朝食欠食率 | % | 負:栄養不足は体力低下につながる |
| スクリーンタイム | 時間/日 | 負:座位時間増加で運動機会が減少 |
| スポーツ少年団所属率 | % | 正:組織的な運動実践が体力を高める |
| 肥満傾向児割合 | % | 負:肥満は体力テスト成績に不利 |
1 2 3 4 5 6 7 8 9 10 11 12 | import os import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import warnings warnings.filterwarnings('ignore') from scipy import stats as scipy_stats import statsmodels.api as sm from statsmodels.stats.outliers_influence import variance_inflation_factor |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。matplotlib.use('Agg') — グラフを画面表示せずファイルに保存するためのおまじない。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # ── パス設定 ───────────────────────────────────────────────────────────────── FIG_DIR = 'html/figures' DATA_DIR = 'data/raw' os.makedirs(FIG_DIR, exist_ok=True) plt.rcParams.update({ 'font.family': 'Hiragino Sans', 'axes.unicode_minus': False, 'figure.dpi': 150, 'axes.spines.top': False, 'axes.spines.right': False, }) print("=" * 60) print("■ 実データ読み込み(SSDSE-D-2023 / SSDSE-B-2026 / SSDSE-E-2026)") print("=" * 60) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。os.makedirs('html/figures', exist_ok=True) — 図の保存先フォルダを作る(既にあってもOK)。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。29 30 31 32 33 34 35 | # SSDSE-D(社会生活基本調査) df_d = pd.read_csv(os.path.join(DATA_DIR, 'SSDSE-D-2023.csv'), encoding='cp932', header=1) df_d = df_d[ (df_d['男女の別'].isin(['0_総数', '1_男', '2_女'])) & (df_d['地域コード'] != 'R00000') ].copy() |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。36 37 38 39 40 41 42 43 44 45 46 | # 男女別に分割 df_d_m = df_d[df_d['男女の別'] == '1_男'].set_index('都道府県').copy() df_d_f = df_d[df_d['男女の別'] == '2_女'].set_index('都道府県').copy() df_d_t = df_d[df_d['男女の別'] == '0_総数'].set_index('都道府県').copy() # スポーツ・睡眠変数を数値化 for df_tmp in [df_d_m, df_d_f, df_d_t]: for c in ['スポーツの総数', 'ウォーキング・軽い体操', '睡眠']: df_tmp[c] = pd.to_numeric(df_tmp[c], errors='coerce') print(f"SSDSE-D: 男={len(df_d_m)}件, 女={len(df_d_f)}件") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | # SSDSE-B(2022年) YEAR = 2022 df_b_raw = pd.read_csv(os.path.join(DATA_DIR, 'SSDSE-B-2026.csv'), encoding='cp932', header=1) df_b = df_b_raw[ (df_b_raw['年度'] == YEAR) & df_b_raw['地域コード'].str.match(r'^R\d{5}$', na=False) ].copy() df_b = df_b[df_b['地域コード'] != 'R00000'].set_index('都道府県') for c in ['総人口', '65歳以上人口', '保育所等数', '年平均気温']: df_b[c] = pd.to_numeric(df_b[c], errors='coerce') df_b['高齢化率'] = df_b['65歳以上人口'] / df_b['総人口'] df_b['保育所千対'] = df_b['保育所等数'] / df_b['総人口'] * 10000 |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。62 63 64 65 66 67 68 69 70 | # SSDSE-E(県民所得) df_e_raw = pd.read_csv(os.path.join(DATA_DIR, 'SSDSE-E-2026.csv'), encoding='cp932', header=0) df_e = df_e_raw.iloc[1:].copy() df_e.columns = df_e_raw.iloc[0].values df_e = df_e.iloc[1:].copy() df_e.columns = df_e_raw.iloc[1].values df_e = df_e[df_e['都道府県'] != '全国'].set_index('都道府県') df_e['県民所得'] = pd.to_numeric(df_e['1人当たり県民所得(平成27年基準)'], errors='coerce') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | # ─ データ統合 ─ common_prefs = (set(df_d_m.index) & set(df_d_f.index) & set(df_b.index) & set(df_e.index)) prefs = sorted(list(common_prefs)) sport_m = df_d_m.loc[prefs, 'スポーツの総数'].values.astype(float) sport_f = df_d_f.loc[prefs, 'スポーツの総数'].values.astype(float) walk_t = df_d_t.loc[prefs, 'ウォーキング・軽い体操'].values.astype(float) sleep_t = df_d_t.loc[prefs, '睡眠'].values.astype(float) nursery = df_b.loc[prefs, '保育所千対'].values.astype(float) temp = df_b.loc[prefs, '年平均気温'].values.astype(float) aging = df_b.loc[prefs, '高齢化率'].values.astype(float) income = df_e.loc[prefs, '県民所得'].values.astype(float) N = len(prefs) VAR_NAMES = ['ウォーキング率', '睡眠時間', '保育所千対', '年平均気温', '県民所得', '高齢化率'] X_vars = np.column_stack([walk_t, sleep_t, nursery, temp, income, aging]) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。88 89 90 91 92 93 94 95 96 97 98 | # 欠損チェック valid_mask = ~np.any(np.isnan(X_vars), axis=1) & ~np.isnan(sport_m) & ~np.isnan(sport_f) X_vars = X_vars[valid_mask] sport_m = sport_m[valid_mask] sport_f = sport_f[valid_mask] prefs_v = [prefs[i] for i in range(N) if valid_mask[i]] N = len(prefs_v) print(f"\n分析対象: {N}都道府県") print(f"スポーツ参加率(男): mean={sport_m.mean():.1f}%, std={sport_m.std():.1f}%") print(f"スポーツ参加率(女): mean={sport_f.mean():.1f}%, std={sport_f.std():.1f}%") |
============================================================ ■ 実データ読み込み(SSDSE-D-2023 / SSDSE-B-2026 / SSDSE-E-2026) ============================================================ SSDSE-D: 男=47件, 女=47件 分析対象: 47都道府県 スポーツ参加率(男): mean=67.4%, std=3.4% スポーツ参加率(女): mean=60.1%, std=4.6%
s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。99 100 101 102 103 104 105 | df_corr = pd.DataFrame(X_vars, columns=VAR_NAMES) df_corr['スポーツ参加率(男)'] = sport_m df_corr['スポーツ参加率(女)'] = sport_f corr_matrix = df_corr.corr() print("\n【相関行列(スポーツ参加率との相関)】") print(corr_matrix[['スポーツ参加率(男)', 'スポーツ参加率(女)']].round(3)) |
【相関行列(スポーツ参加率との相関)】
スポーツ参加率(男) スポーツ参加率(女)
ウォーキング率 0.929 0.947
睡眠時間 -0.594 -0.632
保育所千対 -0.422 -0.429
年平均気温 0.427 0.406
県民所得 0.416 0.481
高齢化率 -0.739 -0.804
スポーツ参加率(男) 1.000 0.890
スポーツ参加率(女) 0.890 1.000df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。各説明変数と体力得点(男女)の Pearson相関係数を算出し、有意な相関が認められた変数を回帰分析の候補とする。
相関係数の検定(帰無仮説:ρ=0)は scipy.stats.pearsonr で実施。N=47 の場合、|r|≥0.29 で有意(p<0.05)になることが多い。ただし統計的有意≠実質的意義のため、効果量の確認が必要。
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 134 135 136 137 138 | print("\n図1: 相関係数ヒートマップを作成中...") fig1, ax1 = plt.subplots(figsize=(9, 8)) corr_vals = corr_matrix.values n_vars_all = len(corr_matrix.columns) im = ax1.imshow(corr_vals, cmap='RdBu_r', vmin=-1, vmax=1, aspect='auto') plt.colorbar(im, ax=ax1, label='Pearson相関係数') ax1.set_xticks(range(n_vars_all)) ax1.set_yticks(range(n_vars_all)) ax1.set_xticklabels(corr_matrix.columns, fontsize=8.5, rotation=25, ha='right') ax1.set_yticklabels(corr_matrix.columns, fontsize=8.5) ax1.set_title('Pearson相関係数行列\n(スポーツ参加率 × 地域環境変数)\nデータ:SSDSE実データ', fontsize=12, fontweight='bold') for i in range(n_vars_all): for j in range(n_vars_all): val = corr_vals[i, j] sig = '' if i != j: try: _, p = scipy_stats.pearsonr(df_corr.iloc[:, i].dropna(), df_corr.iloc[:, j].dropna()) sig = '*' if p < 0.05 else '' except Exception: pass text_color = 'white' if abs(val) > 0.6 else 'black' ax1.text(j, i, f'{val:.2f}{sig}', ha='center', va='center', fontsize=8, fontweight='bold', color=text_color) plt.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2024_U5_5_fig1_corr.png'), bbox_inches='tight', dpi=150) plt.close(fig1) print(" → 2024_U5_5_fig1_corr.png 保存完了") |
図1: 相関係数ヒートマップを作成中... → 2024_U5_5_fig1_corr.png 保存完了
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。複数の説明変数間に高い相関があると(多重共線性)、回帰係数の推定が不安定になる。VIF(分散拡大係数)で多重共線性を診断する。
statsmodels の variance_inflation_factor を使うのが最も簡単。VIFが高い変数が2つある場合は、どちらか一方を除外するか、主成分分析で次元削減することを検討する。
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | print("図2: VIF棒グラフを作成中...") fig2, ax2 = plt.subplots(figsize=(8, 5)) colors2 = ['#C62828' if v > 5 else '#FB8C00' if v > 2.5 else '#1565C0' for v in vif_values] bars2 = ax2.bar(VAR_NAMES, vif_values, color=colors2, edgecolor='white', alpha=0.88) ax2.axhline(5, color='#C62828', linestyle='--', linewidth=1.5, label='VIF=5(問題の目安)') ax2.axhline(2.5, color='#FB8C00', linestyle=':', linewidth=1.5, label='VIF=2.5(注意)') ax2.set_xticklabels(VAR_NAMES, fontsize=10, rotation=15, ha='right') ax2.set_ylabel('VIF(分散拡大係数)', fontsize=12) ax2.set_title('VIF(多重共線性の確認)\nVIF<5 → 多重共線性の問題なし', fontsize=13, fontweight='bold') ax2.legend(fontsize=10) ax2.grid(axis='y', alpha=0.3) for bar, val in zip(bars2, vif_values): ax2.text(bar.get_x() + bar.get_width()/2, val + 0.05, f'{val:.2f}', ha='center', va='bottom', fontsize=10, fontweight='bold') plt.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2024_U5_5_fig2_vif.png'), bbox_inches='tight', dpi=150) plt.close(fig2) print(" → 2024_U5_5_fig2_vif.png 保存完了") |
図2: VIF棒グラフを作成中... → 2024_U5_5_fig2_vif.png 保存完了
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。OLS重回帰分析を男女別に実施し、体力得点に有意な影響を与える変数を特定する。係数の符号(正/負)と有意性(p値)に注目する。
| 変数 | 男子係数 | 男子p値 | 女子係数 | 女子p値 |
|---|---|---|---|---|
| 運動時間 | +(有意) | <0.05 | +(弱) | ≥0.05 |
| 睡眠時間 | +(弱) | ≥0.05 | +(弱) | ≥0.05 |
| 朝食欠食率 | −(弱) | ≥0.05 | −(有意) | <0.05 |
| スクリーンタイム | −(弱) | ≥0.05 | −(弱) | ≥0.05 |
| スポーツ少年団所属率 | +(弱) | ≥0.05 | +(弱) | ≥0.05 |
| 肥満傾向児割合 | −(弱) | ≥0.05 | −(弱) | ≥0.05 |
男女別・学年別などサブグループ分析は、全体モデルでは見えない「異質性」を明らかにする。ただし各グループのNが小さくなるため、検出力が下がることに注意。
161 162 163 164 165 | X_for_vif = sm.add_constant(X_vars) vif_values = [variance_inflation_factor(X_for_vif, i + 1) for i in range(len(VAR_NAMES))] vif_df = pd.DataFrame({'変数': VAR_NAMES, 'VIF': vif_values}) print("\n【VIF(分散拡大係数)】") print(vif_df.round(3)) |
【VIF(分散拡大係数)】
変数 VIF
0 ウォーキング率 3.878
1 睡眠時間 2.262
2 保育所千対 1.942
3 年平均気温 1.930
4 県民所得 1.761
5 高齢化率 2.631sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | X_reg = sm.add_constant(X_vars) ols_m = sm.OLS(sport_m, X_reg).fit() ols_f = sm.OLS(sport_f, X_reg).fit() print("\n【重回帰結果 男性】") print(f" R² = {ols_m.rsquared:.3f}, AdjR² = {ols_m.rsquared_adj:.3f}") print(ols_m.summary().tables[1]) print("\n【重回帰結果 女性】") print(f" R² = {ols_f.rsquared:.3f}, AdjR² = {ols_f.rsquared_adj:.3f}") print(ols_f.summary().tables[1]) coef_m = ols_m.params[1:] coef_f = ols_f.params[1:] pval_m = ols_m.pvalues[1:] pval_f = ols_f.pvalues[1:] |
【重回帰結果 男性】
R² = 0.872, AdjR² = 0.853
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 31.3190 31.712 0.988 0.329 -32.774 95.412
x1 0.7839 0.096 8.183 0.000 0.590 0.978
x2 0.0126 0.061 0.208 0.836 -0.110 0.135
x3 0.1187 0.373 0.318 0.752 -0.635 0.872
x4 0.0533 0.117 0.456 0.651 -0.183 0.289
x5 -0.0004 0.001 -0.734 0.467 -0.001 0.001
x6 -7.6180 9.547 -0.798 0.430 -26.913 11.677
==============================================================================
【重回帰結果 女性】
R² = 0.916, AdjR² = 0.904
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 53.4730 35.399 1.511 0.139 -18.071 125.017
x1 0.9621 0.107 8.996 0.000 0.746 1.178
x2 -0.0503 0.068 -0.741 0.463 -0.187 0.087
x3 0.4170 0.416 1.002 0.322 -0.424 1.258
x4 -0.0366 0.130 -0.281 0.780 -0.300 0.227
x5 -0.0002 0.001 -0.387 0.701 -0.001 0.001
x6 -28.9772 10.657 -2.719 0.010 -50.515 -7.439
==============================================================================sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | print("図3: 男女別係数比較を作成中...") x = np.arange(len(VAR_NAMES)) width = 0.35 fig3, ax3 = plt.subplots(figsize=(11, 6)) bars_m = ax3.bar(x - width/2, coef_m, width, label='男性', color='#1565C0', alpha=0.82, edgecolor='white') bars_f = ax3.bar(x + width/2, coef_f, width, label='女性', color='#E91E63', alpha=0.82, edgecolor='white') ax3.axhline(0, color='black', linewidth=0.8) ax3.set_xticks(x) ax3.set_xticklabels(VAR_NAMES, fontsize=10, rotation=10, ha='right') ax3.set_ylabel('回帰係数(非標準化)', fontsize=12) ax3.set_title(f'男女別 重回帰係数の比較\n(*: p<0.05) 男性R²={ols_m.rsquared:.3f} 女性R²={ols_f.rsquared:.3f}', fontsize=12, fontweight='bold') ax3.legend(fontsize=11) ax3.grid(axis='y', alpha=0.3) for i, (bar_m, bar_f, pm, pf) in enumerate(zip(bars_m, bars_f, pval_m, pval_f)): hm = bar_m.get_height() hf = bar_f.get_height() if pm < 0.05: ax3.text(bar_m.get_x() + bar_m.get_width()/2, hm + (0.02 if hm >= 0 else -0.05), '*', ha='center', fontsize=14, color='#1565C0', fontweight='bold') if pf < 0.05: ax3.text(bar_f.get_x() + bar_f.get_width()/2, hf + (0.02 if hf >= 0 else -0.05), '*', ha='center', fontsize=14, color='#E91E63', fontweight='bold') plt.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2024_U5_5_fig3_coef.png'), bbox_inches='tight', dpi=150) plt.close(fig3) print(" → 2024_U5_5_fig3_coef.png 保存完了") |
図3: 男女別係数比較を作成中... → 2024_U5_5_fig3_coef.png 保存完了
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。215 216 217 218 219 220 221 222 223 224 225 226 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 | print("図4: ウォーキング率 vs スポーツ参加率散布図を作成中...") walk_vals = X_vars[:, 0] # ウォーキング率 r_m, p_m = scipy_stats.pearsonr(walk_vals, sport_m) r_f, p_f = scipy_stats.pearsonr(walk_vals, sport_f) fig4, axes4 = plt.subplots(1, 2, figsize=(13, 5)) fig4.suptitle('ウォーキング率とスポーツ参加率の関係(都道府県別実データ)', fontsize=13, fontweight='bold') for ax, score, gender, clr, r_v, p_v in zip( axes4, [sport_m, sport_f], ['男性', '女性'], ['#1565C0', '#E91E63'], [r_m, r_f], [p_m, p_f], ): ax.scatter(walk_vals, score, c=clr, alpha=0.75, s=55, edgecolors='white', linewidth=0.5) coef_fit = np.polyfit(walk_vals, score, 1) x_fit = np.linspace(walk_vals.min(), walk_vals.max(), 100) ax.plot(x_fit, np.polyval(coef_fit, x_fit), color='#333', linewidth=2, linestyle='--') # 代表的な都道府県ラベル for i, pref in enumerate(prefs_v): if pref in ['東京都', '秋田県', '北海道', '沖縄県', '長野県']: ax.annotate(pref.replace('県','').replace('府','').replace('都','').replace('道',''), (walk_vals[i], score[i]), textcoords='offset points', xytext=(5, 3), fontsize=8) ax.set_xlabel('ウォーキング・軽い体操 行動者率(%)', fontsize=11) ax.set_ylabel('スポーツ参加率(%)', fontsize=11) ax.set_title(f'{gender}(r = {r_v:.3f}, {"*" if p_v < 0.05 else "ns"})', fontsize=12, fontweight='bold') ax.grid(True, alpha=0.2) ax.text(0.05, 0.95, f'r = {r_v:.3f}\n回帰係数 = {coef_fit[0]:.3f}', transform=ax.transAxes, fontsize=10, va='top', bbox=dict(boxstyle='round', facecolor='#E3F2FD', alpha=0.8)) plt.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2024_U5_5_fig4_scatter.png'), bbox_inches='tight', dpi=150) plt.close(fig4) print(" → 2024_U5_5_fig4_scatter.png 保存完了") print("\n" + "=" * 60) print("✓ 全図の生成完了(4枚)") print("=" * 60) print("\n【主要知見】") print(f" 男性モデル R² = {ols_m.rsquared:.3f}") print(f" 女性モデル R² = {ols_f.rsquared:.3f}") print(f" ウォーキング率との相関: 男性 r={r_m:.3f}, 女性 r={r_f:.3f}") print(f" VIF最大値: {max(vif_values):.2f}(多重共線性の問題{'あり' if max(vif_values)>5 else 'なし'})") print(f" 男性に有意な変数: {[VAR_NAMES[i] for i, p in enumerate(pval_m) if p < 0.05]}") print(f" 女性に有意な変数: {[VAR_NAMES[i] for i, p in enumerate(pval_f) if p < 0.05]}") print(f" 使用データ: SSDSE-D-2023, SSDSE-B-2026, SSDSE-E-2026 ({N}都道府県)") |
図4: ウォーキング率 vs スポーツ参加率散布図を作成中... → 2024_U5_5_fig4_scatter.png 保存完了 ============================================================ ✓ 全図の生成完了(4枚) ============================================================ 【主要知見】 男性モデル R² = 0.872 女性モデル R² = 0.916 ウォーキング率との相関: 男性 r=0.929, 女性 r=0.947 VIF最大値: 3.88(多重共線性の問題なし) 男性に有意な変数: ['ウォーキング率'] 女性に有意な変数: ['ウォーキング率', '高齢化率'] 使用データ: SSDSE-D-2023, SSDSE-B-2026, SSDSE-E-2026 (47都道府県)
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。| データ | 出典 |
|---|---|
| 全国体力・運動能力、運動習慣等調査 | 文部科学省(小学5年生 47都道府県) |
| SSDSE-B 都道府県データ | 統計数理研究所 SSDSE(社会・人口統計体系) |
本教育用コードは合成データを使用(np.random.seed(42))。実際の分析は実データによる。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。