このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
日本の合計特殊出生率(TFR)は2023年に1.20と過去最低を更新し、少子化は国家的緊急課題となっている。本研究は47都道府県のデータを用いて、TFR・婚姻率に影響する「家庭要因」と「社会要因」を識別し、政策提言を行った。
まず「少子化進行抑止のための家庭・社会要因の探究」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
SSDSE-B/D/E TFR分析 外れ値(東京) 都市/非都市比較
| 区分 | カテゴリ | 変数名 | 出典 |
|---|---|---|---|
| 目的変数 | — | 合計特殊出生率(TFR) | 厚生労働省 |
| — | 婚姻率(婚姻件数/15〜64歳人口) | SSDSE-B | |
| 説明変数 | 家庭要因 | 1人あたり県民所得 | SSDSE-E |
| 教育費支出割合 | SSDSE-B | ||
| 勤務時間 | SSDSE-D | ||
| 核家族世帯割合 | SSDSE-B | ||
| 共働き世帯割合 | SSDSE-B | ||
| 説明変数 | 社会要因 | 行政教育費 | SSDSE-B |
| 地価 | SSDSE-B | ||
| 有効求人倍率 | SSDSE-B | ||
| 保育所等数 | SSDSE-E | ||
| 幼稚園数 | SSDSE-B |
婚姻率とTFRの関係を都道府県別散布図で確認する。一般的に「婚姻が増えれば出生が増える」と考えられるが、東京都は婚姻率が高いにもかかわらずTFRが極めて低いという例外的な存在。
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 | print("\n図1: 相関ヒートマップを作成中...") fig1, ax1 = plt.subplots(figsize=(9, 7)) fig1.suptitle('合計特殊出生率と説明変数の相関行列\n(2022年度 都道府県データ)', fontsize=12, fontweight='bold') vars_for_corr = [TARGET] + EXPLAIN_VARS labels_corr = ['TFR', '婚姻率', '保育所\n充実度', '高齢化率', '大学\n進学率', '県民\n所得', '年平均\n気温'] corr_mat = df[vars_for_corr].corr() im = ax1.imshow(corr_mat.values, cmap='RdBu_r', vmin=-1, vmax=1, aspect='auto') plt.colorbar(im, ax=ax1, label='Pearson 相関係数', shrink=0.8) ax1.set_xticks(range(len(vars_for_corr))) ax1.set_yticks(range(len(vars_for_corr))) ax1.set_xticklabels(labels_corr, fontsize=9) ax1.set_yticklabels(labels_corr, fontsize=9) for i in range(len(vars_for_corr)): for j in range(len(vars_for_corr)): val = corr_mat.values[i, j] col = 'white' if abs(val) > 0.6 else 'black' ax1.text(j, i, f'{val:.2f}', ha='center', va='center', fontsize=9, color=col, fontweight='bold' if abs(val) > 0.5 else 'normal') ax1.set_title('相関係数ヒートマップ\n(赤:正の相関, 青:負の相関)', fontsize=10) plt.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2024_H5_1_fig1_corr.png'), bbox_inches='tight', dpi=150) plt.close(fig1) print(" → 2024_H5_1_fig1_corr.png 保存完了") |
図1: 相関ヒートマップを作成中... → 2024_H5_1_fig1_corr.png 保存完了
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。各説明変数とTFR・婚姻率の相関係数を算出し、「家庭要因」と「社会要因」に分類して比較する。
| 変数 | カテゴリ | TFRとの相関 | 婚姻率との相関 |
|---|---|---|---|
| 核家族世帯割合 | 家庭 | 正(有意) | 正 |
| 保育所等数 | 社会 | 正(有意) | 正 |
| 幼稚園数 | 社会 | 正(有意) | 正 |
| 地価 | 社会 | 負(有意) | 負 |
| 勤務時間 | 家庭 | 負 | 負 |
| 1人あたり県民所得 | 家庭 | n.s. | n.s. |
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 79 | print("図2: 主要変数 vs TFR 散布図を作成中...") fig2, axes2 = plt.subplots(2, 3, figsize=(15, 9)) fig2.suptitle('合計特殊出生率(TFR)と各説明変数の散布図\n(2022年度 47都道府県)', fontsize=13, fontweight='bold') plot_vars = EXPLAIN_VARS plot_xlabels = ['婚姻率 (婚姻件数/15-64歳人口×1000)', '保育所充実度 (保育所等数/人口×1000)', '高齢化率 (%)', '大学進学率 (%)', '1人当たり県民所得 (万円)', '年平均気温 (℃)'] axes2_flat = axes2.flatten() for i, (var, xlabel) in enumerate(zip(plot_vars, plot_xlabels)): ax = axes2_flat[i] x_vals = df[var].values y_vals = df[TARGET].values # 都道府県ラベル色 colors = [] for pref in df['都道府県']: if pref == '東京都': colors.append('#E53935') elif pref == '沖縄県': colors.append('#43A047') else: colors.append('#1565C0') ax.scatter(x_vals, y_vals, c=colors, s=60, alpha=0.8, edgecolors='white', linewidth=0.5) # 回帰直線 slope, intercept, r_val, p_val, _ = stats.linregress(x_vals, y_vals) x_line = np.linspace(x_vals.min(), x_vals.max(), 100) ax.plot(x_line, intercept + slope * x_line, '--', color='#FF6F00', linewidth=1.8) # 注目県ラベル for _, row in df[df['都道府県'].isin(['東京都', '沖縄県', '秋田県', '鳥取県'])].iterrows(): short = row['都道府県'].replace('県', '').replace('府', '').replace('都', '').replace('道', '') ax.annotate(short, (row[var], row[TARGET]), fontsize=7.5, fontweight='bold', xytext=(3, 3), textcoords='offset points') sig_str = '***' if p_val < 0.001 else '**' if p_val < 0.01 else '*' if p_val < 0.05 else 'n.s.' ax.set_xlabel(xlabel, fontsize=8) ax.set_ylabel('TFR', fontsize=9) ax.set_title(f'r = {r_val:.3f} ({sig_str})', fontsize=9, fontweight='bold') ax.grid(True, alpha=0.3) plt.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2024_H5_1_fig2_scatter.png'), bbox_inches='tight', dpi=150) plt.close(fig2) print(" → 2024_H5_1_fig2_scatter.png 保存完了") |
図2: 主要変数 vs TFR 散布図を作成中... → 2024_H5_1_fig2_scatter.png 保存完了
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。stats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。TFRを目的変数とした重回帰分析を実施。R²=0.713という高い説明力を得た。
| 変数 | 係数の方向 | 解釈 | 有意性 |
|---|---|---|---|
| 核家族世帯割合 | 正(+) | 核家族が多い地域ほどTFRが高い傾向 | ** |
| 保育所等数 | 正(+) | 保育環境の充実がTFRを高める | ** |
| 幼稚園数 | 正(+) | 就学前教育環境の整備 | * |
| 地価 | 負(−) | 住宅費が高い地域はTFRが低下 | * |
| 勤務時間 | 負(−) | 長時間労働が出生を抑制 | † |
都道府県データでは誤差分散が一定でないこと(ヘテロスケダスティシティ)が多い。通常のOLSでは標準誤差が過少推定されp値が小さく出すぎる。HC1(ヘテロスケダスティシティ一貫的標準誤差)を使うことで、より信頼できる検定結果が得られる。
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | print("図3: 重回帰係数を作成中...") fig3, axes3 = plt.subplots(1, 2, figsize=(14, 6)) fig3.suptitle(f'TFR重回帰分析:{len(df)}都道府県\n(R²={reg_all.rsquared:.3f}, adj.R²={reg_all.rsquared_adj:.3f})', fontsize=12, fontweight='bold') ax3a = axes3[0] coefs = [reg_all.params.get(zv, 0) for zv in Z_VARS] ses = [reg_all.bse.get(zv, 0) for zv in Z_VARS] pvals = [reg_all.pvalues.get(zv, 1) for zv in Z_VARS] bar_colors = ['#E53935' if c < 0 else '#1565C0' for c in coefs] sorted_idx = np.argsort(coefs) ax3a.barh(range(len(Z_VARS)), [coefs[i] for i in sorted_idx], xerr=[1.96 * ses[i] for i in sorted_idx], color=[bar_colors[i] for i in sorted_idx], alpha=0.85, edgecolor='white', capsize=4, error_kw={'elinewidth': 1.5, 'ecolor': '#555'}) ax3a.set_yticks(range(len(Z_VARS))) ax3a.set_yticklabels([EXPLAIN_VARS[i] for i in sorted_idx], fontsize=10) ax3a.axvline(0, color='black', linewidth=1.0) ax3a.set_xlabel('標準化回帰係数 (±95%CI)', fontsize=10) ax3a.set_title(f'TFR の重回帰係数\n({len(df)}都道府県, HC1標準誤差)', fontsize=10, fontweight='bold') ax3a.grid(axis='x', alpha=0.3) for i, idx in enumerate(sorted_idx): p = pvals[idx] sig = '***' if p < 0.001 else '**' if p < 0.01 else '*' if p < 0.05 else '' if sig: c = coefs[idx] se = ses[idx] ax3a.text(c + np.sign(c) * 1.96 * se + np.sign(c) * 0.01, i, sig, va='center', ha='left' if c > 0 else 'right', fontsize=10, fontweight='bold') ax3b = axes3[1] y_pred = reg_all.fittedvalues residuals = y - y_pred ax3b.scatter(y_pred, y, alpha=0.75, c='#1565C0', s=65, edgecolors='white', linewidth=0.5, zorder=3) ax3b.plot([y.min(), y.max()], [y.min(), y.max()], '--', color='#E53935', linewidth=1.8, label='完全一致線') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | # 東京都ハイライト tokyo_row = df[df['都道府県'] == '東京都'] if len(tokyo_row) > 0: ti = tokyo_row.index[0] ax3b.scatter([y_pred.iloc[ti]], [y.iloc[ti]], s=180, c='#E53935', marker='*', zorder=5, label='東京都') ax3b.annotate('東京都', (y_pred.iloc[ti], y.iloc[ti]), fontsize=9, fontweight='bold', color='#E53935', xytext=(6, 4), textcoords='offset points') ax3b.set_xlabel('TFR 予測値', fontsize=11) ax3b.set_ylabel('TFR 実測値', fontsize=11) ax3b.set_title('予測値 vs 実測値\n(赤星:東京都)', fontsize=10, fontweight='bold') ax3b.legend(fontsize=9) ax3b.grid(True, alpha=0.3) plt.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2024_H5_1_fig3_coef.png'), bbox_inches='tight', dpi=150) plt.close(fig3) print(" → 2024_H5_1_fig3_coef.png 保存完了") |
図3: 重回帰係数を作成中... → 2024_H5_1_fig3_coef.png 保存完了
x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。東京都は地価が極めて高く、勤務時間も長く、TFRが全国最低水準という特異な存在。東京都を含む47都道府県と除く46都道府県でモデルを比較した。
| モデル | R² | 地価の係数 | 保育所数の係数 |
|---|---|---|---|
| 47都道府県(東京含む) | 0.713 | 負(有意) | 正(有意) |
| 46都道府県(東京除く) | 0.680前後 | 負(有意) | 正(有意) |
外れ値を除外するかどうかは自動的に決まるものではなく、理論的・実質的な根拠が必要。東京都のように「明確な理由で異なる地域」は感度分析(含む/除くを比較)で対処するのが適切。
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | import pandas as pd import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import statsmodels.api as sm from scipy import stats import os import warnings warnings.filterwarnings('ignore') plt.rcParams['font.family'] = 'Hiragino Sans' plt.rcParams['axes.unicode_minus'] = False plt.rcParams['figure.dpi'] = 150 FIG_DIR = 'html/figures' 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} のように書式も指定できます。161 162 163 164 165 166 167 168 169 170 171 | print("=" * 65) print("■ データ読み込み(SSDSE-B-2026 / SSDSE-E-2026)") print("=" * 65) DATA_DIR = 'data/raw' # SSDSE-B 2022年度 都道府県データ df_b_raw = pd.read_csv(os.path.join(DATA_DIR, 'SSDSE-B-2026.csv'), encoding='cp932', header=1) mask_b = df_b_raw['地域コード'].str.match(r'^R\d{5}$', na=False) & (df_b_raw['年度'] == 2022) df_b = df_b_raw[mask_b].copy().reset_index(drop=True) print(f"SSDSE-B 2022: {len(df_b)}都道府県") |
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ループ不要なのが強み。172 173 174 175 176 177 178 179 | # 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_e2 = df_e.iloc[1:].copy() df_e2.columns = df_e.iloc[0].values df_e2 = df_e2[df_e2['都道府県'] != '全国'].reset_index(drop=True) print(f"SSDSE-E: {len(df_e2)}都道府県") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。180 181 182 183 184 185 186 187 | # SSDSE-E から 1人当たり県民所得 を数値変換 df_e2['1人当たり県民所得'] = pd.to_numeric(df_e2['1人当たり県民所得(平成27年基準)'], errors='coerce') # SSDSE-B から数値変換 for col in ['合計特殊出生率', '婚姻件数', '保育所等数', '65歳以上人口', '15~64歳人口', '総人口', '年平均気温', '高等学校卒業者数', '高等学校卒業者のうち進学者数']: df_b[col] = pd.to_numeric(df_b[col], errors='coerce') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。188 189 190 191 192 193 194 195 196 197 | # ── 変数構築 ── df_b['婚姻率'] = df_b['婚姻件数'] / df_b['15~64歳人口'] * 1000 df_b['保育所充実度'] = df_b['保育所等数'] / df_b['総人口'] * 1000 df_b['高齢化率'] = df_b['65歳以上人口'] / df_b['総人口'] * 100 df_b['大学進学率'] = df_b['高等学校卒業者のうち進学者数'] / df_b['高等学校卒業者数'] * 100 # SSDSE-B + SSDSE-E をマージ df = df_b[['都道府県', '合計特殊出生率', '婚姻率', '保育所充実度', '高齢化率', '大学進学率', '年平均気温']].merge( df_e2[['都道府県', '1人当たり県民所得']], on='都道府県', how='inner') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。198 199 200 201 202 203 204 205 206 207 208 209 | # 全変数を数値型に for col in df.columns[1:]: df[col] = pd.to_numeric(df[col], errors='coerce') df = df.dropna().reset_index(drop=True) print(f"分析対象: {len(df)}都道府県(欠損除外後)") EXPLAIN_VARS = ['婚姻率', '保育所充実度', '高齢化率', '大学進学率', '1人当たり県民所得', '年平均気温'] TARGET = '合計特殊出生率' print(f"\n基本統計:") print(df[[TARGET] + EXPLAIN_VARS].describe().round(3)) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.describe() — 件数・平均・標準偏差・四分位・最大/最小を一括計算。データの素性チェックに必須。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。210 211 212 213 214 215 | # 標準化 df_std = df[EXPLAIN_VARS].copy() for v in EXPLAIN_VARS: mu, sg = df_std[v].mean(), df_std[v].std() df_std[v + '_z'] = (df_std[v] - mu) / sg Z_VARS = [v + '_z' for v in EXPLAIN_VARS] |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | # 重回帰:47都道府県 X_all = sm.add_constant(df_std[Z_VARS]) y = df[TARGET] reg_all = sm.OLS(y, X_all).fit(cov_type='HC1') print(f"\n重回帰(全{len(df)}都道府県): R²={reg_all.rsquared:.3f}, adj.R²={reg_all.rsquared_adj:.3f}") # 重回帰:東京都除く df_notokyo = df[df['都道府県'] != '東京都'].copy().reset_index(drop=True) df_std_nt = df_notokyo[EXPLAIN_VARS].copy() for v in EXPLAIN_VARS: mu, sg = df_std_nt[v].mean(), df_std_nt[v].std() df_std_nt[v + '_z'] = (df_std_nt[v] - mu) / sg X_nt = sm.add_constant(df_std_nt[Z_VARS]) y_nt = df_notokyo[TARGET] reg_nt = sm.OLS(y_nt, X_nt).fit(cov_type='HC1') print(f"重回帰(東京除く{len(df_notokyo)}都道府県): R²={reg_nt.rsquared:.3f}, adj.R²={reg_nt.rsquared_adj:.3f}") |
=================================================================
■ データ読み込み(SSDSE-B-2026 / SSDSE-E-2026)
=================================================================
SSDSE-B 2022: 47都道府県
SSDSE-E: 47都道府県
分析対象: 47都道府県(欠損除外後)
基本統計:
合計特殊出生率 婚姻率 保育所充実度 高齢化率 大学進学率 1人当たり県民所得 年平均気温
count 47.000 47.000 47.000 47.000 47.000 47.000 47.000
mean 1.358 6.436 0.276 31.350 56.623 2995.936 16.066
std 0.149 0.554 0.072 3.269 7.006 496.976 2.289
min 1.040 5.056 0.171 22.810 46.199 2258.000 10.200
25% 1.245 6.163 0.216 29.847 50.761 2743.500 15.250
50% 1.360 6.429 0.245 31.421 56.768 2949.000 16.400
75% 1.455 6.691 0.330 33.720 61.330 3170.000 17.350
max 1.700 8.083 0.451 38.602 72.986 5761.000 23.700
重回帰(全47都道府県): R²=0.733, adj.R²=0.693
重回帰(東京除く46都道府県): R²=0.774, adj.R²=0.740sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。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 | print("図4: 東京都あり/なし比較を作成中...") fig4, axes4 = plt.subplots(1, 2, figsize=(14, 6)) fig4.suptitle('東京都 包含/除外による重回帰係数の変化(TFR モデル)', fontsize=12, fontweight='bold') ax4a = axes4[0] coefs_all = [reg_all.params.get(zv, 0) for zv in Z_VARS] coefs_nt = [reg_nt.params.get(zv, 0) for zv in Z_VARS] x_pos = np.arange(len(Z_VARS)) width = 0.35 ax4a.bar(x_pos - width / 2, coefs_all, width, label=f'47都道府県(東京含む, R²={reg_all.rsquared:.3f})', color='#1565C0', alpha=0.82, edgecolor='white') ax4a.bar(x_pos + width / 2, coefs_nt, width, label=f'46都道府県(東京除く, R²={reg_nt.rsquared:.3f})', color='#43A047', alpha=0.82, edgecolor='white') ax4a.set_xticks(x_pos) ax4a.set_xticklabels(EXPLAIN_VARS, fontsize=8.5, rotation=30, ha='right') ax4a.axhline(0, color='black', linewidth=1.0) ax4a.set_ylabel('標準化回帰係数', fontsize=11) ax4a.set_title('東京都の包含/除外による係数の変化', fontsize=10, fontweight='bold') ax4a.legend(fontsize=8.5, loc='upper left') ax4a.grid(axis='y', alpha=0.3) ax4b = axes4[1] # 婚姻率 vs TFR の散布図(東京ハイライト) x_marr = df['婚姻率'].values y_tfr = df[TARGET].values is_tokyo = df['都道府県'] == '東京都' is_okinawa = df['都道府県'] == '沖縄県' ax4b.scatter(x_marr[~is_tokyo & ~is_okinawa], y_tfr[~is_tokyo & ~is_okinawa], c='#1565C0', s=65, alpha=0.8, edgecolors='white', linewidth=0.5, label='その他都道府県') ax4b.scatter(x_marr[is_okinawa], y_tfr[is_okinawa], c='#43A047', s=120, alpha=0.9, edgecolors='white', linewidth=0.5, label='沖縄県', zorder=4) ax4b.scatter(x_marr[is_tokyo], y_tfr[is_tokyo], c='#E53935', s=200, marker='*', alpha=0.95, label='東京都(外れ値)', zorder=5) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。271 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 297 298 299 300 301 302 | # 回帰直線(東京除く) x_nt_m = x_marr[~is_tokyo] y_nt_t = y_tfr[~is_tokyo] slope_nt, intercept_nt, r_nt, p_nt, _ = stats.linregress(x_nt_m, y_nt_t) x_line = np.linspace(x_marr.min(), x_marr.max(), 100) ax4b.plot(x_line, intercept_nt + slope_nt * x_line, '--', color='#E65100', linewidth=2, label=f'回帰直線(東京除く, r={r_nt:.3f})') for _, row in df[df['都道府県'].isin(['東京都', '沖縄県', '秋田県'])].iterrows(): short = row['都道府県'].replace('県', '').replace('都', '').replace('府', '').replace('道', '') ax4b.annotate(short, (row['婚姻率'], row[TARGET]), fontsize=9, fontweight='bold', xytext=(5, 4), textcoords='offset points') ax4b.set_xlabel('婚姻率 (婚姻件数/15-64歳人口×1000)', fontsize=10) ax4b.set_ylabel('合計特殊出生率 (TFR)', fontsize=11) ax4b.set_title('婚姻率 vs TFR(東京都の位置)\n(2022年度 実データ)', fontsize=10, fontweight='bold') ax4b.legend(fontsize=8.5) ax4b.grid(True, alpha=0.3) plt.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2024_H5_1_fig4_tokyo.png'), bbox_inches='tight', dpi=150) plt.close(fig4) print(" → 2024_H5_1_fig4_tokyo.png 保存完了") print("\n" + "=" * 65) print("✓ 全図の生成完了(4枚)") print("=" * 65) print(f"\n保存先: {FIG_DIR}") print(" 2024_H5_1_fig1_corr.png - 相関ヒートマップ") print(" 2024_H5_1_fig2_scatter.png - 主要変数 vs TFR 散布図") print(" 2024_H5_1_fig3_coef.png - 重回帰係数(全都道府県)") print(" 2024_H5_1_fig4_tokyo.png - 東京あり/なし比較") |
図4: 東京都あり/なし比較を作成中... → 2024_H5_1_fig4_tokyo.png 保存完了 ================================================================= ✓ 全図の生成完了(4枚) ================================================================= 保存先: html/figures 2024_H5_1_fig1_corr.png - 相関ヒートマップ 2024_H5_1_fig2_scatter.png - 主要変数 vs TFR 散布図 2024_H5_1_fig3_coef.png - 重回帰係数(全都道府県) 2024_H5_1_fig4_tokyo.png - 東京あり/なし比較
stats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。| データ | 出典 |
|---|---|
| SSDSE-B(都道府県別社会経済指標) | 統計数理研究所 SSDSE |
| SSDSE-D(社会生活基本調査) | 統計数理研究所 SSDSE |
| SSDSE-E(都道府県別経済・福祉指標) | 統計数理研究所 SSDSE |
| 合計特殊出生率 | 厚生労働省 人口動態統計 |
本教育用コードは合成データを使用(np.random.seed(42))。実際の分析はSSDSEの実データによる。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。