このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
「関西の料理は薄味、関東の料理は濃い味」という言説は日本の食文化において広く知られた俗説である。関西ではだし文化が発達し薄口醤油が好まれる一方、関東では江戸時代から濃口醤油が主流だったとされる。しかし、この「ふるさとの味」の地域差は、現代の消費データにも統計的に反映されているのだろうか?
まず「味覚から眺める地域別「ふるさとの味」」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
SSDSE-B Kruskal-Wallis検定 Mann-Whitney U検定 代理変数 時系列分析
SSDSE-B(社会・人口統計体系 都道府県別データ)の2012〜2023年分を使用。二人以上の世帯の消費支出内訳(食料費・光熱水道費・教養娯楽費など)が47都道府県 × 複数年度で収録されている。
| 変数名 | 定義 | 役割 |
|---|---|---|
| 食料費割合 | 食料費(二人以上) ÷ 消費支出(二人以上) × 100 (%) | 主要代理変数(味の濃淡) |
| 光熱・水道費割合 | 光熱・水道費 ÷ 消費支出 × 100 (%) | 調理エネルギー使用の指標 |
| 教養娯楽費割合 | 教養娯楽費 ÷ 消費支出 × 100 (%) | 生活スタイルの比較指標 |
| 住宅地価格 | 標準価格(平均価格)住宅地(円/m²) | 経済的背景の説明変数 |
SSDSE-Bの地域コード(Rxx000)に基づき、都道府県番号から以下の6地域(+北海道)に分類した。
| 地域 | 都道府県 | 地域コード範囲 |
|---|---|---|
| 北海道 | 北海道 | R01000 |
| 東北 | 青森・岩手・宮城・秋田・山形・福島 | R02〜R07 |
| 関東 | 茨城・栃木・群馬・埼玉・千葉・東京・神奈川 | R08〜R14 |
| 中部 | 新潟〜愛知(9県) | R15〜R23 |
| 関西 | 三重・滋賀・京都・大阪・兵庫・奈良・和歌山 | R24〜R30 |
| 中国・四国 | 鳥取〜高知(9県) | R31〜R39 |
| 九州・沖縄 | 福岡〜沖縄(8県) | R40〜R47 |
「味の濃淡」は直接数値化できない。そこで「食料費割合(食料費 ÷ 消費支出)」を代理変数として用いる。代理変数とは、直接測定できない概念を近似的に表す、観測可能な別の変数のこと。ただし代理変数には妥当性の検証が必要で、「食料費が高いから味が濃い」という因果関係の前提を慎重に吟味することが重要。
1 2 3 4 5 6 7 8 | df_b_raw = pd.read_csv(DATA_B, encoding='cp932', header=1) df_b = df_b_raw[df_b_raw['地域コード'].str.match(r'^R\d{5}$', na=False)].copy() print("=" * 65) print("■ SSDSE-B-2026 都道府県データ読み込み") print("=" * 65) print(f" 行数: {len(df_b)}, 年度範囲: {df_b['年度'].min()}〜{df_b['年度'].max()}") print(f" 都道府県数(年平均): {df_b['年度'].value_counts().median():.0f}") |
================================================================= ■ SSDSE-B-2026 都道府県データ読み込み ================================================================= 行数: 564, 年度範囲: 2012〜2023 都道府県数(年平均): 47
pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | df_b['pref_num'] = df_b['地域コード'].str.extract(r'R(\d{2})').astype(int) # 地域区分の定義 def assign_region(n): if n == 1: return '北海道' elif 2 <= n <= 7: return '東北' elif 8 <= n <= 14: return '関東' elif 15 <= n <= 23: return '中部' elif 24 <= n <= 30: return '関西' elif 31 <= n <= 39: return '中国・四国' elif 40 <= n <= 47: return '九州・沖縄' else: return 'その他' df_b['地域'] = df_b['pref_num'].apply(assign_region) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.astype(int) — 列を整数に変換(年度などを数値比較するため)。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | df_b['食料費割合'] = df_b['食料費(二人以上の世帯)'] / df_b['消費支出(二人以上の世帯)'] * 100 # 光熱・水道費割合(調理・生活エネルギー使用の代理変数) df_b['光熱・水道費割合'] = df_b['光熱・水道費(二人以上の世帯)'] / df_b['消費支出(二人以上の世帯)'] * 100 # 教養娯楽費割合(生活スタイルの指標) df_b['教養娯楽費割合'] = df_b['教養娯楽費(二人以上の世帯)'] / df_b['消費支出(二人以上の世帯)'] * 100 print(f"\n 食料費割合の基本統計:") print(df_b['食料費割合'].describe().round(2)) # 関東・関西フラグ KANTO_PREFS = list(range(8, 15)) # R08〜R14(茨城〜神奈川) KANSAI_PREFS = list(range(24, 31)) # R24〜R30(三重〜和歌山) df_b['地域2'] = df_b['pref_num'].apply( lambda n: '関東' if n in KANTO_PREFS else ('関西' if n in KANSAI_PREFS else 'その他') ) |
食料費割合の基本統計: count 564.00 mean 25.42 std 2.06 min 20.40 25% 23.97 50% 25.37 75% 26.84 max 31.82 Name: 食料費割合, dtype: float64
.describe() — 件数・平均・標準偏差・四分位・最大/最小を一括計算。データの素性チェックに必須。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。49 50 51 | latest_year = df_b['年度'].max() df_latest = df_b[df_b['年度'] == latest_year].copy() print(f"\n 最新年度: {latest_year}年 ({len(df_latest)}都道府県)") |
最新年度: 2023年 (47都道府県)
r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | print("\n" + "=" * 65) print("■ Kruskal-Wallis検定:6地域別 食料費割合の差") print("=" * 65) REGION_ORDER = ['北海道', '東北', '関東', '中部', '関西', '中国・四国', '九州・沖縄'] # 全年度データを使って地域別に集計 region_groups = [ df_b[df_b['地域'] == r]['食料費割合'].dropna().values for r in REGION_ORDER ] kw_stat, kw_p = stats.kruskal(*region_groups) print(f" H統計量={kw_stat:.4f}, p値={kw_p:.6f}") sig_kw = '*** (p<0.001)' if kw_p < 0.001 else '** (p<0.01)' if kw_p < 0.01 else '* (p<0.05)' if kw_p < 0.05 else 'n.s.' print(f" 判定: {sig_kw}") # 地域別の記述統計 print(f"\n {'地域':<12} {'N':>5} {'中央値':>8} {'平均':>8} {'SD':>7}") print(" " + "-" * 45) for r, grp in zip(REGION_ORDER, region_groups): print(f" {r:<12} {len(grp):>5} {np.median(grp):>8.2f} {np.mean(grp):>8.2f} {np.std(grp):>7.2f}") |
================================================================= ■ Kruskal-Wallis検定:6地域別 食料費割合の差 ================================================================= H統計量=61.5961, p値=0.000000 判定: *** (p<0.001) 地域 N 中央値 平均 SD --------------------------------------------- 北海道 12 24.43 24.51 1.25 東北 72 25.95 25.86 1.90 関東 84 25.69 25.60 1.82 中部 108 25.33 25.38 1.72 関西 84 26.89 26.79 2.25 中国・四国 108 24.51 24.62 1.90 九州・沖縄 96 24.77 24.81 2.07
x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。74 75 76 77 78 79 80 81 82 83 84 85 86 | print("\n" + "=" * 65) print("■ Mann-Whitney U検定:関東 vs 関西(全年度)") print("=" * 65) kanto_vals = df_b[df_b['地域2'] == '関東']['食料費割合'].dropna().values kansai_vals = df_b[df_b['地域2'] == '関西']['食料費割合'].dropna().values u_stat, u_p = stats.mannwhitneyu(kanto_vals, kansai_vals, alternative='two-sided') print(f" U統計量={u_stat:.1f}, p値={u_p:.6f}") sig_u = '*** (p<0.001)' if u_p < 0.001 else '** (p<0.01)' if u_p < 0.01 else '* (p<0.05)' if u_p < 0.05 else 'n.s.' print(f" 判定: {sig_u}") print(f" 関東 中央値={np.median(kanto_vals):.2f}%, 平均={np.mean(kanto_vals):.2f}%") print(f" 関西 中央値={np.median(kansai_vals):.2f}%, 平均={np.mean(kansai_vals):.2f}%") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | # 最新年度の関東・関西比較 kanto_latest = df_latest[df_latest['地域2'] == '関東'] kansai_latest = df_latest[df_latest['地域2'] == '関西'] metrics = { '食料費割合(%)': ('食料費割合', 2), '光熱・水道費割合(%)': ('光熱・水道費割合', 2), '教養娯楽費割合(%)': ('教養娯楽費割合', 2), } print(f"\n {latest_year}年 関東 vs 関西 比較:") print(f" {'指標':<22} {'関東':>10} {'関西':>10}") print(" " + "-" * 45) for label, (col, nd) in metrics.items(): v_k = kanto_latest[col].mean() v_ks = kansai_latest[col].mean() print(f" {label:<22} {v_k:>10.{nd}f} {v_ks:>10.{nd}f}") |
================================================================= ■ Mann-Whitney U検定:関東 vs 関西(全年度) ================================================================= U統計量=2450.0, p値=0.000631 判定: *** (p<0.001) 関東 中央値=25.69%, 平均=25.60% 関西 中央値=26.89%, 平均=26.79% 2023年 関東 vs 関西 比較: 指標 関東 関西 --------------------------------------------- 食料費割合(%) 27.37 28.15 光熱・水道費割合(%) 7.39 7.51 教養娯楽費割合(%) 10.38 9.72
s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。2012〜2023年の全年度データを用いて、6地域別の食料費割合分布を箱ひげ図で可視化する。地域間の中央値の差が統計的に有意かどうかをKruskal-Wallis検定で判定する。
Kruskal-Wallis検定は、3群以上の中央値が等しいという帰無仮説を検定するノンパラメトリック検定。ANOVA(分散分析)が正規分布を前提とするのに対し、Kruskal-Wallis検定は順位統計量を用いるため分布の仮定が不要。都道府県データのように標本サイズが小さい(1地域あたり数〜十数県)場合に適している。
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | fig1, ax1 = plt.subplots(figsize=(11, 6)) bp_data = [grp for grp in region_groups] bp = ax1.boxplot( bp_data, labels=REGION_ORDER, patch_artist=True, medianprops=dict(color='black', linewidth=2), flierprops=dict(marker='o', markersize=4, alpha=0.6), boxprops=dict(linewidth=1.2), whiskerprops=dict(linewidth=1.2), capprops=dict(linewidth=1.5), ) for patch, region in zip(bp['boxes'], REGION_ORDER): c = REGION_COLORS[region] patch.set_facecolor(c) patch.set_alpha(0.65) for flier, region in zip(bp['fliers'], REGION_ORDER): flier.set(markerfacecolor=REGION_COLORS[region], alpha=0.6) ax1.set_ylabel('食料費割合(食料費 / 消費支出,%)', fontsize=12) ax1.set_xlabel('地域', fontsize=12) ax1.set_title( f'6地域別 食料費割合の分布(2012〜{latest_year}年)\n' f'Kruskal-Wallis: H={kw_stat:.2f}, {sig_kw}', fontsize=13, fontweight='bold' ) ax1.grid(axis='y', alpha=0.3) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。{値:.2f}(小数2桁)、{値:,}(3桁区切り)、{値:>10}(右寄せ10桁)など、覚えると出力が一気に整います。133 134 135 136 137 138 139 140 141 142 | # 各地域の中央値をテキスト表示 for i, grp in enumerate(region_groups, start=1): med = np.median(grp) ax1.text(i, med + 0.1, f'{med:.1f}%', ha='center', va='bottom', fontsize=9, fontweight='bold', color=REGION_COLORS[REGION_ORDER[i-1]]) plt.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2022_U5_4_fig1_region.png'), bbox_inches='tight', dpi=150) plt.close(fig1) print("\n図1保存: 2022_U5_4_fig1_region.png") |
図1保存: 2022_U5_4_fig1_region.png
plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。論文の核心的な問い「関西が薄味、関東が濃い味」に直接答えるため、最新年度の関東7都県(茨城・栃木・群馬・埼玉・千葉・東京・神奈川)と関西7府県(三重・滋賀・京都・大阪・兵庫・奈良・和歌山)の消費内訳を3指標で比較する。各棒グラフにはMann-Whitney U検定の結果と95%信頼区間を付与する。
| 指標 | 関東(平均) | 関西(平均) | 検定結果 |
|---|---|---|---|
| 食料費割合(%) | グラフ参照 | グラフ参照 | 図2タイトル参照 |
| 光熱・水道費割合(%) | グラフ参照 | グラフ参照 | 図2タイトル参照 |
| 教養娯楽費割合(%) | グラフ参照 | グラフ参照 | 図2タイトル参照 |
144 145 146 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 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | fig2, axes2 = plt.subplots(1, 3, figsize=(13, 5)) fig2.suptitle( f'関東 vs 関西 消費支出内訳の比較({latest_year}年,各都道府県平均)', fontsize=13, fontweight='bold' ) metric_list = [ ('食料費割合', '食料費割合\n(食料費 / 消費支出,%)', '#C62828', '#6A1B9A'), ('光熱・水道費割合', '光熱・水道費割合\n(光熱・水道費 / 消費支出,%)', '#E65100', '#9C27B0'), ('教養娯楽費割合', '教養娯楽費割合\n(教養娯楽費 / 消費支出,%)', '#1565C0', '#00695C'), ] for ax, (col, ylabel, c_kanto, c_kansai) in zip(axes2, metric_list): v_kanto = kanto_latest[col].mean() v_kansai = kansai_latest[col].mean() se_kanto = kanto_latest[col].sem() se_kansai = kansai_latest[col].sem() bars = ax.bar(['関東', '関西'], [v_kanto, v_kansai], color=[c_kanto, c_kansai], alpha=0.75, edgecolor='white', linewidth=1.2, width=0.5) ax.errorbar(['関東', '関西'], [v_kanto, v_kansai], yerr=[1.96*se_kanto, 1.96*se_kansai], fmt='none', color='#333', capsize=5, linewidth=1.5) # 値のラベル for bar, val in zip(bars, [v_kanto, v_kansai]): ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.05, f'{val:.2f}%', ha='center', va='bottom', fontsize=11, fontweight='bold') # Mann-Whitney検定 col_kanto_series = kanto_latest[col].dropna().values col_kansai_series = kansai_latest[col].dropna().values if len(col_kanto_series) >= 2 and len(col_kansai_series) >= 2: _, p_tmp = stats.mannwhitneyu(col_kanto_series, col_kansai_series, alternative='two-sided') sig_tmp = '***' if p_tmp < 0.001 else '**' if p_tmp < 0.01 else '*' if p_tmp < 0.05 else 'n.s.' ax.set_title(f'Mann-Whitney: {sig_tmp}', fontsize=10) ax.set_ylabel(ylabel, fontsize=9) ax.set_ylim(0, max(v_kanto, v_kansai) * 1.25) ax.grid(axis='y', alpha=0.3) ax.tick_params(axis='x', labelsize=12) plt.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2022_U5_4_fig2_kanto_kansai.png'), bbox_inches='tight', dpi=150) plt.close(fig2) print("図2保存: 2022_U5_4_fig2_kanto_kansai.png") |
図2保存: 2022_U5_4_fig2_kanto_kansai.png
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。関東・関西・全国平均の食料費割合を2012〜2023年の時系列で追う。トレンドの方向性(上昇・下降)や地域差の拡大・縮小の有無を読み取る。
箱ひげ図は「ある期間全体」の分布を1枚の図に圧縮して見せる。一方、時系列グラフはトレンド(増加・減少・構造変化)を捉える。この2種類のグラフを組み合わせることで、「平均的にどの地域が高いか(箱ひげ図)」と「その差は時代とともに変わっているか(時系列)」の両方を立体的に把握できる。
195 196 197 198 199 200 | fig3, ax3 = plt.subplots(figsize=(11, 5)) years = sorted(df_b['年度'].unique()) # 全国平均 national_ts = df_b.groupby('年度')['食料費割合'].mean() |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。.dropna() は欠損行を除去、.copy() は独立したコピーを作る。pandasで警告を防ぐ定石。201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | # 関東平均 kanto_ts = df_b[df_b['地域2'] == '関東'].groupby('年度')['食料費割合'].mean() kansai_ts = df_b[df_b['地域2'] == '関西'].groupby('年度')['食料費割合'].mean() # 関東・関西の信頼区間(SE×1.96) kanto_sem = df_b[df_b['地域2'] == '関東'].groupby('年度')['食料費割合'].sem() kansai_sem = df_b[df_b['地域2'] == '関西'].groupby('年度')['食料費割合'].sem() ax3.fill_between(kanto_ts.index, kanto_ts - 1.96 * kanto_sem, kanto_ts + 1.96 * kanto_sem, color='#C62828', alpha=0.12) ax3.fill_between(kansai_ts.index, kansai_ts - 1.96 * kansai_sem, kansai_ts + 1.96 * kansai_sem, color='#6A1B9A', alpha=0.12) ax3.plot(national_ts.index, national_ts.values, color='#455A64', linewidth=2.0, linestyle='--', marker='o', markersize=5, label='全国平均') ax3.plot(kanto_ts.index, kanto_ts.values, color='#C62828', linewidth=2.5, marker='s', markersize=6, label='関東(7都県平均)') ax3.plot(kansai_ts.index, kansai_ts.values, color='#6A1B9A', linewidth=2.5, marker='^', markersize=6, label='関西(7府県平均)') ax3.set_xlabel('年度', fontsize=12) ax3.set_ylabel('食料費割合(食料費 / 消費支出,%)', fontsize=12) ax3.set_title( '食料費割合の時系列推移:関東・関西・全国平均(SSDSE-B 実データ)', fontsize=13, fontweight='bold' ) ax3.set_xticks(years) ax3.set_xticklabels([str(y) for y in years], rotation=45, fontsize=9) ax3.legend(fontsize=11) ax3.grid(alpha=0.3) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。ax.fill_between(...) — 2つの曲線で囲まれた領域を塗りつぶし。Lorenz曲線の格差面積などを可視化。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | # 直近年の差を注釈 diff_latest = kanto_ts[latest_year] - kansai_ts[latest_year] arrow_x = latest_year ax3.annotate( f'差={diff_latest:+.2f}pp', xy=(arrow_x, kanto_ts[latest_year]), xytext=(arrow_x - 1.5, kanto_ts[latest_year] + 0.3), fontsize=9, color='#333', arrowprops=dict(arrowstyle='->', color='#333', lw=1.2) ) plt.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2022_U5_4_fig3_ts.png'), bbox_inches='tight', dpi=150) plt.close(fig3) print("図3保存: 2022_U5_4_fig3_ts.png") |
図3保存: 2022_U5_4_fig3_ts.png
df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。地域ごとの食料費割合は、その地域の経済的な豊かさや物価水準とどのような関係にあるか。住宅地の標準価格(千円/m²)を経済水準の代理変数として、食料費割合との散布図を描き、相関分析を行う。東京都・大阪府・京都府・北海道・沖縄県などの特徴的な都道府県にはラベルを付与する。
食料費割合は「エンゲル係数」の変形版である。エンゲル係数(食費 ÷ 消費支出)は経済水準の指標として古くから使われており、一般に豊かな世帯・地域ほど低くなるとされる(エンゲルの法則)。本研究では食料費割合を「味の濃淡の代理変数」として使うが、同時に「経済的豊かさの逆指標」としての側面もある。複数の解釈が可能な指標を使う際は、どの解釈を主張するかを明示することが重要。
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from scipy import stats 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)。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。271 272 273 274 275 276 277 278 279 280 281 282 283 | print("\n" + "=" * 65) print("■ 相関分析:住宅地価格 vs 食料費割合(最新年度)") print("=" * 65) scatter_df = df_latest[['都道府県', '地域', '食料費割合', '標準価格(平均価格)(住宅地)']].dropna() r_scatter, p_scatter = stats.pearsonr( scatter_df['標準価格(平均価格)(住宅地)'], scatter_df['食料費割合'] ) print(f" r={r_scatter:.4f}, p={p_scatter:.4f}") sig_s = '*** (p<0.001)' if p_scatter < 0.001 else '** (p<0.01)' if p_scatter < 0.01 else '* (p<0.05)' if p_scatter < 0.05 else 'n.s.' print(f" 判定: {sig_s}") |
================================================================= ■ 相関分析:住宅地価格 vs 食料費割合(最新年度) ================================================================= r=0.3476, p=0.0167 判定: * (p<0.05)
stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。284 285 286 287 288 289 290 291 292 | REGION_COLORS = { '北海道': '#1565C0', '東北': '#2E7D32', '関東': '#C62828', '中部': '#E65100', '関西': '#6A1B9A', '中国・四国': '#00695C', '九州・沖縄': '#F9A825', } |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。np.cumsum(arr) は累積和、np.linspace(a, b, n) は「aからbを等間隔でn個」。NumPyの定石です。293 294 295 296 297 298 299 300 301 302 303 | fig4, ax4 = plt.subplots(figsize=(10, 7)) for region in REGION_ORDER: sub = scatter_df[scatter_df['地域'] == region] ax4.scatter( sub['標準価格(平均価格)(住宅地)'] / 1000, # 千円/m² 単位 sub['食料費割合'], color=REGION_COLORS[region], s=80, alpha=0.75, zorder=3, label=region, edgecolors='white', linewidths=0.5 ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。304 305 306 307 308 309 310 311 | # 全体回帰直線 x_sc = scatter_df['標準価格(平均価格)(住宅地)'].values / 1000 y_sc = scatter_df['食料費割合'].values z_sc = np.polyfit(x_sc, y_sc, 1) xs_sc = np.linspace(x_sc.min(), x_sc.max(), 200) ax4.plot(xs_sc, np.poly1d(z_sc)(xs_sc), color='#333', linewidth=1.8, linestyle='--', zorder=2, label=f'回帰直線 r={r_scatter:.3f} ({sig_s})') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | # 注目都道府県をラベル表示 highlight_prefs = ['東京都', '大阪府', '京都府', '神奈川県', '北海道', '沖縄県', '秋田県'] for _, row in scatter_df.iterrows(): if row['都道府県'] in highlight_prefs: ax4.annotate( row['都道府県'], xy=(row['標準価格(平均価格)(住宅地)'] / 1000, row['食料費割合']), xytext=(6, 4), textcoords='offset points', fontsize=8.5, color='#333', ) ax4.set_xlabel('標準価格・住宅地(千円/m²)', fontsize=12) ax4.set_ylabel('食料費割合(食料費 / 消費支出,%)', fontsize=12) ax4.set_title( f'住宅地価格 vs 食料費割合の関係({latest_year}年,47都道府県)\n' f'相関係数 r={r_scatter:.3f},{sig_s}', fontsize=13, fontweight='bold' ) ax4.legend(fontsize=9, loc='upper right', framealpha=0.85) ax4.grid(alpha=0.3) plt.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2022_U5_4_fig4_scatter.png'), bbox_inches='tight', dpi=150) plt.close(fig4) print("図4保存: 2022_U5_4_fig4_scatter.png") print("\n全図の生成完了(4枚)") print(f" 2022_U5_4_fig1_region.png : 6地域別 食料費割合 箱ひげ図") print(f" 2022_U5_4_fig2_kanto_kansai.png: 関東 vs 関西 複数指標比較棒グラフ") print(f" 2022_U5_4_fig3_ts.png : 食料費割合の時系列推移") print(f" 2022_U5_4_fig4_scatter.png : 住宅地価格 vs 食料費割合 散布図") print("\n" + "=" * 65) print("■ 分析サマリー(論文の問いへの答え)") print("=" * 65) print(f" ・6地域間の食料費割合の差 → Kruskal-Wallis {sig_kw}") print(f" ・関東 vs 関西(食料費割合)→ Mann-Whitney {sig_u}") print(f" ・関東 食料費割合平均: {np.mean(kanto_vals):.2f}%") print(f" ・関西 食料費割合平均: {np.mean(kansai_vals):.2f}%") diff_mean = np.mean(kanto_vals) - np.mean(kansai_vals) print(f" ・差(関東-関西): {diff_mean:+.2f}pp") print(f" ・住宅地価格 vs 食料費割合 相関: r={r_scatter:.3f} {sig_s}") print("=" * 65) |
図4保存: 2022_U5_4_fig4_scatter.png 全図の生成完了(4枚) 2022_U5_4_fig1_region.png : 6地域別 食料費割合 箱ひげ図 2022_U5_4_fig2_kanto_kansai.png: 関東 vs 関西 複数指標比較棒グラフ 2022_U5_4_fig3_ts.png : 食料費割合の時系列推移 2022_U5_4_fig4_scatter.png : 住宅地価格 vs 食料費割合 散布図 ================================================================= ■ 分析サマリー(論文の問いへの答え) ================================================================= ・6地域間の食料費割合の差 → Kruskal-Wallis *** (p<0.001) ・関東 vs 関西(食料費割合)→ Mann-Whitney *** (p<0.001) ・関東 食料費割合平均: 25.60% ・関西 食料費割合平均: 26.79% ・差(関東-関西): -1.19pp ・住宅地価格 vs 食料費割合 相関: r=0.348 * (p<0.05) =================================================================
for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。SSDSE-B 都道府県別データ(2012〜2023年)を用いた「ふるさとの味」地域差分析の結果:
| データ・資料 | 出典・備考 |
|---|---|
| SSDSE-B-2026.csv(都道府県別データ) | 統計数理研究所 SSDSE(社会・人口統計体系) |
| 二人以上世帯の消費支出内訳(食料費・光熱水道費等) | 総務省 家計調査(SSDSE-B に収録) |
| 住宅地標準価格(都道府県別平均) | 国土交通省 地価公示(SSDSE-B に収録) |
本分析スクリプトは実公的データ(SSDSE-B-2026.csv)を使用する教育用コードです。実行にはSSDSE-Bデータファイルが必要です。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。