このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
2015年に国連が採択した「持続可能な開発目標(SDGs)」は17の目標・169のターゲットからなり、 2030年までの達成が求められている。日本でも国・地方自治体レベルでの取り組みが進んでいるが、 都道府県ごとの達成状況には大きな格差が存在する。
まず「SDGs指標の地域比較都道府県別の持続可能性スコア分析」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
本研究は、公的統計データ(SSDSE-B)から経済・環境・社会・人口の4カテゴリ7指標を構築し、 主成分分析(PCA)により47都道府県の「総合持続可能性スコア」を算出する。 さらにWard法クラスタリングとレーダーチャートを用いて 地域ごとの強みと弱みを多面的に可視化した。
SSDSE-B 主成分分析 Ward法クラスタリング レーダーチャート SDGs
分析データは統計数理研究所が提供する SSDSE-B-2026(都道府県データ)の2022年断面を使用した(47都道府県)。 SDGsの4カテゴリ(経済・環境・社会・人口)に対応する7指標を以下のとおり構築した。
消費支出_log = log(消費支出(二人以上の世帯))
生活水準の代理変数。対数変換で右裾を圧縮。
求人倍率 = 月間有効求人数 / 月間有効求職者数
雇用充実度。1超 = 求人が求職を上回る。
ごみリサイクル率 = ごみのリサイクル率(%)
廃棄物のリサイクル達成度。
ごみ排出量_inv = 1 ÷ (1人1日当たりの排出量g)
排出量が少ないほど値が大きくなるよう逆数変換。
大学進学率 = 高校卒業者のうち進学者数 / 高校卒業者数 × 100(%)
高等教育へのアクセス。
保育所密度 = 保育所等数 / 総人口 × 10000
人口1万人あたりの保育所数。子育て支援の充実度。
合計特殊出生率 = 1人の女性が生涯に産む子の数の推計値
人口再生産の指標。2.07が人口維持水準。
| 指標 | 平均 | 標準偏差 | 最小 | 最大 |
|---|---|---|---|---|
| 消費支出_log(円/月) | 12.574 | 0.067 | 12.41 | 12.70 |
| 求人倍率 | 1.394 | 0.247 | 0.89 | 2.06 |
| ごみリサイクル率(%) | 18.2 | 3.8 | 9.3 | 27.6 |
| ごみ排出量_inv(×10⁻³) | 1.07 | 0.09 | 0.83 | 1.27 |
| 大学進学率(%) | 56.6 | 7.0 | 41.0 | 74.2 |
| 保育所密度(人口1万対) | 2.76 | 0.72 | 1.46 | 4.88 |
| 合計特殊出生率 | 1.358 | 0.149 | 1.04 | 1.79 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | df_raw = pd.read_csv(DATA_B, encoding='shift-jis', header=0) # 行0がラベル行(日本語名)、行1以降が実データ df_all = df_raw.iloc[1:].copy() df_all.columns = df_raw.columns # 必要な数値列に変換 NUM_COLS = ['A1101', 'A4103', 'E4601', 'E4602', 'F3102', 'F3103', 'H5610', 'H5614', 'J2503', 'L3221'] for c in NUM_COLS: df_all[c] = pd.to_numeric(df_all[c], errors='coerce') df_all['年度'] = df_all['SSDSE-B-2026'].astype(int) df_all['都道府県'] = df_all['Prefecture'].astype(str) print("=" * 65) print("■ SSDSE-B-2026 読み込み完了") print(f" 年度範囲: {df_all['年度'].min()}〜{df_all['年度'].max()}") print(f" 都道府県数(各年): {df_all.groupby('年度')['都道府県'].count().iloc[0]}件") print("=" * 65) |
================================================================= ■ SSDSE-B-2026 読み込み完了 年度範囲: 2012〜2023 都道府県数(各年): 47件 =================================================================
pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。.astype(int) — 列を整数に変換(年度などを数値比較するため)。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。21 | df = df_all[df_all['年度'] == 2022].copy().reset_index(drop=True) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | df['消費支出_log'] = np.log(df['L3221']) # 経済: 生活水準(対数変換) df['求人倍率'] = df['F3103'] / df['F3102'] # 経済: 雇用充実度 df['ごみリサイクル率'] = df['H5614'] # 環境: リサイクル率(%) df['ごみ排出量_inv'] = 1.0 / df['H5610'] # 環境: 排出少=良い → 逆数 df['大学進学率'] = df['E4602'] / df['E4601'] * 100 # 社会: 教育到達度(%) df['保育所密度'] = df['J2503'] / df['A1101'] * 10000 # 社会: 人口1万対保育所数 df['合計特殊出生率'] = df['A4103'] # 人口持続性 INDICATOR_COLS = [ '消費支出_log', '求人倍率', 'ごみリサイクル率', 'ごみ排出量_inv', '大学進学率', '保育所密度', '合計特殊出生率' ] INDICATOR_LABELS = [ '消費支出\n(log)', '求人倍率', 'ごみ\nリサイクル率', 'ごみ排出量\n(逆数)', '大学進学率', '保育所密度', '合計特殊\n出生率' ] |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。38 39 40 41 42 43 44 45 46 | # 欠損値がある行を除外 df_sdgs = df[['都道府県'] + INDICATOR_COLS].dropna().reset_index(drop=True) prefectures = df_sdgs['都道府県'].values X_raw = df_sdgs[INDICATOR_COLS].values print(f"\n■ 2022年 SDGs指標データ: {len(df_sdgs)}都道府県") print(f" 7指標の基本統計:") for col in INDICATOR_COLS: print(f" {col}: 平均={df_sdgs[col].mean():.3f}, SD={df_sdgs[col].std():.3f}") |
■ 2022年 SDGs指標データ: 47都道府県
7指標の基本統計:
消費支出_log: 平均=12.574, SD=0.067
求人倍率: 平均=1.394, SD=0.247
ごみリサイクル率: 平均=18.206, SD=3.828
ごみ排出量_inv: 平均=0.001, SD=0.000
大学進学率: 平均=56.623, SD=7.006
保育所密度: 平均=2.758, SD=0.719
合計特殊出生率: 平均=1.358, SD=0.149r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。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 | REGION_MAP = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄', } REGION_ORDER = ['北海道・東北', '関東', '中部', '近畿', '中国・四国', '九州・沖縄'] REGION_COLORS = { '北海道・東北': '#1565C0', '関東': '#E65100', '中部': '#2E7D32', '近畿': '#6A1B9A', '中国・四国': '#795548', '九州・沖縄': '#00838F', } regions = np.array([REGION_MAP.get(p, '不明') for p in prefectures]) df_sdgs['地方'] = regions |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。7指標をStandardScalerで標準化(平均0・分散1)した後、主成分分析を適用した。 第1主成分(PC1)は寄与率42.6%、第2主成分(PC2)は18.0%で、 PC1+PC2の累積寄与率は60.6%に達する。
| 主成分 | 固有値相当 | 寄与率 | 累積寄与率 |
|---|---|---|---|
| PC1 | 2.98 | 42.6% | 42.6% |
| PC2 | 1.26 | 18.0% | 60.6% |
| PC3 | 0.95 | 13.5% | 74.1% |
| PC4 | 0.73 | 10.5% | 84.6% |
| PC5〜PC7 | — | 15.4% | 100.0% |
| 順位 | 都道府県 | 地方 | PC1スコア | 特徴 |
|---|---|---|---|---|
| 1位 | 島根県 | 中国・四国 | +3.11 | 保育所密度・出生率が高く雇用も充実 |
| 2位 | 宮崎県 | 九州・沖縄 | +3.09 | 出生率が高く地方型の持続可能性 |
| 3位 | 沖縄県 | 九州・沖縄 | +2.93 | 合計特殊出生率1位(1.70) |
| 45位 | 神奈川県 | 関東 | −3.41 | 大学進学率高・出生率低の大都市型 |
| 46位 | 京都府 | 近畿 | −3.39 | 大学集積・若者流出型 |
| 47位 | 東京都 | 関東 | −3.37 | 消費支出最大・出生率全国最低(1.04) |
複数の指標を一つの「総合スコア」に集約する最もよく使われる手法がPCA(主成分分析)。 相関のある変数群を互いに直交(無相関)な主成分に変換し、 第1主成分(最も分散が大きい方向)を「代表スコア」として使う。
76 77 78 79 80 81 82 83 84 85 86 87 88 89 | print("\n" + "=" * 65) print("■ 図1: PCAスコアプロット(PC1 vs PC2)") print("=" * 65) fig1, ax1 = plt.subplots(figsize=(12, 8)) for region in REGION_ORDER: mask = regions == region if mask.sum() == 0: continue ax1.scatter(scores[mask, 0], scores[mask, 1], color=REGION_COLORS[region], s=80, alpha=0.85, edgecolors='white', linewidth=0.7, label=f'{region} (n={mask.sum()})', zorder=3) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。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 | # 都道府県ラベル(全都道府県に短縮名を表示) for i, pref in enumerate(prefectures): short = pref.replace('県', '').replace('都', '').replace('道', '').replace('府', '') ax1.annotate(short, (scores[i, 0], scores[i, 1]), xytext=(3, 3), textcoords='offset points', fontsize=6.5, color='#333', alpha=0.9) ax1.axhline(0, color='gray', linestyle='--', linewidth=0.8, alpha=0.5) ax1.axvline(0, color='gray', linestyle='--', linewidth=0.8, alpha=0.5) ax1.set_xlabel(f'PC1(寄与率 {ev_ratio[0]*100:.1f}%)── 総合持続可能性スコア', fontsize=12) ax1.set_ylabel(f'PC2(寄与率 {ev_ratio[1]*100:.1f}%)── 経済 vs 環境・人口', fontsize=12) ax1.set_title( 'SDGs指標の主成分スコアプロット(2022年, 都道府県別)\n' '〜PC1: 総合持続可能性スコア。右ほど持続可能性が高い傾向〜', fontsize=13, fontweight='bold' ) ax1.legend(loc='lower left', fontsize=9, framealpha=0.88, bbox_to_anchor=(0.0, 0.0)) ax1.grid(True, alpha=0.25) plt.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2022_H5_15_fig1_pca_score.png'), bbox_inches='tight', dpi=150) plt.close(fig1) print("図1保存: 2022_H5_15_fig1_pca_score.png") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。117 118 119 120 121 122 123 124 125 126 | # PC1スコア上位・下位を表示 df_pca = df_sdgs.copy() df_pca['PC1'] = scores[:, 0] df_pca['PC2'] = scores[:, 1] top5 = df_pca.nlargest(5, 'PC1')[['都道府県', '地方', 'PC1', 'PC2']] bot5 = df_pca.nsmallest(5, 'PC1')[['都道府県', '地方', 'PC1', 'PC2']] print(f"\n PC1スコア TOP5(持続可能性が高い都道府県):") print(top5.to_string(index=False)) print(f"\n PC1スコア BOTTOM5(持続可能性が低い都道府県):") print(bot5.to_string(index=False)) |
================================================================= ■ 図1: PCAスコアプロット(PC1 vs PC2) ================================================================= 図1保存: 2022_H5_15_fig1_pca_score.png PC1スコア TOP5(持続可能性が高い都道府県): 都道府県 地方 PC1 PC2 島根県 中国・四国 3.110330 1.572073 宮崎県 九州・沖縄 3.093585 0.257942 沖縄県 九州・沖縄 2.929596 -1.325906 長崎県 九州・沖縄 2.440846 -0.610472 鹿児島県 九州・沖縄 2.240748 -0.081065 PC1スコア BOTTOM5(持続可能性が低い都道府県): 都道府県 地方 PC1 PC2 神奈川県 関東 -3.407123 0.163349 京都府 近畿 -3.394715 -1.163834 東京都 関東 -3.371390 1.390604 埼玉県 関東 -3.325768 0.985651 千葉県 関東 -2.500758 0.026829
np.cumsum(arr) は累積和、np.linspace(a, b, n) は「aからbを等間隔でn個」。NumPyの定石です。主成分の「意味」を解釈するには因子負荷量(factor loadings)を確認する。 因子負荷量は「元の変数が各主成分にどの程度寄与しているか」を示す係数であり、 ヒートマップで可視化することで変数と主成分の関係を一覧できる。
| 指標 | PC1 | PC2 | 解釈 |
|---|---|---|---|
| 保育所密度 | +0.48 | +0.10 | PC1に強く寄与(保育充実 = 高スコア) |
| 合計特殊出生率 | +0.41 | +0.24 | PC1に正寄与(出生率高 = 高スコア) |
| 求人倍率 | +0.29 | +0.45 | PC2に特に大きく寄与(雇用充実) |
| 大学進学率 | −0.48 | −0.05 | PC1に強く負寄与(大都市圏 = 低スコア) |
| 消費支出_log | −0.37 | +0.48 | PC1に負、PC2に正(大都市・消費志向) |
| ごみ排出量_inv | −0.37 | +0.06 | PC1に負(逆数=排出少が多い地方は高排出?) |
| ごみリサイクル率 | −0.14 | +0.70 | PC2に強く寄与(リサイクル先進地域) |
pca.components_ は形状(n_components, n_features)の行列。 転置すると「変数 × 成分」の因子負荷行列になる。 絶対値が大きい変数ほどその成分を強く規定する。
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | print("\n" + "=" * 65) print("■ 図2: 主成分負荷量ヒートマップ") print("=" * 65) N_PC_SHOW = 4 # PC1〜PC4を表示 load_show = loadings[:, :N_PC_SHOW] fig2, ax2 = plt.subplots(figsize=(9, 6)) im = ax2.imshow(load_show, cmap='RdBu_r', vmin=-1, vmax=1, aspect='auto') plt.colorbar(im, ax=ax2, label='因子負荷量', shrink=0.85) ax2.set_xticks(range(N_PC_SHOW)) ax2.set_xticklabels( [f'PC{i+1}\n({ev_ratio[i]*100:.1f}%)' for i in range(N_PC_SHOW)], fontsize=11 ) ax2.set_yticks(range(len(INDICATOR_LABELS))) ax2.set_yticklabels(INDICATOR_LABELS, fontsize=11) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | # セル内に数値を表示 for i in range(len(INDICATOR_COLS)): for j in range(N_PC_SHOW): val = load_show[i, j] color = 'white' if abs(val) > 0.55 else '#222' ax2.text(j, i, f'{val:.2f}', ha='center', va='center', fontsize=10, fontweight='bold', color=color) ax2.set_title( 'SDGs指標の主成分負荷量ヒートマップ(PC1〜PC4)\n' '〜赤:正の負荷(その指標がPCと同方向)、青:負の負荷〜', fontsize=13, fontweight='bold' ) ax2.set_xlabel('主成分(説明した分散の割合)', fontsize=11) ax2.set_ylabel('SDGs指標', fontsize=11) plt.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2022_H5_15_fig2_loadings.png'), bbox_inches='tight', dpi=150) plt.close(fig2) print("図2保存: 2022_H5_15_fig2_loadings.png") print(f"\n 因子負荷量(PC1〜PC4):") df_load = pd.DataFrame(load_show, index=INDICATOR_COLS, columns=[f'PC{i+1}' for i in range(N_PC_SHOW)]) print(df_load.round(3).to_string()) |
=================================================================
■ 図2: 主成分負荷量ヒートマップ
=================================================================
図2保存: 2022_H5_15_fig2_loadings.png
因子負荷量(PC1〜PC4):
PC1 PC2 PC3 PC4
消費支出_log -0.374 0.481 -0.245 0.144
求人倍率 0.289 0.449 -0.418 0.591
ごみリサイクル率 -0.136 0.704 0.188 -0.561
ごみ排出量_inv -0.369 0.057 0.642 0.369
大学進学率 -0.476 -0.049 0.088 0.357
保育所密度 0.476 0.097 0.289 0.041
合計特殊出生率 0.411 0.237 0.476 0.225np.cumsum(arr) は累積和、np.linspace(a, b, n) は「aからbを等間隔でn個」。NumPyの定石です。PCAで2次元に射影したスコアに加え、7指標全体の標準化データを使って 階層的クラスタリング(Ward法)を実行した。 Ward法はクラスター内の分散の増加を最小化するようにクラスターを統合するため、 比較的コンパクトで解釈しやすいクラスターが形成される。
レーダーチャートは極座標系(polar)を使って描く。各指標を等間隔の角度に配置し、 値を半径方向にプロットする。閉じたポリゴンにするために末尾に先頭の値を追加する。
174 175 176 177 178 179 | print("\n" + "=" * 65) print("■ 図3: Ward法クラスタリング デンドログラム") print("=" * 65) # Ward法でクラスタリング(PCA後のスコア全7成分を使用) Z = linkage(X_std, method='ward', metric='euclidean') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。np.cumsum(arr) は累積和、np.linspace(a, b, n) は「aからbを等間隔でn個」。NumPyの定石です。180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | # 都道府県の短縮名リスト pref_short = [p.replace('県', '').replace('都', '').replace('道', '').replace('府', '') for p in prefectures] fig3, ax3 = plt.subplots(figsize=(16, 7)) dn = dendrogram(Z, labels=pref_short, ax=ax3, color_threshold=0.5 * Z[-5:, 2].mean(), leaf_font_size=8.5, leaf_rotation=75) ax3.set_title( 'Ward法クラスタリング デンドログラム(SDGs7指標, 47都道府県)\n' '〜類似した持続可能性プロファイルを持つ都道府県がグループ化される〜', fontsize=13, fontweight='bold' ) ax3.set_xlabel('都道府県', fontsize=11) ax3.set_ylabel('Ward距離(ユークリッド距離)', fontsize=11) ax3.yaxis.grid(True, alpha=0.3) plt.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2022_H5_15_fig3_dendrogram.png'), bbox_inches='tight', dpi=150) plt.close(fig3) print("図3保存: 2022_H5_15_fig3_dendrogram.png") |
================================================================= ■ 図3: Ward法クラスタリング デンドログラム ================================================================= 図3保存: 2022_H5_15_fig3_dendrogram.png
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。{値:.2f}(小数2桁)、{値:,}(3桁区切り)、{値:>10}(右寄せ10桁)など、覚えると出力が一気に整います。解釈しやすい4指標(求人倍率・ごみリサイクル率・大学進学率・合計特殊出生率)を選び、 6地域ブロック(北海道・東北、関東、中部、近畿、中国・四国、九州・沖縄)の平均値を min-max正規化(全国最小=0、全国最大=1)してレーダーチャートで比較した。
| 地方 | 求人倍率 (雇用) | ごみリサイクル率 (環境) |
大学進学率 (教育) | 合計特殊出生率 (人口) |
|---|---|---|---|---|
| 北海道・東北 | 0.50 | 0.20 | 0.16 | 0.25 |
| 関東 | 0.31 | 0.53 | 0.61 | 0.24 |
| 中部 | 0.68 | 0.37 | 0.47 | 0.53 |
| 近畿 | 0.28 | 0.18 | 0.65 | 0.41 |
| 中国・四国 | 0.61 | 0.52 | 0.35 | 0.62 |
| 九州・沖縄 | 0.45 | 0.35 | 0.13 | 0.76 |
SDGsの進捗を評価するには「ベンチマーク(比較基準)」の設定が重要。 本研究ではmin-max正規化により全国最低=0・全国最高=1としたが、 国際比較では「OECD平均」や「SDGs目標値」をベンチマークにすることも多い。 地域格差の「大きさ」は標準偏差で測定できる。
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA from scipy.cluster.hierarchy import dendrogram, linkage from scipy.spatial.distance import pdist 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)。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。227 228 229 230 231 232 233 234 235 236 237 238 239 | scaler = StandardScaler() X_std = scaler.fit_transform(X_raw) pca = PCA(n_components=7) pca.fit(X_std) scores = pca.transform(X_std) # 主成分スコア (47 × 7) loadings = pca.components_.T # 因子負荷行列 (7変数 × 7成分) ev_ratio = pca.explained_variance_ratio_ print(f"\n■ PCA 寄与率:") for i, ev in enumerate(ev_ratio[:5]): cum = ev_ratio[:i+1].sum() print(f" PC{i+1}: {ev*100:.1f}% (累積 {cum*100:.1f}%)") |
■ PCA 寄与率: PC1: 42.6% (累積 42.6%) PC2: 18.0% (累積 60.6%) PC3: 13.5% (累積 74.1%) PC4: 10.5% (累積 84.6%) PC5: 6.0% (累積 90.6%)
StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。240 241 242 243 244 245 246 247 | print("\n" + "=" * 65) print("■ 図4: 地域別レーダーチャート(6地域 × 4指標)") print("=" * 65) # レーダーチャートに使う4指標(解釈しやすいものを選択) RADAR_COLS = ['求人倍率', 'ごみリサイクル率', '大学進学率', '合計特殊出生率'] RADAR_LABELS = ['求人倍率\n(雇用)', 'ごみリサイクル率\n(環境)', '大学進学率\n(教育)', '合計特殊出生率\n(人口)'] |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。{値:.2f}(小数2桁)、{値:,}(3桁区切り)、{値:>10}(右寄せ10桁)など、覚えると出力が一気に整います。248 249 250 251 252 253 254 255 256 257 258 | # 地域別平均を計算(正規化用に全国平均・標準偏差を使用) df_radar = df_sdgs[['地方'] + RADAR_COLS].copy() region_means = df_radar.groupby('地方')[RADAR_COLS].mean() # 全国平均・SD で0〜1正規化(各列を min-max スケール) col_min = df_sdgs[RADAR_COLS].min() col_max = df_sdgs[RADAR_COLS].max() region_norm = (region_means - col_min) / (col_max - col_min) print("\n 地域別 正規化スコア(0〜1スケール):") print(region_norm.round(3).to_string()) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。259 260 261 262 263 264 265 | # レーダーチャートの角度計算 N_VARS = len(RADAR_COLS) angles = np.linspace(0, 2 * np.pi, N_VARS, endpoint=False).tolist() angles += angles[:1] # 閉じるために先頭を末尾に追加 fig4, ax4 = plt.subplots(figsize=(10, 8), subplot_kw=dict(projection='polar')) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。.dropna() は欠損行を除去、.copy() は独立したコピーを作る。pandasで警告を防ぐ定石。266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | # 全体の平均をグレーの参照線として描画 national_mean = np.ones(N_VARS) * 0.5 # 正規化後の中央値(参考) vals_nat = national_mean.tolist() + national_mean[:1].tolist() ax4.plot(angles, vals_nat, 'k--', linewidth=1.0, alpha=0.4, label='_nolegend_') ax4.fill(angles, vals_nat, color='gray', alpha=0.08) # 各地域をプロット for region in REGION_ORDER: if region not in region_norm.index: continue vals = region_norm.loc[region, RADAR_COLS].values.tolist() vals += vals[:1] # 閉じる ax4.plot(angles, vals, color=REGION_COLORS[region], linewidth=2.2, label=region, alpha=0.9) ax4.fill(angles, vals, color=REGION_COLORS[region], alpha=0.12) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | # 軸ラベル設定 ax4.set_xticks(angles[:-1]) ax4.set_xticklabels(RADAR_LABELS, fontsize=10.5) ax4.set_ylim(0, 1) ax4.set_yticks([0.25, 0.5, 0.75]) ax4.set_yticklabels(['25%', '50%', '75%'], fontsize=8, color='#666') ax4.set_title( '地域別 SDGs4指標 レーダーチャート(2022年)\n' '〜各指標を全国min-max正規化。グレー点線は中央値(0.5)〜', fontsize=13, fontweight='bold', pad=20 ) ax4.legend(loc='lower left', bbox_to_anchor=(-0.18, -0.08), fontsize=9.5, framealpha=0.88) ax4.grid(True, alpha=0.3) plt.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2022_H5_15_fig4_radar.png'), bbox_inches='tight', dpi=150) plt.close(fig4) print("図4保存: 2022_H5_15_fig4_radar.png") |
=================================================================
■ 図4: 地域別レーダーチャート(6地域 × 4指標)
=================================================================
地域別 正規化スコア(0〜1スケール):
求人倍率 ごみリサイクル率 大学進学率 合計特殊出生率
地方
中国・四国 0.610 0.523 0.351 0.621
中部 0.684 0.367 0.466 0.525
九州・沖縄 0.446 0.349 0.127 0.756
北海道・東北 0.496 0.201 0.163 0.249
近畿 0.276 0.180 0.647 0.411
関東 0.309 0.528 0.608 0.240
図4保存: 2022_H5_15_fig4_radar.pngdf['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | print("\n" + "=" * 65) print("■ 全図生成完了(4枚)") print(f" fig1_pca_score.png : PCAスコアプロット(PC1 vs PC2, 地域色分け)") print(f" fig2_loadings.png : 変数の主成分負荷量ヒートマップ") print(f" fig3_dendrogram.png : Ward法クラスタリング デンドログラム") print(f" fig4_radar.png : 地域別レーダーチャート(6地域 × 4指標)") print("=" * 65) print(f"\n■ PCA寄与率サマリ:") for i in range(4): print(f" PC{i+1}: {ev_ratio[i]*100:.1f}% (累積: {ev_ratio[:i+1].sum()*100:.1f}%)") print(f"\n■ PC1スコア上位5都道府県(持続可能性が高い):") print(top5[['都道府県', '地方', 'PC1']].to_string(index=False)) print(f"\n■ PC1スコア下位5都道府県(持続可能性が低い):") print(bot5[['都道府県', '地方', 'PC1']].to_string(index=False)) |
================================================================= ■ 全図生成完了(4枚) fig1_pca_score.png : PCAスコアプロット(PC1 vs PC2, 地域色分け) fig2_loadings.png : 変数の主成分負荷量ヒートマップ fig3_dendrogram.png : Ward法クラスタリング デンドログラム fig4_radar.png : 地域別レーダーチャート(6地域 × 4指標) ================================================================= ■ PCA寄与率サマリ: PC1: 42.6% (累積: 42.6%) PC2: 18.0% (累積: 60.6%) PC3: 13.5% (累積: 74.1%) PC4: 10.5% (累積: 84.6%) ■ PC1スコア上位5都道府県(持続可能性が高い): 都道府県 地方 PC1 島根県 中国・四国 3.110330 宮崎県 九州・沖縄 3.093585 沖縄県 九州・沖縄 2.929596 長崎県 九州・沖縄 2.440846 鹿児島県 九州・沖縄 2.240748 ■ PC1スコア下位5都道府県(持続可能性が低い): 都道府県 地方 PC1 神奈川県 関東 -3.407123 京都府 近畿 -3.394715 東京都 関東 -3.371390 埼玉県 関東 -3.325768 千葉県 関東 -2.500758
plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。SSDSE-B 2022年データから構築した7指標に主成分分析を適用した結果、 都道府県の「SDGs持続可能性スコア」の構造が以下のとおり明らかになった。
| データ | 出典 | 主な変数 |
|---|---|---|
| SSDSE-B-2026.csv(都道府県データ) | 統計数理研究所・統計センター | 消費支出、求人数、ごみ排出量、リサイクル率、進学者数、保育所数、出生率 |
| SDGs関連7指標(派生変数) | SSDSE-B より計算 | 消費支出_log、求人倍率、ごみリサイクル率、ごみ排出量_inv、大学進学率、保育所密度、合計特殊出生率 |
本教育用コードはSSDSE-B-2026.csvの実データのみを使用(合成データ・乱数使用なし)。 図の再現には scikit-learn, scipy, matplotlib, pandas, numpy が必要。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。