このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
日本の空き家問題は深刻化しており、2018年時点で空き家数は約849万戸、空き家率は13.6%に達している。この問題の背景には人口減少・転出超過・高齢化という構造的な要因がある。本研究は都道府県別の統計データを用いて、これらの人口動態要因が住宅建設と地価に与える影響を定量的に分析する。
まず「空き家問題と人口減少転出超過・高齢化が住宅に与える影響」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
SSDSE-B 転出超過率 高齢化率 OLS回帰 住宅地地価
SSDSE-B(都道府県別社会・人口統計体系データセット)を使用。直接的な「空き家数・空き家率」のデータは同データセットに含まれないため、下記の代理変数を用いて空き家問題の構造を分析する。
| 変数名 | 定義 | SSDSE-Bの元変数 | 空き家との関係 |
|---|---|---|---|
| 着工新設住宅率 | 着工新設住宅戸数 / 総人口 × 10,000 | H1800, A1101 | 高いほど供給過剰リスク(→空き家増加) |
| 転出超過率 | (転出者数 − 転入者数) / 総人口 × 1,000 | A5102, A5101, A1101 | 正値(転出超過)ほど空き家増加 |
| 高齢化率 | 65歳以上人口 / 総人口 × 100 | A1303, A1101 | 高いほど将来的空き家予備軍が多い |
| 住宅地地価 | 標準価格(平均価格)(住宅地) | C5401 | 地域の住宅需要・活力の指標 |
| 消費支出_log | log(消費支出(二人以上の世帯)) | L3221 | 所得水準の代理 |
| 求人倍率 | 月間有効求人数 / 月間有効求職者数 | F3103, F3102 | 雇用環境→人口定着力 |
直接指標(空き家数)が入手困難な場合、理論的に関連する変数を「代理変数(proxy variable)」として使う。重要なのは「どの代理変数が空き家のどの側面を捉えているか」を明確にすることだ。
本分析では2つの軸で代理変数を設計する:
供給側:着工新設住宅率 → 新規建設が需要を上回ると既存住宅が余剰に
需要側:転出超過率・高齢化率 → 人口が減ると住宅需要が低下
| 変数 | 平均 | 標準偏差 | 最小 | 最大 |
|---|---|---|---|---|
| 着工新設住宅率(万人あたり戸数) | 59.9 | 12.3 | 39.7 | 96.4 |
| 転出超過率(‰) | 1.31 | 1.76 | −3.0 | 4.0 |
| 高齢化率(%) | 31.4 | 3.3 | 22.8 | 38.6 |
| 住宅地地価(万円/m²) | 5.34 | 6.20 | 1.32 | 38.9 |
| 消費支出(二人以上世帯、万円/月) | 29.0 | 2.0 | 24.7 | 33.1 |
| 求人倍率(倍) | 1.39 | 0.25 | 0.88 | 1.94 |
| 変数 | 着工新設住宅率との相関 | 解釈 |
|---|---|---|
| 転出超過率 | −0.754** | 転出超過が多いと着工が少ない(需要低迷) |
| 高齢化率 | −0.790** | 高齢化が進む地域ほど着工が少ない |
| 住宅地地価 | +0.659** | 地価が高い地域ほど着工が多い |
| 消費支出_log | +0.281* | 所得水準が高いと着工も多い |
| 求人倍率 | −0.206 | 弱い負相関(非有意) |
** p<0.01, * p<0.05, 無印 n.s.(非有意)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | print("\n=== 2022年 変数サマリー ===") summary_cols = ['着工新設住宅率', '転出超過率', '高齢化率', '標準価格(平均価格)(住宅地)', '消費支出_log', '求人倍率'] summary_labels = ['着工新設住宅率', '転出超過率', '高齢化率', '住宅地地価', '消費支出_log', '求人倍率'] print(df2022[summary_cols].describe().round(3)) # 相関行列 print("\n=== 相関係数(2022年) ===") corr_df = df2022[summary_cols].rename(columns=dict(zip(summary_cols, summary_labels))) print(corr_df.corr().round(3)) print("\n全図の保存完了。") print(f" 保存先: {os.path.abspath(FIG_DIR)}") |
=== 2022年 変数サマリー ===
着工新設住宅率 転出超過率 高齢化率 標準価格(平均価格)(住宅地) 消費支出_log 求人倍率
count 47.000 47.000 47.000 47.000 47.000 47.000
mean 59.870 1.305 31.350 53372.340 12.574 1.394
std 12.270 1.764 3.269 61991.622 0.067 0.247
min 39.744 -2.991 22.810 13200.000 12.409 0.881
25% 52.831 0.536 29.847 25300.000 12.531 1.184
50% 57.553 1.626 31.421 30800.000 12.570 1.435
75% 65.795 2.403 33.720 55500.000 12.619 1.570
max 96.440 4.032 38.602 389100.000 12.691 1.940
=== 相関係数(2022年) ===
着工新設住宅率 転出超過率 高齢化率 住宅地地価 消費支出_log 求人倍率
着工新設住宅率 1.000 -0.754 -0.790 0.659 0.281 -0.206
転出超過率 -0.754 1.000 0.725 -0.603 -0.431 0.462
高齢化率 -0.790 0.725 1.000 -0.694 -0.348 0.391
住宅地地価 0.659 -0.603 -0.694 1.000 0.338 -0.294
消費支出_log 0.281 -0.431 -0.348 0.338 1.000 -0.012
求人倍率 -0.206 0.462 0.391 -0.294 -0.012 1.000
全図の保存完了。
保存先: /Users/shimpei/Dropbox/Works_Researches/2026 統計・データ解析コンペ/html/figures.describe() — 件数・平均・標準偏差・四分位・最大/最小を一括計算。データの素性チェックに必須。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。2012〜2022年にわたる転出超過率(‰ = 千人あたり)の推移を、代表的な4都道府県(東京・大阪・秋田・島根)で比較する。転出超過率が正の場合は「人口流出」、負の場合は「人口流入」を意味する。
東京の転出超過者数(絶対数)は秋田より多くなることがある。しかし「問題の深刻さ」を比較するには人口規模で割った「相対数(‰)」が適切だ。
統計分析では「実数」と「人口あたり比率」の使い分けが重要。政策論議では比率を使わないと「大きい県が常に問題」という誤解が生じる。
16 17 18 19 20 21 22 23 24 25 26 27 28 | import os import warnings import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.ticker as mticker from matplotlib import rcParams import statsmodels.api as sm from scipy import stats warnings.filterwarnings('ignore') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。matplotlib.use('Agg') — グラフを画面表示せずファイルに保存するためのおまじない。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。29 30 31 32 33 34 35 36 37 38 | # ── パス設定 ────────────────────────────────────────────── FIG_DIR = 'html/figures' DATA_B = 'data/raw/SSDSE-B-2026.csv' os.makedirs(FIG_DIR, exist_ok=True) # ── フォント設定 ─────────────────────────────────────────── rcParams['font.family'] = ['Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'AppleGothic', 'Noto Sans CJK JP', 'sans-serif'] rcParams['axes.unicode_minus'] = False |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。os.makedirs('html/figures', exist_ok=True) — 図の保存先フォルダを作る(既にあってもOK)。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。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 | # ── データ読み込み ──────────────────────────────────────── def load_ssdse_b(path): """SSDSE-B-2026.csv を読み込んで整形する。 1行目がコード行、2行目が日本語ラベル行、3行目以降がデータ。 """ raw = pd.read_csv(path, header=0, encoding='cp932') # 行0はJapanese labels、行1以降が実データ data = raw.iloc[1:].copy().reset_index(drop=True) data.columns = raw.columns # 列名を日本語ラベルにリネーム label_row = raw.iloc[0] rename_map = {col: label_row[col] for col in raw.columns} data = data.rename(columns=rename_map) # 年度列を整数に data = data.rename(columns={'年度': 'year', '都道府県': 'pref', '地域コード': 'code'}) data['year'] = data['year'].astype(int) # 数値列を変換 for col in data.columns: if col not in ['year', 'pref', 'code']: data[col] = pd.to_numeric(data[col], errors='coerce') return data print("データ読み込み中...") df = load_ssdse_b(DATA_B) print(f" 読み込み完了: {df.shape[0]}行 × {df.shape[1]}列") print(f" 年度: {sorted(df['year'].unique())}") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。.astype(int) — 列を整数に変換(年度などを数値比較するため)。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。65 66 67 68 69 70 | # ── 派生変数の計算 ──────────────────────────────────────── # 着工新設住宅率(万人あたり) df['着工新設住宅率'] = df['着工新設住宅戸数'] / df['総人口'] * 10000 # 転出超過率(千人あたり) df['転出超過率'] = (df['転出者数(日本人移動者)'] - df['転入者数(日本人移動者)']) / df['総人口'] * 1000 |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。71 72 73 74 75 76 77 78 79 80 | # 高齢化率(%) df['高齢化率'] = df['65歳以上人口'] / df['総人口'] * 100 # 消費支出(対数) df['消費支出_log'] = np.log(df['消費支出(二人以上の世帯)']) # 求人倍率 df['求人倍率'] = df['月間有効求人数(一般)'] / df['月間有効求職者数(一般)'] print("派生変数計算完了。") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。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 | # ── 2022年データ抽出 ────────────────────────────────────── df2022 = df[df['year'] == 2022].copy().reset_index(drop=True) print(f" 2022年データ: {len(df2022)}都道府県") print("\nFig1: 転出超過率の時系列推移...") TARGET_PREFS = ['東京都', '大阪府', '秋田県', '島根県'] COLORS = ['#E53935', '#1565C0', '#43A047', '#7B1FA2'] MARKERS = ['o', 's', '^', 'D'] fig1, ax1 = plt.subplots(figsize=(9, 5.5), dpi=150) for pref, color, marker in zip(TARGET_PREFS, COLORS, MARKERS): pdata = df[df['pref'] == pref].sort_values('year') ax1.plot(pdata['year'], pdata['転出超過率'], color=color, marker=marker, markersize=5, linewidth=2, label=pref) ax1.axhline(0, color='gray', linewidth=0.8, linestyle='--', alpha=0.7) ax1.set_xlabel('年度', fontsize=12) ax1.set_ylabel('転出超過率(‰、千人あたり)', fontsize=12) ax1.set_title('Fig1: 転出超過率の時系列推移\n(東京・大阪・秋田・島根)', fontsize=13, fontweight='bold') ax1.legend(loc='upper left', fontsize=11) ax1.xaxis.set_major_locator(mticker.MultipleLocator(2)) ax1.xaxis.set_major_formatter(mticker.FormatStrFormatter('%d')) ax1.grid(axis='y', alpha=0.3) |
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行で書けます。107 108 109 110 111 112 113 114 115 116 | # 正負の意味を注釈 ax1.annotate('正値 = 転出超過(人口流出)', xy=(0.02, 0.97), xycoords='axes fraction', fontsize=9, color='gray', va='top') fig1.tight_layout() fig1_path = os.path.join(FIG_DIR, '2022_H5_11_fig1_netout_timeseries.png') fig1.savefig(fig1_path, dpi=150, bbox_inches='tight') plt.close(fig1) print(f" 保存: {fig1_path}") |
データ読み込み中... 読み込み完了: 564行 × 112列 年度: [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)] 派生変数計算完了。 2022年データ: 47都道府県 Fig1: 転出超過率の時系列推移... findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Fon …(長いため省略)
df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。2022年の47都道府県データを用いて、高齢化率(横軸)と転出超過率(縦軸)の散布図を描く。両変数が空き家問題とどのように関連しているかを視覚的に確認する。
| 指標 | 値 | 解釈 |
|---|---|---|
| 相関係数 r | +0.725 | 強い正の相関(高齢化 → 転出超過) |
| 決定係数 r² | 0.526 | 転出超過率の変動の52.6%を高齢化率で説明 |
| p値 | <0.001 | 統計的に高度に有意 |
| 観測数 n | 47都道府県 | 全都道府県網羅 |
118 119 120 121 122 123 124 125 126 127 | print("Fig2: 高齢化率 vs 転出超過率 散布図...") d2 = df2022[['pref', '高齢化率', '転出超過率']].dropna() fig2, ax2 = plt.subplots(figsize=(10, 7.5), dpi=150) # 転出超過率の符号で色分け colors2 = ['#E53935' if v > 0 else '#1565C0' for v in d2['転出超過率']] ax2.scatter(d2['高齢化率'], d2['転出超過率'], c=colors2, s=55, alpha=0.8, zorder=3) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | # 都道府県ラベル(重要なもの) highlight = ['東京都', '大阪府', '秋田県', '島根県', '鳥取県', '高知県', '沖縄県', '愛知県', '神奈川県', '北海道', '宮城県', '福島県'] for _, row in d2.iterrows(): if row['pref'] in highlight: offset_x = 0.2 offset_y = 0.05 ax2.annotate(row['pref'], xy=(row['高齢化率'], row['転出超過率']), xytext=(row['高齢化率'] + offset_x, row['転出超過率'] + offset_y), fontsize=8, color='#333333', arrowprops=dict(arrowstyle='-', color='gray', lw=0.5)) else: ax2.annotate(row['pref'], xy=(row['高齢化率'], row['転出超過率']), fontsize=7, color='#555555', ha='center', va='bottom') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | # 回帰直線 x2 = d2['高齢化率'].values y2 = d2['転出超過率'].values slope, intercept, r_val, p_val, _ = stats.linregress(x2, y2) x_line = np.linspace(x2.min(), x2.max(), 100) ax2.plot(x_line, intercept + slope * x_line, color='#F57C00', linewidth=2, linestyle='--', label=f'回帰直線 (r={r_val:.2f}, p={p_val:.3f})') ax2.axhline(0, color='gray', linewidth=0.8, linestyle=':', alpha=0.7) ax2.set_xlabel('高齢化率(%)', fontsize=12) ax2.set_ylabel('転出超過率(‰)', fontsize=12) ax2.set_title('Fig2: 高齢化率 vs 転出超過率(2022年、都道府県別)', fontsize=13, fontweight='bold') ax2.legend(fontsize=10) ax2.grid(alpha=0.25) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。stats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | # 凡例の追加(色の意味) from matplotlib.lines import Line2D legend_elements = [ Line2D([0], [0], marker='o', color='w', markerfacecolor='#E53935', markersize=9, label='転出超過(流出)'), Line2D([0], [0], marker='o', color='w', markerfacecolor='#1565C0', markersize=9, label='転入超過(流入)'), ] ax2.legend(handles=legend_elements + [ Line2D([0], [0], color='#F57C00', linewidth=2, linestyle='--', label=f'回帰直線 (r={r_val:.2f}, p={p_val:.3f})') ], fontsize=9, loc='upper left') fig2.tight_layout() fig2_path = os.path.join(FIG_DIR, '2022_H5_11_fig2_aging_scatter.png') fig2.savefig(fig2_path, dpi=150, bbox_inches='tight') plt.close(fig2) print(f" 保存: {fig2_path}") |
Fig2: 高齢化率 vs 転出超過率 散布図... findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic …(長いため省略)
import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。転出超過率・高齢化率・消費支出(対数)・求人倍率を説明変数として、着工新設住宅率をOLS(最小二乗法)重回帰で分析する。係数は標準化済みのため、各変数の「相対的な影響力」を比較できる。
| 説明変数 | 標準化係数 | p値 | 有意性 | 解釈 |
|---|---|---|---|---|
| 転出超過率 | −6.41 | <0.001 | ** | 転出超過が多いほど着工が少ない |
| 高齢化率 | −6.71 | <0.001 | ** | 高齢化が進むほど着工が抑制 |
| 消費支出(対数) | −1.64 | 0.136 | n.s. | 非有意(単独では効果不明瞭) |
| 求人倍率 | +3.07 | 0.008 | ** | 求人倍率が高い(雇用が豊富)ほど着工増加 |
モデル適合: Adj.R²=0.721, F(4,42)=30.66, p<0.001。** p<0.01, n.s. 非有意。
住宅地地価は「住宅を買いたい人がいる場所」を反映する。地価が高い = 需要が旺盛 = 人口が集まっている = 空き家が少ない、というロジックで「住宅需要の代理変数」として機能する。
地価データを分析に使うメリット:①市場参加者の期待を反映している、②都道府県単位で公式統計として入手できる、③住宅の「使われ方」(居住需要)を間接的に示す。
179 180 181 182 183 184 185 186 187 | print("Fig3: OLS 回帰係数プロット...") # 説明変数の選択 REG_VARS = ['転出超過率', '高齢化率', '消費支出_log', '求人倍率'] REG_LABELS = ['転出超過率\n(‰)', '高齢化率\n(%)', '消費支出\n(対数)', '求人倍率'] TARGET = '着工新設住宅率' d3 = df2022[REG_VARS + [TARGET]].dropna() print(f" 回帰データ: {len(d3)}都道府県") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | # 標準化(係数比較のため) from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X3_scaled = scaler.fit_transform(d3[REG_VARS]) y3 = d3[TARGET].values X3_sm = sm.add_constant(X3_scaled) model3 = sm.OLS(y3, X3_sm).fit() print(model3.summary()) coefs = model3.params[1:] # 定数項を除く conf_int = model3.conf_int()[1:] p_values = model3.pvalues[1:] fig3, ax3 = plt.subplots(figsize=(8, 5), dpi=150) y_pos = np.arange(len(REG_VARS)) bar_colors = ['#E53935' if p < 0.05 else '#90A4AE' for p in p_values] bars = ax3.barh(y_pos, coefs, color=bar_colors, alpha=0.85, height=0.55) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。207 208 209 210 211 212 213 214 215 216 217 218 219 | # 信頼区間のエラーバー for i, (ci_low, ci_high) in enumerate(conf_int): ax3.plot([ci_low, ci_high], [i, i], color='#212121', linewidth=2.5, zorder=5) ax3.plot([ci_low, ci_low], [i - 0.18, i + 0.18], color='#212121', linewidth=1.5, zorder=5) ax3.plot([ci_high, ci_high], [i - 0.18, i + 0.18], color='#212121', linewidth=1.5, zorder=5) ax3.axvline(0, color='gray', linewidth=0.8, linestyle='--') ax3.set_yticks(y_pos) ax3.set_yticklabels(REG_LABELS, fontsize=11) ax3.set_xlabel('標準化回帰係数(95%CI)', fontsize=11) ax3.set_title(f'Fig3: 着工新設住宅率の決定要因(OLS回帰、2022年)\n' f'Adj.R²={model3.rsquared_adj:.3f} n={len(d3)}', fontsize=12, fontweight='bold') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。220 221 222 223 224 225 226 227 | # p値の注釈 for i, (coef, p) in enumerate(zip(coefs, p_values)): sig_str = '**' if p < 0.01 else '*' if p < 0.05 else 'n.s.' ax3.text(coef + (0.03 if coef >= 0 else -0.03), i, sig_str, ha='left' if coef >= 0 else 'right', va='center', fontsize=11, color='#C62828' if sig_str != 'n.s.' else '#888888') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。228 229 230 231 232 233 234 235 236 237 238 239 240 241 | # 凡例 from matplotlib.patches import Patch legend_elems = [ Patch(facecolor='#E53935', alpha=0.85, label='有意(p<0.05)'), Patch(facecolor='#90A4AE', alpha=0.85, label='非有意'), ] ax3.legend(handles=legend_elems, fontsize=9, loc='lower right') ax3.grid(axis='x', alpha=0.3) fig3.tight_layout() fig3_path = os.path.join(FIG_DIR, '2022_H5_11_fig3_ols_coef.png') fig3.savefig(fig3_path, dpi=150, bbox_inches='tight') plt.close(fig3) print(f" 保存: {fig3_path}") |
Fig3: OLS 回帰係数プロット...
回帰データ: 47都道府県
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 0.745
Model: OLS Adj. R-squared: 0.721
Method: Least Squares F-statistic: 30.66
Date: Mon, 18 May 2026 Prob (F-statistic): 5.79e-12
Time: 11:24:04 Log-Likelihood: -151.92
No. Observations: 47 AIC: 313.8
Df Residuals: 42 BIC: 323.1
Df Model: 4
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 59.8700 0.946 63.283 0.000 57.961 61.779
x1 -6.4116 1.517 -4.225 0.000 -9.474 -3.349
x2 -6.7141 1.383 -4.854 0.000 -9.506 -3.922
x3 -1.6443 1.082 -1.520 0.136 -3.827 0.539
x4 3.0679 1.103 2.780 0.008 0.841 5.295
==============================================================================
Omnibus: 1.472 Durbin-Watson: 1.385
Prob(Omnibus): 0.479 Jarque-Bera (JB): 1.454
Skew: 0.353 Prob(JB): 0.483
Kurtosis: 2.506 Cond. No. 2.97
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not found.
findfont: Font family 'Hiragino Kaku Gothic ProN' not found.
findfont: Font family 'Noto Sans CJK JP' not
…(長いため省略)import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。2022年の標準価格(平均価格)(住宅地)を都道府県別にランキング表示する。住宅地地価は地域の住宅需要・経済活力の代理指標として、空き家問題の深刻さを逆から照らす。
| 順位 | 都道府県 | 住宅地地価(万円/m²) | 空き家問題との関連 |
|---|---|---|---|
| 1位(最高) | 東京都 | 38.9 | 需要旺盛・空き家率低 |
| 2位 | 神奈川県 | 16.3 | 都市部・需要安定 |
| 3位 | 大阪府 | 14.9 | 都市部・需要安定 |
| 45位 | 鳥取県 | 1.4 | 需要低迷・空き家リスク大 |
| 46位 | 秋田県 | 1.3 | 高齢化最高・転出超過 |
| 47位(最低) | 島根県 | 1.3 | 人口流出・住宅余剰 |
本分析で明らかになった構造:
「高齢化 → 転出超過 → 住宅需要低下 → 地価下落 → 空き家増加」
この悪循環を断ち切るためにはどのような政策が有効か、統計データは示唆を与える。
統計分析の限界:相関分析・OLS回帰では「政策の効果(因果)」を証明するには不十分。RCT(ランダム化比較試験)や差分の差分法(DID)などの因果推論手法と組み合わせることで、より説得力のある政策提言が可能になる。
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 | print("Fig4: 住宅地地価ランキング...") d4 = df2022[['pref', '標準価格(平均価格)(住宅地)']].dropna().copy() d4 = d4.rename(columns={'標準価格(平均価格)(住宅地)': '住宅地地価'}) d4 = d4.sort_values('住宅地地価', ascending=True).reset_index(drop=True) # 上位・下位に色分け n4 = len(d4) bar_c4 = [] for i in range(n4): if i >= n4 - 5: # 上位5(高い) bar_c4.append('#E53935') elif i < 5: # 下位5(低い) bar_c4.append('#1565C0') else: bar_c4.append('#78909C') fig4, ax4 = plt.subplots(figsize=(9, 11), dpi=150) ax4.barh(range(n4), d4['住宅地地価'] / 10000, color=bar_c4, alpha=0.85) ax4.set_yticks(range(n4)) ax4.set_yticklabels(d4['pref'], fontsize=8.5) ax4.set_xlabel('住宅地地価(万円/m²)', fontsize=11) ax4.set_title('Fig4: 住宅地地価の都道府県別ランキング(2022年)\n' '※ 標準価格(平均価格)(住宅地)', fontsize=12, fontweight='bold') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | # 地価の数値ラベル for i, val in enumerate(d4['住宅地地価']): ax4.text(val / 10000 + 0.3, i, f'{val/10000:.1f}', va='center', fontsize=7.5, color='#333333') # 凡例 from matplotlib.patches import Patch as MPatch legend_items = [ MPatch(facecolor='#E53935', alpha=0.85, label='地価上位5(高い)'), MPatch(facecolor='#1565C0', alpha=0.85, label='地価下位5(低い)'), MPatch(facecolor='#78909C', alpha=0.85, label='その他'), ] ax4.legend(handles=legend_items, fontsize=9, loc='lower right') ax4.grid(axis='x', alpha=0.3) fig4.tight_layout() fig4_path = os.path.join(FIG_DIR, '2022_H5_11_fig4_landprice_rank.png') fig4.savefig(fig4_path, dpi=150, bbox_inches='tight') plt.close(fig4) print(f" 保存: {fig4_path}") |
Fig4: 住宅地地価ランキング... findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' not found. findfont: Font family 'Noto Sans CJK JP' not found. findfont: Font family 'Hiragino Kaku Gothic ProN' n …(長いため省略)
import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。SSDSE-B(都道府県別データ)を用いた分析の結果、以下の知見が得られた:
| データ | 出典 | 変数例 |
|---|---|---|
| SSDSE-B-2026(都道府県別) | 統計数理研究所 SSDSE(社会・人口統計体系) | 人口、転入・転出者数、着工住宅戸数、地価など |
| 標準価格(住宅地・商業地) | 国土交通省 地価公示(SSDSE-Bに収録) | C5401(住宅地)、C5403(商業地) |
| 月間有効求人数・求職者数 | 厚生労働省 職業安定業務統計(SSDSE-Bに収録) | F3103、F3102 |
| 消費支出(二人以上の世帯) | 総務省 家計調査(SSDSE-Bに収録) | L3221 |
本教育用コードは実データ(SSDSE-B-2026.csv)のみを使用し、合成データ・np.random等は一切使用していない。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。