このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
日本の少子高齢化は世界最速水準で進行しており、2023年度の全国平均高齢化率(65歳以上人口比率)は約31.6%に達している。しかし都道府県間では大きな差があり、高齢化が急速に進む地域への先制的な社会保障投資を検討するためには、科学的な将来予測が欠かせない。
まず「都道府県別高齢化率の時系列分析と将来予測指数平滑法・Holt線形トレンドモデル」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
本研究では、SSDSE-B(都道府県別統計データ)を用いて2012〜2023年の高齢化率時系列データを分析し、指数平滑法(SES)とHolt線形トレンドモデルという2つの予測モデルを比較・評価する。
SSDSE-B 時系列分析 指数平滑法 Holt線形トレンド RMSE・MAE ACF
SSDSE(社会・人口統計体系データセット)-B は、都道府県レベルの統計データを年度別に収録した公的データセットである。本分析では「65歳以上人口」と「総人口」から高齢化率を計算した。
| 項目 | 内容 |
|---|---|
| データソース | SSDSE-B-2026.csv(統計数理研究所) |
| 対象 | 47都道府県 |
| 期間 | 2012〜2023年度(12時点) |
| 分析指標 | 65歳以上人口比率(高齢化率) |
| 全国平均(2012年) | 約 25.6% |
| 全国平均(2023年) | 約 31.6% |
| 12年間の上昇幅 | 約 6.0 ポイント |
| 順位 | 都道府県 | 高齢化率 | 特徴 |
|---|---|---|---|
| 最高 | 秋田県 | 約 39% | 過疎・少子化が深刻 |
| 2位 | 高知県・島根県 | 約 36〜37% | 中山間地域の高齢化 |
| — | 全国平均 | 約 31.6% | — |
| 46位 | 神奈川県・埼玉県 | 約 25〜26% | 首都圏:若年層流入 |
| 最低 | 沖縄県 | 約 22% | 出生率が高く若年人口多 |
2023年度の47都道府県を高齢化率で昇順に並べた棒グラフを示す。地域ごとに色分けして、地域間の傾向を視覚化している。
指数平滑法(SES)は、過去の観測値に指数的に減衰する重みをつけて予測値を計算する方法である。α(0 < α < 1)は「直近データをどれだけ重視するか」を制御するパラメータ。
αが大きいほど直近データを重視し、αが小さいほど過去データを重視(記憶が長い)。statsmodels では optimized=True で最適 α が自動選択される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import os import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.ticker as mticker import statsmodels.api as sm from statsmodels.tsa.holtwinters import ExponentialSmoothing, SimpleExpSmoothing from statsmodels.graphics.tsaplots import plot_acf from sklearn.metrics import mean_squared_error, mean_absolute_error plt.rcParams['font.family'] = 'Hiragino Sans' plt.rcParams['axes.unicode_minus'] = False plt.rcParams['figure.dpi'] = 150 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)。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。20 21 22 23 24 25 26 27 | # ── データ読み込み ────────────────────────────────────── 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) print("Columns:", df_b.columns.tolist()) print("Years:", sorted(df_b['年度'].unique())) print("Shape:", df_b.shape) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。.astype(int) — 列を整数に変換(年度などを数値比較するため)。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。28 29 30 31 32 33 34 35 36 37 38 | # 高齢化率を計算(65歳以上人口 / 総人口 × 100) df_b['高齢化率'] = df_b['65歳以上人口'] / df_b['総人口'] * 100 aging_col = '高齢化率' print(f"\n高齢化率 統計: \n{df_b[aging_col].describe()}") # 都道府県名の正規化(「県」「都」「道」「府」を除く短縮名) def shorten_pref(name): return name.replace('県','').replace('都','').replace('道','').replace('府','') df_b['都道府県短'] = df_b['都道府県'].apply(shorten_pref) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.describe() — 件数・平均・標準偏差・四分位・最大/最小を一括計算。データの素性チェックに必須。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | # 地域マッピング(短縮名ベース) region_map = { '北海道': '北海道・東北', '青森': '北海道・東北', '岩手': '北海道・東北', '宮城': '北海道・東北', '秋田': '北海道・東北', '山形': '北海道・東北', '福島': '北海道・東北', '茨城': '関東', '栃木': '関東', '群馬': '関東', '埼玉': '関東', '千葉': '関東', '東京': '関東', '神奈川': '関東', '新潟': '中部', '富山': '中部', '石川': '中部', '福井': '中部', '山梨': '中部', '長野': '中部', '岐阜': '中部', '静岡': '中部', '愛知': '中部', '三重': '近畿', '滋賀': '近畿', '京都': '近畿', '大阪': '近畿', '兵庫': '近畿', '奈良': '近畿', '和歌山': '近畿', '鳥取': '中国・四国', '島根': '中国・四国', '岡山': '中国・四国', '広島': '中国・四国', '山口': '中国・四国', '徳島': '中国・四国', '香川': '中国・四国', '愛媛': '中国・四国', '高知': '中国・四国', '福岡': '九州・沖縄', '佐賀': '九州・沖縄', '長崎': '九州・沖縄', '熊本': '九州・沖縄', '大分': '九州・沖縄', '宮崎': '九州・沖縄', '鹿児島': '九州・沖縄', '沖縄': '九州・沖縄' } region_colors = { '北海道・東北': '#4e9af1', '関東': '#e05c5c', '中部': '#f0a500', '近畿': '#5cb85c', '中国・四国': '#9b59b6', '九州・沖縄': '#f39c12' } df_b['地域'] = df_b['都道府県短'].map(region_map).fillna('その他') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。62 63 64 65 66 67 68 69 70 71 | # ── 全国平均時系列 ────────────────────────────────────── nat_avg = df_b.groupby('年度')[aging_col].mean().sort_index() years = nat_avg.index.values print(f"\n全国平均高齢化率(年度別):\n{nat_avg}") # ── Simple Exponential Smoothing (SES) ────────────────── ses = SimpleExpSmoothing(nat_avg.values).fit(optimized=True) ses_fitted = ses.fittedvalues ses_forecast = ses.forecast(3) print(f"\nSES alpha={ses.params['smoothing_level']:.4f}") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | # ── Holt 線形トレンドモデル ────────────────────────────── holt = ExponentialSmoothing(nat_avg.values, trend='add').fit(optimized=True) holt_fitted = holt.fittedvalues holt_forecast = holt.forecast(3) print(f"Holt alpha={holt.params['smoothing_level']:.4f}, beta={holt.params['smoothing_trend']:.4f}") # ── 予測精度 ──────────────────────────────────────────── rmse_ses = np.sqrt(mean_squared_error(nat_avg.values[1:], ses_fitted[1:])) rmse_holt = np.sqrt(mean_squared_error(nat_avg.values[1:], holt_fitted[1:])) mae_ses = mean_absolute_error(nat_avg.values[1:], ses_fitted[1:]) mae_holt = mean_absolute_error(nat_avg.values[1:], holt_fitted[1:]) print(f"SES RMSE={rmse_ses:.4f}, MAE={mae_ses:.4f}") print(f"Holt RMSE={rmse_holt:.4f}, MAE={mae_holt:.4f}") forecast_years = np.array([years[-1]+1, years[-1]+2, years[-1]+3]) latest_year = int(nat_avg.index.max()) df_latest = df_b[df_b['年度'] == latest_year].copy() df_latest = df_latest.sort_values(aging_col, ascending=True).reset_index(drop=True) nat_mean_latest = nat_avg[latest_year] fig1, ax1 = plt.subplots(figsize=(10, 12)) bar_colors = [region_colors.get(r, '#aaaaaa') for r in df_latest['地域']] bars = ax1.barh(df_latest['都道府県短'], df_latest[aging_col], color=bar_colors, edgecolor='white', linewidth=0.4, height=0.75) ax1.axvline(nat_mean_latest, color='black', linestyle='--', linewidth=1.8, label=f'全国平均 {nat_mean_latest:.1f}%') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | # 凡例(地域色) import matplotlib.patches as mpatches legend_patches = [mpatches.Patch(color=c, label=r) for r, c in region_colors.items()] legend_patches.append(mpatches.Patch(color='black', label=f'全国平均 {nat_mean_latest:.1f}%', fill=False, linestyle='--')) ax1.legend(handles=legend_patches, loc='lower right', fontsize=9, framealpha=0.9) ax1.set_xlabel('高齢化率(65歳以上人口比率)[%]', fontsize=11) ax1.set_title(f'都道府県別高齢化率ランキング({latest_year}年度)\n地域色分け・全国平均点線', fontsize=13, fontweight='bold') ax1.set_xlim(0, max(df_latest[aging_col]) * 1.08) ax1.xaxis.set_major_formatter(mticker.FormatStrFormatter('%.0f%%')) ax1.grid(axis='x', linestyle=':', alpha=0.5) fig1.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2018_H3_fig1.png'), bbox_inches='tight') plt.close(fig1) print("Saved fig1") |
Columns: ['年度', '地域コード', '都道府県', '総人口', '総人口(男)', '総人口(女)', '日本人人口', '日本人人口(男)', '日本人人口(女)', '15歳未満人口', '15歳未満人口(男)', '15歳未満人口(女)', '15~64歳人口', '15~64歳人口(男)', '15~64歳人口(女)', '65歳以上人口', '65歳以上人口(男)', '65歳以上人口(女)', '出生数', '出生数(男)', '出生数(女)', '合計特殊出生率', '死亡数', '死亡数(男)', '死亡数(女)', '転入者数(日本人移動者)', '転入者数(日本人移動者)(男)', '転入者数(日本人移動者)(女)', '転出者数(日本人移動者)', '転出者数(日本人移動者)(男)', '転出者数(日本人移動者)(女)', '婚姻件数', '離婚件数', '年平均気温', '最高気温(日最高気温の月平均の最高値)', '最低気温(日最低気温の月平均の最低値)', '降水日数(年間)', '降水量(年間)', '着工建築物数', '着工建築物床面積', '旅館営業施設数(ホテルを含む)', '旅館営業施設客室数(ホテルを含む)', '標準価格(平均価格)(住宅地)', '標準価格(平均価格)(商業地)', '幼稚園数', '幼稚園教員数', '幼稚園在園者数', '小学校数', '小学校教員数', '小学校児童数', '中学校数', '中学校教員数', '中学校生徒数', '中学校卒業者数', '中学校卒業者のうち進学者数', '高等学校数', '高等学校教員数', '高等学校生徒数', '高等学校卒業者数', '高等学校卒業者のうち進学者数', '短期大学数', '大学数', '短期大学教員数', '大学教員数', '短期大学学生数', '大学学生数', '短期大学卒業者数', '短期大学卒業者のうち進学者数', '大学卒業者数', '大学卒業者のうち進学者数', '専修学校数', '各種学校数', '専修学校生徒数', '各種学校生徒数', '新規求職申込件数(一般)', '月間有効求職者数(一般)', '月間有効求人数(一般)', '充足数(一般)', '就職件数(一般)', '一般旅券発行件数', '延べ宿泊者数', '外国人延べ宿泊者数', '着工新設住宅戸数', '着工新設持家数', '着工新設貸家数', '着工新設分譲住宅数', '着工新設住宅床面積', '着工新設持家床面積', '着工新設分譲住宅床面積', '着工新設貸家床面積', 'ごみ総排出量(総量)', '1人1日当たりの排出量', 'ごみのリサイクル率', '一般病院数', '一般診療所数', '歯科診療所数', '保育所等数', '保育所等定員数', '保育所等利用待機児童数', '保育所等在所児数', '保育所等保育士数', '消費支出(二人以上の世帯)', '食料費(二人以上の世帯)', '住居費(二人以上の世帯)', '光熱・水道費(二人以上の世帯)', '家具・家事用品費(二人以上の世帯)', '被服及び履物費(二人以上の世帯)', '保健医療費(二人以上の世帯)', '交通・通信費(二人以上の世帯)', '教育費(二人以上の世帯)', '教養娯楽費(二人以上の世帯)', 'その他の消費支出(二人以上の世帯)'] Years: [np.int64(2012), np.int64(2013), np.int64(2014), np.int64(2015), np.int64(2016), np.int64(2017), np.int64(2018), np.int64(2019), np.int64(2020), np.int64(2021), np.int64(2022), np.int64(2023)] Shape: (564, 112) 高齢化率 統計: count 564.000000 mean 29.239736 std 3.479207 min 17.717931 25% 27.033139 50% 29.471963 75% 31.756432 max 39.059081 Name: 高齢化率, dtype: float64 全国平均高齢化率(年度別): 年度 2012 25.623803 2013 26.550323 2014 27.489833 2015 27.994066 2016 28.962795 2017 29.525488 2018 30.008401 2019 30.415235 2020 30.257000 2021 31.113973 2022 31.350024 2023 31.585892 Name: 高齢化率, dtype: float64 SES alpha=1.0000 Holt alpha=1.0000, beta=0.0000 SES RMSE=0.6410, MAE=0.5708 Holt RMSE=0.3422, MAE=0.2808 Saved fig1
import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。全国平均高齢化率の時系列(2012〜2023年)に対して、SESとHolt線形トレンドモデルを適合させ、3年先(2024〜2026年)の予測を行う。
| モデル | α(平滑化係数) | β(トレンド係数) | RMSE | MAE | 評価 |
|---|---|---|---|---|---|
| SES(単純指数平滑法) | 1.000 | — | 0.641 | 0.571 | — |
| Holt 線形トレンド | 1.000 | 0.000 | 0.342 | 0.281 | 優(RMSE -47%) |
Holt モデルは「レベル」と「トレンド(傾き)」の2成分を別々に指数平滑する。αはレベルの更新速度、βはトレンドの更新速度を制御する。
β=0 のとき、トレンドは初期値から変化しない(一定傾きで外挿)。高齢化率のように安定したトレンドがある場合はβが小さい値になりやすい。
118 119 120 121 122 123 124 125 126 127 128 129 130 | fig2, ax2 = plt.subplots(figsize=(11, 6)) ax2.plot(years, nat_avg.values, 'ko-', linewidth=2, markersize=6, label='実績値', zorder=5) ax2.plot(years, ses_fitted, 'b-', linewidth=1.8, alpha=0.85, label=f'SES(α={ses.params["smoothing_level"]:.3f})RMSE={rmse_ses:.3f}') ax2.plot(forecast_years, ses_forecast, 'b--', linewidth=1.8, alpha=0.85) ax2.plot([years[-1], forecast_years[0]], [ses_fitted[-1], ses_forecast[0]], 'b--', linewidth=1.8, alpha=0.85) ax2.plot(years, holt_fitted, 'r-', linewidth=1.8, alpha=0.85, label=f'Holt線形(α={holt.params["smoothing_level"]:.3f}, β={holt.params["smoothing_trend"]:.3f})RMSE={rmse_holt:.3f}') ax2.plot(forecast_years, holt_forecast, 'r--', linewidth=1.8, alpha=0.85) ax2.plot([years[-1], forecast_years[0]], [holt_fitted[-1], holt_forecast[0]], 'r--', linewidth=1.8, alpha=0.85) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | # 予測区間帯 ax2.axvspan(years[-1], forecast_years[-1], alpha=0.06, color='gray', label='予測期間') ax2.axvline(years[-1], color='gray', linestyle=':', linewidth=1) ax2.text(years[-1]+0.1, ax2.get_ylim()[0] if ax2.get_ylim()[0] > 0 else 20, '← 実績 予測 →', fontsize=9, color='gray', va='bottom') ax2.set_xlabel('年度', fontsize=11) ax2.set_ylabel('高齢化率(全国平均)[%]', fontsize=11) ax2.set_title('全国平均高齢化率の時系列分析\n指数平滑法(SES)・Holt線形トレンドモデル + 3年先予測', fontsize=13, fontweight='bold') ax2.legend(fontsize=10, loc='upper left') ax2.set_xticks(list(years) + list(forecast_years)) ax2.set_xticklabels([str(y) for y in years] + [f'{y}(予)' for y in forecast_years], rotation=45, ha='right', fontsize=9) ax2.yaxis.set_major_formatter(mticker.FormatStrFormatter('%.1f%%')) ax2.grid(linestyle=':', alpha=0.5) fig2.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2018_H3_fig2.png'), bbox_inches='tight') plt.close(fig2) print("Saved fig2") |
Saved fig2
ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。時系列データの自己相関関数(ACF: Autocorrelation Function)は、ある時点の値が過去の値とどの程度相関しているかを示す。ACFプロットは時系列の特性(トレンド・季節性・定常性)を診断するための重要なツールである。
予測モデルの精度は、フィット値と実績値の誤差を集計する指標で評価する。代表的な指標は RMSE(二乗平均平方根誤差)と MAE(平均絶対誤差)の2つ。
RMSE は大きな誤差を強くペナルティするため、異常値・外れ値に敏感。MAE は全誤差を均等に扱うため解釈が直感的。両指標を並記して判断することが重要。
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | fig3, ax3 = plt.subplots(figsize=(10, 4)) max_lags = min(8, len(nat_avg) - 2) plot_acf(nat_avg.values, lags=max_lags, ax=ax3, title='自己相関関数 (ACF):全国平均高齢化率', alpha=0.05) ax3.set_xlabel('ラグ(年)', fontsize=11) ax3.set_ylabel('自己相関係数', fontsize=11) ax3.set_title('自己相関関数 (ACF):全国平均高齢化率\n(高い自己相関は強いトレンドの存在を示す)', fontsize=12, fontweight='bold') # 解説注釈 ax3.text(0.02, 0.05, '青い影:95%信頼区間\nバーが区間外 → 有意な自己相関あり', transform=ax3.transAxes, fontsize=9, color='#1565C0', va='bottom', bbox=dict(boxstyle='round,pad=0.3', facecolor='#EFF3FF', alpha=0.8)) fig3.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2018_H3_fig3.png'), bbox_inches='tight') plt.close(fig3) print("Saved fig3") |
Saved fig3
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。47都道府県を6地域に集約し、地域ごとの高齢化率の推移(2012〜2023年)と最新年の格差を比較する。全国平均の上昇に対して、地域によってその速度が異なることが分かる。
| 地域 | 2023年平均高齢化率(概算) | 特徴 |
|---|---|---|
| 北海道・東北 | ~33〜35% | 最も高い。人口流出・少子化が複合 |
| 中国・四国 | ~33〜34% | 島根・高知・鳥取など過疎地域が牽引 |
| 近畿 | ~30〜31% | 和歌山・奈良と大阪・滋賀で格差 |
| 中部 | ~29〜30% | 愛知(低)と富山・福井(高)が混在 |
| 九州・沖縄 | ~28〜30% | 沖縄が大幅に低い(出生率高) |
| 関東 | ~26〜27% | 最も低い。東京・神奈川が若年人口を吸引 |
時系列分析では「定常性(stationarity)」が重要な前提となる。定常な時系列とは、平均・分散・自己相関が時間によって変化しない系列のこと。高齢化率のように一方向にトレンドが続く系列は非定常であり、多くの古典的分析手法は非定常系列に直接適用できない。
ACF が高いラグで有意に残る場合はトレンドの存在を示す。1階差分(Δy_t = y_t − y_{t-1})を取ることで定常化し、ARIMA モデルを適用可能になる。
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | df_region = df_b.copy() region_ts = df_region.groupby(['年度', '地域'])[aging_col].mean().reset_index() fig4, axes = plt.subplots(1, 2, figsize=(14, 6)) ax4L, ax4R = axes # 左:時系列折れ線 for region, color in region_colors.items(): sub = region_ts[region_ts['地域'] == region].sort_values('年度') if len(sub) == 0: continue ax4L.plot(sub['年度'], sub[aging_col], '-o', color=color, linewidth=2, markersize=5, label=region) ax4L.set_xlabel('年度', fontsize=11) ax4L.set_ylabel('高齢化率(地域平均)[%]', fontsize=11) ax4L.set_title('6地域別 高齢化率の時系列推移\n(2012〜2023年)', fontsize=12, fontweight='bold') ax4L.legend(fontsize=9, loc='upper left') ax4L.set_xticks(sorted(df_b['年度'].unique())) ax4L.set_xticklabels([str(y) for y in sorted(df_b['年度'].unique())], rotation=45, ha='right', fontsize=8) ax4L.yaxis.set_major_formatter(mticker.FormatStrFormatter('%.0f%%')) ax4L.grid(linestyle=':', alpha=0.5) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | # 右:最新年の地域格差(棒グラフ) latest_region = region_ts[region_ts['年度'] == latest_year].copy() latest_region = latest_region.sort_values(aging_col, ascending=False) bar_cols_r = [region_colors.get(r, '#aaaaaa') for r in latest_region['地域']] ax4R.bar(latest_region['地域'], latest_region[aging_col], color=bar_cols_r, edgecolor='white', linewidth=0.4) ax4R.axhline(nat_mean_latest, color='black', linestyle='--', linewidth=1.8, label=f'全国平均 {nat_mean_latest:.1f}%') ax4R.set_xlabel('地域', fontsize=11) ax4R.set_ylabel('高齢化率(地域平均)[%]', fontsize=11) ax4R.set_title(f'{latest_year}年度の地域間格差\n(6地域別平均 vs 全国平均)', fontsize=12, fontweight='bold') ax4R.legend(fontsize=10) ax4R.set_xticklabels(latest_region['地域'], rotation=25, ha='right', fontsize=9) ax4R.yaxis.set_major_formatter(mticker.FormatStrFormatter('%.0f%%')) ax4R.grid(axis='y', linestyle=':', alpha=0.5) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | # 値ラベル for bar, val in zip(ax4R.patches, latest_region[aging_col]): ax4R.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.15, f'{val:.1f}%', ha='center', va='bottom', fontsize=9, fontweight='bold') fig4.suptitle('地域別高齢化率の時系列分析と地域格差', fontsize=14, fontweight='bold', y=1.01) fig4.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2018_H3_fig4.png'), bbox_inches='tight') plt.close(fig4) print("Saved fig4") print("\nDONE: 2018_H3_suri") print(f"SES alpha={ses.params['smoothing_level']:.4f} RMSE={rmse_ses:.4f} MAE={mae_ses:.4f}") print(f"Holt alpha={holt.params['smoothing_level']:.4f}, beta={holt.params['smoothing_trend']:.4f} RMSE={rmse_holt:.4f} MAE={mae_holt:.4f}") print(f"SES 3年先予測: {ses_forecast}") print(f"Holt 3年先予測: {holt_forecast}") |
<string>:38: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator. Saved fig4 DONE: 2018_H3_suri SES alpha=1.0000 RMSE=0.6410 MAE=0.5708 Holt alpha=1.0000, beta=0.0000 RMSE=0.3422 MAE=0.2808 SES 3年先予測: [31.58589175 31.58589175 31.58589175] Holt 3年先予測: [32.1278998 32.66990784 33.21191588]
x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。| データ | 出典 |
|---|---|
| SSDSE-B-2026.csv(都道府県別統計) | 統計数理研究所 SSDSE(社会・人口統計体系データセット) |
| 65歳以上人口・総人口 | 総務省 住民基本台帳人口移動報告 |
本教育用コードは SSDSE-B-2026.csv の実データのみを使用。合成データ(np.random.seed 等)は一切使用していない。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。