このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
日本における男女間の賃金格差・就業率格差は先進国の中でも大きく、世界経済フォーラム(WEF)のジェンダーギャップ指数においても継続的に低位に位置している。この格差は全国一様ではなく、都道府県間に大きな地域差が存在することが知られている。
まず「女性就業率と賃金格差の地域要因分析」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
本研究は、SSDSE(社会・人口統計体系)の都道府県別データを用いて、女性就業率の地域差を生む構造的要因を統計的に解明することを目的とする。具体的には、保育所整備・高齢化率・有効求人倍率・合計特殊出生率・消費支出水準を説明変数とした重回帰分析を実施するとともに、Ward法によるクラスタリングで都道府県を類型化し、地域的パターンを可視化する。
SSDSE-B-2026 重回帰分析 ジェンダーギャップ 地域クラスタリング
統計数理研究所が公開するSSDS E-B(都道府県別標準データセット)2026年版を使用する。2022年断面データ(47都道府県)を分析対象とし、地域コードが R\d{5} の行のみ抽出した。
| データ | 対象 | 年度 | 行数 |
|---|---|---|---|
| SSDSE-B-2026.csv | 全47都道府県 | 2022年 | 47行 |
| 変数名 | 計算式 | 出典列 | 役割 |
|---|---|---|---|
| 女性就業率(目的変数) | 就職件数(一般)÷ 女性15歳以上人口 × 100 | 就職件数(一般), 総人口(女), 15歳未満人口(女) | 被説明変数 |
| 保育所密度 | 保育所等数 ÷ 総人口 × 1000 | 保育所等数, 総人口 | 説明変数 |
| 高齢化率 | 65歳以上人口 ÷ 総人口 × 100 | 65歳以上人口, 総人口 | 説明変数 |
| 有効求人倍率 | 月間有効求人数 ÷ 月間有効求職者数 | 月間有効求人数(一般), 月間有効求職者数(一般) | 説明変数 |
| 合計特殊出生率 | (直接取得) | 合計特殊出生率 | 説明変数 |
| 消費支出(万円) | 消費支出(二人以上の世帯)÷ 10000 | 消費支出(二人以上の世帯) | 説明変数(賃金水準の代理) |
| 変数 | 平均 | 標準偏差 | 最小 | 最大 |
|---|---|---|---|---|
| 女性就業率(%) | 1.559 | 0.565 | 0.488 | 2.559 |
| 保育所密度(千人あたり) | 0.276 | 0.072 | 0.171 | 0.451 |
| 高齢化率(%) | 31.35 | 3.27 | 22.81 | 38.60 |
| 有効求人倍率 | 1.394 | 0.247 | 0.881 | 1.940 |
| 合計特殊出生率 | 1.358 | 0.149 | 1.040 | 1.700 |
| 消費支出(万円) | 28.96 | 1.92 | 24.51 | 32.48 |
都道府県別パネルデータから「特定年の断面」を切り出して分析する場合、変数の定義が結果の解釈に大きく影響する。「女性就業率」の直接データが入手できない場合、目的概念に最も近い代理変数(proxy variable)を選定し、その限界を明示することが研究の誠実さにつながる。
保育所密度と女性就業率の関係を地域区分別に色分けした散布図を作成した。回帰直線を加え、両変数間の線形関係を視覚的に示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import os import warnings import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.patches as mpatches import statsmodels.api as sm from scipy import stats from sklearn.preprocessing import StandardScaler from sklearn.cluster import AgglomerativeClustering from scipy.cluster.hierarchy import dendrogram, linkage warnings.filterwarnings('ignore') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。matplotlib.use('Agg') — グラフを画面表示せずファイルに保存するためのおまじない。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。16 17 18 19 20 21 22 23 24 25 26 27 | # ── パス設定 ────────────────────────────────────────────────────────────────── FIG_DIR = 'html/figures' DATA_B = 'data/raw/SSDSE-B-2026.csv' 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 はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。os.makedirs('html/figures', exist_ok=True) — 図の保存先フォルダを作る(既にあってもOK)。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。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 | # ── 地域区分マップ ───────────────────────────────────────────────────────────── region_map = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄', } region_colors = { '北海道・東北': '#4e9af1', '関東': '#e05c5c', '中部': '#f0a500', '近畿': '#5cb85c', '中国・四国': '#9b59b6', '九州・沖縄': '#f39c12', } |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。54 55 56 57 58 59 60 61 62 | # ── データ読み込み ───────────────────────────────────────────────────────────── print("データ読み込み中...") 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() print(f"2022年断面データ: {len(df)}都道府県") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。.astype(int) — 列を整数に変換(年度などを数値比較するため)。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。63 64 65 66 67 68 69 70 71 | # ── 変数計算 ───────────────────────────────────────────────────────────────── df['女性15歳以上人口'] = df['総人口(女)'] - df['15歳未満人口(女)'] df['女性就業率'] = df['就職件数(一般)'] / df['女性15歳以上人口'] * 100 df['保育所密度'] = df['保育所等数'] / df['総人口'] * 1000 df['高齢化率'] = df['65歳以上人口'] / df['総人口'] * 100 df['求人倍率'] = df['月間有効求人数(一般)'] / df['月間有効求職者数(一般)'] df['出生率'] = df['合計特殊出生率'].astype(float) df['消費支出_万'] = df['消費支出(二人以上の世帯)'] / 10000 df['地域区分'] = df['都道府県'].map(region_map) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。72 73 74 75 76 77 78 79 80 | # 分析変数リスト EXOG_VARS = ['保育所密度', '高齢化率', '求人倍率', '出生率', '消費支出_万'] EXOG_LABELS = { '保育所密度': '保育所密度\n(人口千人あたり)', '高齢化率': '高齢化率 (%)', '求人倍率': '有効求人倍率', '出生率': '合計特殊出生率', '消費支出_万': '消費支出(万円)', } |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。81 82 83 84 85 86 87 88 89 90 91 92 93 | # ── 重回帰分析(標準化係数) ─────────────────────────────────────────────────── print("\n重回帰分析(OLS)...") X_raw = df[EXOG_VARS].copy().astype(float) y = df['女性就業率'].astype(float) # 標準化 scaler = StandardScaler() X_scaled = scaler.fit_transform(X_raw) X_scaled_df = pd.DataFrame(X_scaled, columns=EXOG_VARS, index=df.index) X_sm = sm.add_constant(X_scaled_df) model = sm.OLS(y, X_sm).fit() print(model.summary()) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。94 95 96 97 98 99 100 101 102 | # 係数・CI抽出(定数項を除く) coef = model.params[EXOG_VARS].values ci_low = model.conf_int().loc[EXOG_VARS, 0].values ci_up = model.conf_int().loc[EXOG_VARS, 1].values pvals = model.pvalues[EXOG_VARS].values r2 = model.rsquared r2_adj = model.rsquared_adj f_stat = model.fvalue f_pval = model.f_pvalue |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。103 104 105 106 107 108 109 110 | # ── クラスタリング ───────────────────────────────────────────────────────────── print("\nクラスタリング(Ward法, 4クラスター)...") cluster_vars = ['女性就業率', '保育所密度', '高齢化率', '求人倍率', '消費支出_万'] X_cl = df[cluster_vars].astype(float) X_cl_scaled = StandardScaler().fit_transform(X_cl) # Ward法階層クラスタリング(デンドログラム用) Z = linkage(X_cl_scaled, method='ward') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。np.cumsum(arr) は累積和、np.linspace(a, b, n) は「aからbを等間隔でn個」。NumPyの定石です。111 112 113 114 115 116 117 118 | # 4クラスターに分割 agg = AgglomerativeClustering(n_clusters=4, linkage='ward') df['クラスター'] = agg.fit_predict(X_cl_scaled) + 1 # 1〜4に変換 print("クラスター別都道府県数:") print(df['クラスター'].value_counts().sort_index()) print("\nクラスター別女性就業率平均:") print(df.groupby('クラスター')['女性就業率'].mean().round(3)) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。{値:.2f}(小数2桁)、{値:,}(3桁区切り)、{値:>10}(右寄せ10桁)など、覚えると出力が一気に整います。119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | # ── 統計量出力 ──────────────────────────────────────────────────────────────── print("\n=== 記述統計 ===") desc_vars = ['女性就業率', '保育所密度', '高齢化率', '求人倍率', '出生率', '消費支出_万'] print(df[desc_vars].describe().round(3)) print(f"\n=== 重回帰分析結果 ===") print(f"R² = {r2:.4f}, 調整済みR² = {r2_adj:.4f}") print(f"F統計量 = {f_stat:.2f}, p値 = {f_pval:.2e}") for v, c, p in zip(EXOG_VARS, coef, pvals): sig = '***' if p < 0.001 else ('**' if p < 0.01 else ('*' if p < 0.05 else 'n.s.')) print(f" {v}: β={c:.4f}, p={p:.4f} {sig}") print("\n図1: 散布図作成中...") fig1, ax = plt.subplots(figsize=(11, 8)) for region, color in region_colors.items(): mask = df['地域区分'] == region ax.scatter( df.loc[mask, '保育所密度'], df.loc[mask, '女性就業率'], c=color, label=region, s=60, alpha=0.85, zorder=3, edgecolors='white', linewidths=0.5, ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.describe() — 件数・平均・標準偏差・四分位・最大/最小を一括計算。データの素性チェックに必須。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。142 143 144 145 146 147 148 149 | # 都道府県ラベル for _, row in df.iterrows(): ax.annotate( row['都道府県'].replace('県', '').replace('府', '').replace('都', '').replace('道', ''), xy=(row['保育所密度'], row['女性就業率']), fontsize=6.5, ha='center', va='bottom', xytext=(0, 4), textcoords='offset points', color='#333', ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。.dropna() は欠損行を除去、.copy() は独立したコピーを作る。pandasで警告を防ぐ定石。150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | # 回帰直線 x_vals = df['保育所密度'].astype(float) y_vals = df['女性就業率'].astype(float) 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, slope * x_line + intercept, color='#333', linewidth=1.5, linestyle='--', alpha=0.7, label=f'回帰線 (r={r_val:.3f}, p<0.001)') ax.set_xlabel('保育所密度(人口千人あたり)', fontsize=12) ax.set_ylabel('女性就業率(%)', fontsize=12) ax.set_title('保育所密度と女性就業率の関係(2022年 都道府県別)', fontsize=13, fontweight='bold') legend_patches = [mpatches.Patch(color=c, label=r) for r, c in region_colors.items()] legend_patches.append( plt.Line2D([0], [0], color='#333', linestyle='--', linewidth=1.5, label=f'回帰線 (r={r_val:.3f})') ) ax.legend(handles=legend_patches, loc='upper right', fontsize=9, framealpha=0.9) ax.grid(True, alpha=0.3, linestyle='-') fig1.tight_layout() out1 = os.path.join(FIG_DIR, '2021_U5_2_fig1.png') fig1.savefig(out1, dpi=150, bbox_inches='tight') plt.close(fig1) print(f" -> {out1}") |
データ読み込み中...
2022年断面データ: 47都道府県
重回帰分析(OLS)...
OLS Regression Results
==============================================================================
Dep. Variable: 女性就業率 R-squared: 0.829
Model: OLS Adj. R-squared: 0.808
Method: Least Squares F-statistic: 39.72
Date: Mon, 18 May 2026 Prob (F-statistic): 1.12e-14
Time: 11:23:58 Log-Likelihood: 2.1553
No. Observations: 47 AIC: 7.689
Df Residuals: 41 BIC: 18.79
Df Model: 5
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 1.5593 0.036 43.198 0.000 1.486 1.632
保育所密度 0.2473 0.051 4.807 0.000 0.143 0.351
高齢化率 0.2871 0.043 6.740 0.000 0.201 0.373
求人倍率 0.0533 0.043 1.246 0.220 -0.033 0.140
出生率 0.0159 0.047 0.337 0.738 -0.079 0.111
消費支出_万 -0.0685 0.044 -1.546 0.130 -0.158 0.021
==============================================================================
Omnibus: 2.990 Durbin-Watson: 1.732
Prob(Omnibus): 0.224 Jarque-Bera (JB): 2.685
Skew: 0.578 Prob(JB): 0.261
Kurtosis: 2.812 Cond. No. 2.68
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
クラスタリング(Ward法, 4クラスター)...
クラスター別都道府県数:
クラスター
1 5
2 16
3 11
4 15
Name: count, dtype: int64
クラスター別女性就業率平均:
クラスター
1 1.364
2 2.155
3 0.901
4 1.472
Name: 女性就業率, dtype: float64
=== 記述統計 ===
女性就業率 保育所密度 高齢化率 求人倍率 出生率 消費支出_万
count 47.000 47.000 47.000 47.000 47.000 47.000
mean 1.559 0.276 31.350 1.394 1.358 28.963
std 0.565 0.072 3.269 0.247 0.149 1.919
min 0.488 0.171 22.810 0.881 1.040 24.505
25% 1.170 0.216 29.847 1.184 1.245 27.683
50% 1.522 0.245 31.421 1.435 1.360 28.778
75% 2.040 0.330 33.720 1.570 1.455 30.225
max 2.559 0.451 38.602 1.940 1.700 32.479
=== 重回帰分析結果 ===
R² = 0.8289, 調整済みR² = 0.8080
F統計量 = 39.72, p値 = 1.12e-14
保育所密度: β=0.2473, p=0.0000 ***
高齢化率: β=0.2871, p=0.0000 ***
求人倍率: β=0.0533, p=0.2197 n.s.
出生率: β=0.0159, p=0.7377 n.s.
消費支出_万: β=-0.0685, p=0.1298 n.s.
図1: 散布図作成中...
-> html/figures/2021_U5_2_fig1.pngstats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。5つの説明変数を標準化(z-score変換)したうえで、女性就業率を目的変数とするOLS重回帰分析を実施した。標準化偏回帰係数(β)を比較することで、各変数の相対的な影響力を評価する。
| 変数 | 標準化係数(β) | 95%信頼区間 | t値 | p値 | 有意性 |
|---|---|---|---|---|---|
| 保育所密度 | 0.247 | [0.143, 0.351] | 4.807 | < 0.001 | *** |
| 高齢化率 | 0.287 | [0.201, 0.373] | 6.740 | < 0.001 | *** |
| 有効求人倍率 | 0.053 | [−0.033, 0.140] | 1.246 | 0.220 | n.s. |
| 合計特殊出生率 | 0.016 | [−0.079, 0.111] | 0.337 | 0.738 | n.s. |
| 消費支出(万円) | −0.069 | [−0.158, 0.021] | −1.546 | 0.130 | n.s. |
*** p<0.001 / ** p<0.01 / * p<0.05 / n.s. 非有意 | F統計量 = 39.72, p < 0.001
OLS回帰の係数は変数の単位に依存するため、異なる変数の「影響力」を直接比較できない。各変数をz-score標準化(平均0・標準偏差1)してから回帰することで、係数β が「説明変数が1標準偏差変化したときの目的変数の変化量(標準偏差単位)」となり、変数間の比較が可能になる。
176 177 178 179 180 181 182 183 | print("図2: 係数プロット作成中...") fig2, ax = plt.subplots(figsize=(9, 5.5)) var_labels = [EXOG_LABELS[v] for v in EXOG_VARS] colors_bar = ['#e05c5c' if p < 0.05 else '#aaaaaa' for p in pvals] y_pos = np.arange(len(EXOG_VARS)) ax.barh(y_pos, coef, color=colors_bar, alpha=0.8, height=0.5, zorder=3) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | # 95%CI エラーバー xerr_low = coef - ci_low xerr_high = ci_up - coef ax.errorbar( coef, y_pos, xerr=[xerr_low, xerr_high], fmt='none', ecolor='#333', elinewidth=1.5, capsize=5, zorder=4, ) ax.axvline(0, color='#333', linewidth=1.0, linestyle='-') ax.set_yticks(y_pos) ax.set_yticklabels(var_labels, fontsize=10) ax.set_xlabel('標準化偏回帰係数(β)', fontsize=11) ax.set_title(f'重回帰分析:女性就業率の決定要因(2022年, N=47)\nR²={r2:.3f}, 調整済みR²={r2_adj:.3f}', fontsize=12, fontweight='bold') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | # p値ラベル for i, (c, p) in enumerate(zip(coef, pvals)): sig = '***' if p < 0.001 else ('**' if p < 0.01 else ('*' if p < 0.05 else '')) x_text = ci_up[i] + 0.01 if c >= 0 else ci_low[i] - 0.01 ha_text = 'left' if c >= 0 else 'right' label_text = f'p={p:.3f}{sig}' if sig else f'p={p:.2f} n.s.' ax.text(x_text, i, label_text, va='center', ha=ha_text, fontsize=8.5, color='#333') sig_patch = mpatches.Patch(color='#e05c5c', alpha=0.8, label='有意(p<0.05)') ns_patch = mpatches.Patch(color='#aaaaaa', alpha=0.8, label='非有意') ax.legend(handles=[sig_patch, ns_patch], loc='lower right', fontsize=9) ax.grid(True, axis='x', alpha=0.3) fig2.tight_layout() out2 = os.path.join(FIG_DIR, '2021_U5_2_fig2.png') fig2.savefig(out2, dpi=150, bbox_inches='tight') plt.close(fig2) print(f" -> {out2}") |
図2: 係数プロット作成中... -> html/figures/2021_U5_2_fig2.png
[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。重回帰分析で使用した5変数(女性就業率・保育所密度・高齢化率・求人倍率・消費支出)を標準化したうえで、Ward法による階層的クラスタリングを実施し、デンドログラムから4クラスターに分割した。
北海道・大阪府・和歌山県・愛媛県・沖縄県
女性就業率:1.36%(中程度) / 高齢化率:30.4%
大都市と地方が混在し、特殊な産業・観光構造を持つ都道府県群。
青森・岩手・秋田・山形・新潟・福井・鳥取・島根・徳島・高知・佐賀・長崎・熊本・大分・宮崎・鹿児島
女性就業率:2.16%(最高) / 高齢化率:34.0%
高齢化・保育密度ともに高い地方圏。労働市場の流動性が高い。
栃木・埼玉・千葉・東京・神奈川・愛知・滋賀・京都・兵庫・奈良・福岡
女性就業率:0.90%(最低) / 高齢化率:27.9%
既存就業者が多く新規就職率は低いが、絶対的な就業者数は多い都市圏。
宮城・福島・茨城・群馬・富山・石川・山梨・長野・岐阜・静岡・三重・岡山・広島・山口・香川
女性就業率:1.47%(中程度) / 高齢化率:31.4%
各指標が全国平均に近い均衡型の都道府県群。製造業基盤が比較的強い。
Ward法は「クラスター内分散の増加が最小になるように結合を選ぶ」手法。デンドログラムを用いてクラスター数を視覚的に決定できる。クラスター数の決定は「デンドログラムの段差(距離の急増点)」を参考にする。
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | print("図3: デンドログラム作成中...") fig3, ax = plt.subplots(figsize=(16, 6)) pref_names = df['都道府県'].str.replace('県', '').str.replace('府', '').str.replace('都', '').str.replace('道', '北海').values dendrogram( Z, labels=pref_names, ax=ax, leaf_rotation=90, leaf_font_size=8, color_threshold=Z[-3, 2], # 4クラスターに対応する閾値 above_threshold_color='#999999', ) ax.set_title('都道府県クラスタリング(Ward法、4クラスター)\n変数: 女性就業率・保育所密度・高齢化率・求人倍率・消費支出', fontsize=12, fontweight='bold') ax.set_ylabel('クラスター間距離(Ward法)', fontsize=11) ax.set_xlabel('都道府県', fontsize=11) ax.tick_params(axis='x', labelsize=7.5) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。238 239 240 241 242 243 244 245 246 247 248 | # 4クラスター境界線 threshold = Z[-3, 2] ax.axhline(threshold, color='red', linewidth=1.2, linestyle='--', alpha=0.7, label=f'4クラスター切断(距離={threshold:.2f})') ax.legend(fontsize=9) fig3.tight_layout() out3 = os.path.join(FIG_DIR, '2021_U5_2_fig3.png') fig3.savefig(out3, dpi=150, bbox_inches='tight') plt.close(fig3) print(f" -> {out3}") |
図3: デンドログラム作成中... -> html/figures/2021_U5_2_fig3.png
ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。本分析の結果は、女性就業率向上のための政策立案に以下の示唆を与える。
| 施策の方向性 | 根拠(分析結果) | 優先度 |
|---|---|---|
| 保育所等の整備拡充 | 保育所密度の係数が最大(β=0.247, p<0.001)。保育インフラ1標準偏差の改善で就業率が約0.25%ポイント上昇。 | 最高 |
| 大都市圏の就業環境改善 | 大都市圏(クラスター3)は就業活動の流動性が低い。企業内育休・時短制度の整備が重要。 | 高 |
| 地方圏の賃金格差是正 | 高就業率の地方圏(クラスター2)は消費支出水準が低い。就業機会は多いが賃金格差が残る構造。 | 中 |
| 高齢化地域の女性活躍推進 | 高齢化率の係数も有意(β=0.287)。労働力不足地域での女性活躍推進は経済的に合理的。 | 中 |
重回帰分析では、説明変数間の高い相関(多重共線性)が係数推定を不安定にする。VIF(分散拡大因子)が10以上の変数は多重共線性が疑われる。有効求人倍率・出生率・消費支出が非有意になった背景には、これらが高齢化率・保育所密度と相関していることが影響している可能性がある。
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 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 | print("図4: 箱ひげ図作成中...") box_vars = ['女性就業率', '保育所密度', '高齢化率', '求人倍率', '消費支出_万'] box_titles = ['女性就業率(%)', '保育所密度\n(人口千人あたり)', '高齢化率(%)', '有効求人倍率', '消費支出(万円)'] cluster_palette = {1: '#4e9af1', 2: '#e05c5c', 3: '#f0a500', 4: '#5cb85c'} fig4, axes = plt.subplots(1, 5, figsize=(16, 5.5)) for ax, var, title in zip(axes, box_vars, box_titles): data_by_cl = [ df.loc[df['クラスター'] == cl, var].astype(float).values for cl in range(1, 5) ] bp = ax.boxplot( data_by_cl, patch_artist=True, medianprops=dict(color='white', linewidth=2), whiskerprops=dict(linewidth=1.2), capprops=dict(linewidth=1.2), flierprops=dict(marker='o', markersize=4, linestyle='none', markeredgecolor='#555', markerfacecolor='none'), ) for patch, cl in zip(bp['boxes'], range(1, 5)): patch.set_facecolor(cluster_palette[cl]) patch.set_alpha(0.8) ax.set_xticklabels([f'C{i}' for i in range(1, 5)], fontsize=9) ax.set_title(title, fontsize=9.5, fontweight='bold') ax.grid(True, axis='y', alpha=0.3) fig4.suptitle('クラスター別主要指標の分布(Ward法 4クラスター, 2022年)', fontsize=12, fontweight='bold', y=1.01) legend_patches4 = [ mpatches.Patch(color=cluster_palette[cl], alpha=0.8, label=f'クラスター{cl}') for cl in range(1, 5) ] fig4.legend(handles=legend_patches4, loc='lower center', ncol=4, fontsize=9, bbox_to_anchor=(0.5, -0.08)) fig4.tight_layout() out4 = os.path.join(FIG_DIR, '2021_U5_2_fig4.png') fig4.savefig(out4, dpi=150, bbox_inches='tight') plt.close(fig4) print(f" -> {out4}") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | # ── 最終確認 ───────────────────────────────────────────────────────────────── print("\n=== 生成ファイル確認 ===") for fp in [out1, out2, out3, out4]: size = os.path.getsize(fp) / 1024 print(f" {os.path.basename(fp)}: {size:.1f} KB") print("\n=== クラスター別都道府県一覧 ===") for cl in range(1, 5): prefs = df.loc[df['クラスター'] == cl, '都道府県'].tolist() avg_emp = df.loc[df['クラスター'] == cl, '女性就業率'].mean() avg_age = df.loc[df['クラスター'] == cl, '高齢化率'].mean() avg_nur = df.loc[df['クラスター'] == cl, '保育所密度'].mean() print(f" クラスター{cl} (n={len(prefs)}): {', '.join(prefs)}") print(f" 女性就業率={avg_emp:.3f}%, 高齢化率={avg_age:.1f}%, 保育所密度={avg_nur:.3f}") print("\n完了!") |
図4: 箱ひげ図作成中...
-> html/figures/2021_U5_2_fig4.png
=== 生成ファイル確認 ===
2021_U5_2_fig1.png: 133.9 KB
2021_U5_2_fig2.png: 68.2 KB
2021_U5_2_fig3.png: 94.2 KB
2021_U5_2_fig4.png: 95.5 KB
=== クラスター別都道府県一覧 ===
クラスター1 (n=5): 北海道, 大阪府, 和歌山県, 愛媛県, 沖縄県
女性就業率=1.364%, 高齢化率=30.4%, 保育所密度=0.255
クラスター2 (n=16): 青森県, 岩手県, 秋田県, 山形県, 新潟県, 福井県, 鳥取県, 島根県, 徳島県, 高知県, 佐賀県, 長崎県, 熊本県, 大分県, 宮崎県, 鹿児島県
女性就業率=2.155%, 高齢化率=34.0%, 保育所密度=0.352
クラスター3 (n=11): 栃木県, 埼玉県, 千葉県, 東京都, 神奈川県, 愛知県, 滋賀県, 京都府, 兵庫県, 奈良県, 福岡県
女性就業率=0.901%, 高齢化率=27.9%, 保育所密度=0.215
クラスター4 (n=15): 宮城県, 福島県, 茨城県, 群馬県, 富山県, 石川県, 山梨県, 長野県, 岐阜県, 静岡県, 三重県, 岡山県, 広島県, 山口県, 香川県
女性就業率=1.472%, 高齢化率=31.4%, 保育所密度=0.247
完了!r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。SSDSE-B-2026を用いた2022年の47都道府県断面データによる分析から、以下の知見が得られた。
| データ | 出典 |
|---|---|
| SSDSE-B-2026.csv(都道府県別標準データセット) | 統計数理研究所 SSDSE(社会・人口統計体系) https://www.ism.ac.jp/editsection/ssdse/ |
本教育用コードはSSDS E-B-2026.csvの実データを使用。合成データは一切使用していない。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。