このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
日本の地域間経済格差は長年の政策課題である。特に「なぜある地域は豊かで、別の地域は貧しいのか」という問いは、経済地理学・地域経済学の核心的テーマである。本研究は、都道府県の産業構造(特に製造業比率)が地域の雇用・所得水準にどう影響するかを統計的に検証する。
まず「製造業・産業構造と地域雇用・所得の関係分析」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
SSDSE-E-2026(2021年度) SSDSE-B-2026(2022年度) 特化係数(LQ) OLS重回帰 地域比較
| データセット | 年度 | 使用変数 |
|---|---|---|
| SSDSE-E-2026(都道府県横断) | 2021年度 | 産業別従業者数(建設・製造・情報通信・卸売小売・医療福祉等)、1人当たり県民所得、総人口、65歳以上人口、総面積 |
| SSDSE-B-2026(都道府県時系列) | 2022年度 | 消費支出(二人以上世帯)、月間有効求人数、就職件数(一般)、転入者数、総人口 |
※ SSDSE: 社会・人口統計体系データセット(統計センター公表)。産業別従業者数は民営事業所ベース(経済センサス)。
| 役割 | 変数名 | 定義 | 出典年度 |
|---|---|---|---|
| 目的変数 | 消費支出 | 二人以上世帯の月額消費支出(所得水準の代理) | SSDSE-B 2022 |
| 説明変数 | 製造業従業者割合 | 民営従業者全体に占める製造業の割合(%) | SSDSE-E 2021 |
| 情報通信業従業者割合 | 民営従業者全体に占める情報通信業の割合(%) | SSDSE-E 2021 | |
| 高齢化率 | 65歳以上人口 / 総人口(%) | SSDSE-E 2021 | |
| 人口密度 | 総人口 / 総面積(人/km²) | SSDSE-E 2021 | |
| 有効求人倍率(代理) | 月間有効求人数 / 就職件数(雇用市場の過熱度) | SSDSE-B 2022 |
LQは「ある地域のある産業の集中度を全国平均と比較した指標」。LQ = 1.0 なら全国平均と同じ、1.0 超なら特化(集積)、1.0 未満なら相対的に少ないことを意味する。
| 順位 | 都道府県 | 製造業LQ | 製造業割合 | 地域特性 |
|---|---|---|---|---|
| 1 | 滋賀県 | 1.77 | 26.9% | 琵琶湖沿岸の工業集積(電機・化学) |
| 2 | 三重県 | 1.71 | 26.1% | 石油化学・半導体(四日市) |
| 3 | 富山県 | 1.70 | 25.8% | アルミ・化学薬品・医薬品 |
| 4 | 静岡県 | 1.68 | 25.5% | 輸送機器・楽器・食品(総合的ものづくり) |
| 5 | 群馬県 | 1.66 | 25.1% | 輸送機器(SUBARU・スズキ) |
| 43 | 北海道 | 0.57 | 8.7% | 農林水産・観光・サービス業主体 |
| 44 | 高知県 | 0.66 | 10.0% | 林業・農業・水産業主体 |
| 45 | 福岡県 | 0.71 | 10.9% | 九州の経済中心・商業・サービス集積 |
| 46 | 東京都 | 0.39 | 5.9% | 情報通信・金融・商業の中心 |
| 47 | 沖縄県 | 0.36 | 5.5% | 観光・軍事基地・建設業主体 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | region_map = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄' } region_colors = { '北海道・東北': '#4e9af1', '関東': '#e05c5c', '中部': '#f0a500', '近畿': '#5cb85c', '中国・四国': '#9b59b6', '九州・沖縄': '#f39c12' } |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。21 22 23 24 25 26 27 28 29 30 | print("SSDSE-E を読み込み中...") df_e_raw = pd.read_csv(DATA_E, encoding='cp932', header=0) # 行0: 年度, 行1: 変数名, 行2以降: データ # 都道府県データ(R01000〜R47000)と全国(R00000)を分離 df_e_all = df_e_raw[df_e_raw['SSDSE-E-2026'] == 'R00000'].copy() # 全国 df_e_pref = df_e_raw[ df_e_raw['SSDSE-E-2026'].str.match(r'^R\d{5}$', na=False) & (df_e_raw['SSDSE-E-2026'] != 'R00000') ].copy() |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | # 数値変換対象列 e_num_cols = [ 'C2208', # 従業者数(民営)計 'C220836', # 建設業 'C220837', # 製造業 'C220839', # 情報通信業 'C220841', # 卸売業・小売業 'C220847', # 宿泊業・飲食サービス業 'C220848', # 生活関連サービス業・娯楽業 'C220850', # 医療・福祉 'C122101', # 1人当たり県民所得(万円) 'A1101', # 総人口 'A1303', # 65歳以上人口 'B1101', # 総面積 ] for col in e_num_cols: df_e_pref[col] = pd.to_numeric(df_e_pref[col], errors='coerce') df_e_all[col] = pd.to_numeric(df_e_all[col], errors='coerce') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。49 50 51 | # 都道府県名を列として整理 df_e_pref = df_e_pref.rename(columns={'SSDSE-E-2026': '地域コード', 'Prefecture': '都道府県'}) df_e_pref = df_e_pref.reset_index(drop=True) |
SSDSE-E を読み込み中...
r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。52 53 54 55 56 57 58 59 60 | total_workers = df_e_pref['C2208'] df_e_pref['従業者割合_製造業'] = df_e_pref['C220837'] / total_workers * 100 df_e_pref['従業者割合_建設業'] = df_e_pref['C220836'] / total_workers * 100 df_e_pref['従業者割合_情報通信業'] = df_e_pref['C220839'] / total_workers * 100 df_e_pref['従業者割合_卸売小売業'] = df_e_pref['C220841'] / total_workers * 100 df_e_pref['従業者割合_宿泊飲食業'] = df_e_pref['C220847'] / total_workers * 100 df_e_pref['従業者割合_生活娯楽業'] = df_e_pref['C220848'] / total_workers * 100 df_e_pref['従業者割合_医療福祉業'] = df_e_pref['C220850'] / total_workers * 100 |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | nat_total = float(df_e_all['C2208'].values[0]) nat_mfg = float(df_e_all['C220837'].values[0]) nat_const = float(df_e_all['C220836'].values[0]) nat_ict = float(df_e_all['C220839'].values[0]) nat_retail= float(df_e_all['C220841'].values[0]) nat_med = float(df_e_all['C220850'].values[0]) nat_mfg_ratio = nat_mfg / nat_total nat_const_ratio = nat_const / nat_total nat_ict_ratio = nat_ict / nat_total nat_retail_ratio= nat_retail/ nat_total nat_med_ratio = nat_med / nat_total df_e_pref['LQ_製造業'] = (df_e_pref['C220837'] / total_workers) / nat_mfg_ratio df_e_pref['LQ_建設業'] = (df_e_pref['C220836'] / total_workers) / nat_const_ratio df_e_pref['LQ_情報通信業'] = (df_e_pref['C220839'] / total_workers) / nat_ict_ratio df_e_pref['LQ_卸売小売業'] = (df_e_pref['C220841'] / total_workers) / nat_retail_ratio df_e_pref['LQ_医療福祉業'] = (df_e_pref['C220850'] / total_workers) / nat_med_ratio # 高齢化率・人口密度 df_e_pref['高齢化率'] = df_e_pref['A1303'] / df_e_pref['A1101'] * 100 df_e_pref['人口密度'] = df_e_pref['A1101'] / df_e_pref['B1101'] # 人/km² print(f"SSDSE-E: {len(df_e_pref)} 都道府県") |
SSDSE-E: 47 都道府県
r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | print("SSDSE-B を読み込み中...") 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) df_b2022 = df_b[df_b['年度'] == 2022].copy() # 数値変換 b_num_cols = [ '消費支出(二人以上の世帯)', '月間有効求人数(一般)', '就職件数(一般)', '転入者数(日本人移動者)', '転出者数(日本人移動者)', '総人口', '65歳以上人口', '15~64歳人口', ] for col in b_num_cols: if col in df_b2022.columns: df_b2022[col] = pd.to_numeric(df_b2022[col], errors='coerce') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。.astype(int) — 列を整数に変換(年度などを数値比較するため)。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。105 106 107 108 109 110 111 112 113 114 | # 有効求人倍率(月間有効求人数 / 就職件数(分母として近似)) # 実際はハローワーク統計で算出されるが、代理指標として使用 df_b2022['有効求人倍率_代理'] = ( df_b2022['月間有効求人数(一般)'] / df_b2022['就職件数(一般)'] ) # 転入率(転入/総人口×1000) df_b2022['転入率'] = df_b2022['転入者数(日本人移動者)'] / df_b2022['総人口'] * 1000 print(f"SSDSE-B 2022年: {len(df_b2022)} 都道府県") |
SSDSE-B を読み込み中... SSDSE-B 2022年: 47 都道府県
df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | df = pd.merge( df_e_pref[['都道府県', '地域コード', '従業者割合_製造業', '従業者割合_建設業', '従業者割合_情報通信業', '従業者割合_卸売小売業', '従業者割合_宿泊飲食業', '従業者割合_医療福祉業', 'LQ_製造業', 'LQ_建設業', 'LQ_情報通信業', 'LQ_卸売小売業', 'LQ_医療福祉業', 'C122101', '高齢化率', '人口密度']], df_b2022[['都道府県', '消費支出(二人以上の世帯)', '有効求人倍率_代理', '転入率']], on='都道府県', how='inner' ) df['地域区分'] = df['都道府県'].map(region_map) df['地域色'] = df['地域区分'].map(region_colors) # 1人当たり県民所得を万円単位に(元データは千円単位) df['県民所得_万円'] = df['C122101'] / 10 # 千円→万円 print(f"結合後: {len(df)} 都道府県") print() |
結合後: 47 都道府県
df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。製造業従業者割合の上位10都道府県と下位10都道府県の産業構成を積み上げ棒グラフで比較する。産業構造の地域差が一目で確認できる。
複数のカテゴリ(産業)の割合を同時に比較するには積み上げ棒グラフが有効。全体(100%)に対する各カテゴリの相対的大きさと、都道府県間の比較が1枚の図で可能になる。
136 137 138 139 140 141 142 | print() print("図1 生成中...") # 製造業割合で上位10・下位10を選択 df_sorted_mfg = df.sort_values('従業者割合_製造業', ascending=False) target_prefs = pd.concat([df_sorted_mfg.head(10), df_sorted_mfg.tail(10)]) target_prefs = target_prefs.reset_index(drop=True) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。143 144 145 146 147 148 149 150 151 | # 積み上げ棒グラフの業種 bar_cols = [ ('従業者割合_製造業', '製造業', '#e05c5c'), ('従業者割合_建設業', '建設業', '#f0a500'), ('従業者割合_情報通信業', '情報通信業', '#4e9af1'), ('従業者割合_卸売小売業', '卸売・小売業', '#5cb85c'), ('従業者割合_宿泊飲食業', '宿泊・飲食業', '#9b59b6'), ('従業者割合_医療福祉業', '医療・福祉業', '#f39c12'), ] |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.dropna() は欠損行を除去、.copy() は独立したコピーを作る。pandasで警告を防ぐ定石。152 153 154 155 156 157 158 159 160 161 162 163 164 | # 残りをその他として計算 listed_cols = [c[0] for c in bar_cols] target_prefs['その他'] = 100 - target_prefs[listed_cols].sum(axis=1) fig1, ax1 = plt.subplots(figsize=(14, 7)) x = np.arange(len(target_prefs)) bottom = np.zeros(len(target_prefs)) for col, label, color in bar_cols: vals = target_prefs[col].values ax1.bar(x, vals, bottom=bottom, label=label, color=color, width=0.72, edgecolor='white', linewidth=0.5) bottom += vals |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。165 166 167 168 169 170 171 172 | # その他 ax1.bar(x, target_prefs['その他'].values, bottom=bottom, label='その他', color='#aaaaaa', width=0.72, edgecolor='white', linewidth=0.5) # 上位10と下位10の境界線 ax1.axvline(x=9.5, color='black', linestyle='--', linewidth=1.2, alpha=0.6) ax1.text(4.5, 102, '製造業割合 上位10県', ha='center', fontsize=11, fontweight='bold', color='#333333') ax1.text(14.5, 102, '製造業割合 下位10県', ha='center', fontsize=11, fontweight='bold', color='#666666') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | # ラベル設定 ax1.set_xticks(x) pref_labels = target_prefs['都道府県'].str.replace('県', '').str.replace('府', '').str.replace('都', '').str.replace('道', '') ax1.set_xticklabels(pref_labels, rotation=45, ha='right', fontsize=9) ax1.set_ylabel('産業別従業者割合(%)', fontsize=12) ax1.set_title('都道府県別産業構造(製造業割合 上位・下位各10都道府県)\n─ 民営事業所 従業者数ベース(2021年) ─', fontsize=13, fontweight='bold', pad=12) ax1.legend(loc='upper right', fontsize=9, ncol=2) ax1.set_ylim(0, 115) ax1.set_xlim(-0.6, len(target_prefs) - 0.4) ax1.yaxis.grid(True, alpha=0.3, linestyle='--') ax1.set_axisbelow(True) plt.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2020_H5_3_fig1.png'), bbox_inches='tight') plt.close(fig1) print(" -> 2020_H5_3_fig1.png 保存完了") |
図1 生成中... -> 2020_H5_3_fig1.png 保存完了
.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。消費支出(所得の代理変数)を目的変数とし、産業構造・人口構造・雇用環境を説明変数としたOLS重回帰を実施した。変数はすべて標準化(平均0・分散1)し、標準化偏回帰係数(β)で効果の大きさを比較する。
| 説明変数 | 標準化係数(β) | p値 | 有意性 | 解釈 |
|---|---|---|---|---|
| 製造業従業者割合 | +0.407 | 0.009 | ** | 製造業が多いほど消費支出が高い |
| 有効求人倍率(代理) | +0.610 | 0.048 | * | 求人超過の地域は消費水準が高い |
| 情報通信業従業者割合 | −0.044 | 0.871 | n.s. | 有意な効果なし |
| 高齢化率 | −0.096 | 0.606 | n.s. | 有意な効果なし(単相関では有意) |
| 人口密度 | −0.169 | 0.565 | n.s. | 有意な効果なし |
| モデル全体 | R²=0.423, 修正済みR²=0.352, F(5,41)=6.00, p=0.0003 | |||
説明変数間の相関が高いと、個々の係数推定が不安定になる「多重共線性」が生じる。VIF(分散膨張係数)= 1/(1-R²ⱼ) で診断する。VIF>10は問題あり。
191 192 193 194 195 196 197 198 199 200 201 | print("図2 生成中...") fig2, ax2 = plt.subplots(figsize=(10, 7)) for region, color in region_colors.items(): mask = df['地域区分'] == region ax2.scatter( df.loc[mask, '従業者割合_製造業'], df.loc[mask, '消費支出(二人以上の世帯)'], c=color, label=region, s=70, alpha=0.85, edgecolors='white', linewidth=0.6, zorder=3 ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。.dropna() は欠損行を除去、.copy() は独立したコピーを作る。pandasで警告を防ぐ定石。202 203 204 205 206 207 208 209 210 | # 都道府県ラベル for _, row in df.iterrows(): pref_short = row['都道府県'].replace('県', '').replace('府', '').replace('都', '').replace('道', '') ax2.annotate( pref_short, xy=(row['従業者割合_製造業'], row['消費支出(二人以上の世帯)']), xytext=(3, 3), textcoords='offset points', fontsize=7, color='#444444', zorder=4 ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | # 回帰直線 x_mfg = df['従業者割合_製造業'].values y_csp = df['消費支出(二人以上の世帯)'].values mask_valid = ~(np.isnan(x_mfg) | np.isnan(y_csp)) slope, intercept, r_val, p_val, std_err = stats.linregress(x_mfg[mask_valid], y_csp[mask_valid]) x_line = np.linspace(x_mfg[mask_valid].min(), x_mfg[mask_valid].max(), 100) ax2.plot(x_line, slope * x_line + intercept, 'k--', linewidth=1.5, alpha=0.7, zorder=2, label=f'回帰直線 (r={r_val:.3f})') ax2.set_xlabel('製造業従業者割合(%)', fontsize=12) ax2.set_ylabel('消費支出(円/月・二人以上世帯)', fontsize=12) ax2.set_title(f'製造業割合と消費支出の関係(47都道府県、2021/2022年)\nr={r_val:.3f}, p={p_val:.4f}', fontsize=13, fontweight='bold') ax2.legend(fontsize=9, loc='upper left', ncol=2) ax2.yaxis.get_major_formatter().set_useOffset(False) ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda val, _: f'{val/10000:.0f}万')) ax2.xaxis.grid(True, alpha=0.3, linestyle='--') ax2.yaxis.grid(True, alpha=0.3, linestyle='--') ax2.set_axisbelow(True) plt.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2020_H5_3_fig2.png'), bbox_inches='tight') plt.close(fig2) print(f" -> 2020_H5_3_fig2.png 保存完了 (r={r_val:.3f}, p={p_val:.4f})") |
図2 生成中... -> 2020_H5_3_fig2.png 保存完了 (r=0.394, p=0.0061)
stats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。製造業従業者割合と消費支出の関係を散布図で可視化し、地域ブロック別の傾向を比較する。また相関ヒートマップで変数間の関係構造を俯瞰する。
| 変数ペア | r値 | p値 | 解釈 |
|---|---|---|---|
| 製造業割合 vs 消費支出 | +0.394 | 0.006** | 製造業地域で消費水準が高い |
| 建設業割合 vs 消費支出 | −0.437 | 0.002** | 建設業依存は消費低迷と関連 |
| 有効求人倍率 vs 消費支出 | +0.448 | 0.002** | 雇用市場の活況が消費を押し上げ |
| 高齢化率 vs 消費支出 | −0.382 | 0.008** | 高齢化が進む地域で消費水準が低い |
| 転入率 vs 消費支出 | +0.318 | 0.029* | 転入超過地域が経済的に活力ある傾向 |
| 情報通信業割合 vs 消費支出 | +0.171 | 0.251 | 有意な相関なし(東京集中の効果) |
製造業が地域に集積することで生まれる経済的便益を「集積効果」という。同業種企業の集積(特化経済)と多様な産業の集積(都市化経済)の2種類がある。LQが高い地域では特化経済の恩恵が消費水準向上に貢献していると解釈できる。
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | print("図3 生成中...") heat_vars = { '製造業\n従業者割合': '従業者割合_製造業', '建設業\n従業者割合': '従業者割合_建設業', '情報通信業\n従業者割合': '従業者割合_情報通信業', '医療福祉業\n従業者割合': '従業者割合_医療福祉業', '製造業\nLQ': 'LQ_製造業', '高齢化率': '高齢化率', '人口密度': '人口密度', '有効求人\n倍率(代理)': '有効求人倍率_代理', '転入率': '転入率', '消費支出': '消費支出(二人以上の世帯)', } heat_df = df[[v for v in heat_vars.values()]].copy() heat_df.columns = list(heat_vars.keys()) corr_matrix = heat_df.corr() fig3, ax3 = plt.subplots(figsize=(10, 8)) n = len(corr_matrix) # ヒートマップ描画 im = ax3.imshow(corr_matrix.values, cmap='RdBu_r', vmin=-1, vmax=1, aspect='auto') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。259 260 261 262 263 264 265 266 267 268 | # カラーバー cbar = fig3.colorbar(im, ax=ax3, fraction=0.046, pad=0.04) cbar.set_label('Pearson相関係数', fontsize=10) # 軸ラベル labels = list(corr_matrix.columns) ax3.set_xticks(range(n)) ax3.set_yticks(range(n)) ax3.set_xticklabels(labels, fontsize=9, rotation=45, ha='right') ax3.set_yticklabels(labels, fontsize=9) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | # セル内に数値を表示 for i in range(n): for j in range(n): val = corr_matrix.values[i, j] text_color = 'white' if abs(val) > 0.6 else 'black' ax3.text(j, i, f'{val:.2f}', ha='center', va='center', fontsize=8.5, color=text_color, fontweight='bold' if abs(val) > 0.5 else 'normal') ax3.set_title('産業構造・経済指標の相関ヒートマップ(47都道府県)\n─ Pearson相関係数 ─', fontsize=13, fontweight='bold', pad=14) plt.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2020_H5_3_fig3.png'), bbox_inches='tight') plt.close(fig3) print(" -> 2020_H5_3_fig3.png 保存完了") |
図3 生成中... -> 2020_H5_3_fig3.png 保存完了
.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。| 都道府県 | 製造業LQ | 製造業割合 | 消費支出(月額) |
|---|---|---|---|
| 滋賀県 | 1.77 | 26.9% | 319,456円 |
| 三重県 | 1.71 | 26.1% | 277,102円 |
| 富山県 | 1.70 | 25.8% | 316,801円 |
| 静岡県 | 1.68 | 25.5% | 300,439円 |
| 群馬県 | 1.66 | 25.1% | 310,407円 |
| 岐阜県 | 1.63 | 24.8% | 313,314円 |
| 栃木県 | 1.60 | 24.3% | 297,278円 |
| 愛知県 | 1.57 | 23.8% | 319,344円 |
| 長野県 | 1.53 | 23.2% | 298,965円 |
| 全国平均(47都道府県) | 289,630円 | ||
製造業特化地域9県の消費支出平均は約30.6万円/月で、全国平均比約+5.6%高い。
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | import os import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import statsmodels.api as sm 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 FIG_DIR = 'html/figures' DATA_B = 'data/raw/SSDSE-B-2026.csv' DATA_E = 'data/raw/SSDSE-E-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} のように書式も指定できます。304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | print("=" * 60) print("産業別従業者割合 (2021年度) 統計サマリー") print("=" * 60) for col in ['従業者割合_製造業', '従業者割合_建設業', '従業者割合_情報通信業']: m = df[col].mean() s = df[col].std() print(f" {col}: 平均={m:.1f}%, 標準偏差={s:.1f}%") print() print("=" * 60) print("LQ(製造業特化係数)上位・下位5都道府県") print("=" * 60) lq_sorted = df[['都道府県', 'LQ_製造業', '従業者割合_製造業']].sort_values('LQ_製造業', ascending=False) print("製造業LQ 上位5:") print(lq_sorted.head(5).to_string(index=False)) print("製造業LQ 下位5:") print(lq_sorted.tail(5).to_string(index=False)) |
============================================================ 産業別従業者割合 (2021年度) 統計サマリー ============================================================ 従業者割合_製造業: 平均=17.3%, 標準偏差=5.4% 従業者割合_建設業: 平均=7.2%, 標準偏差=1.4% 従業者割合_情報通信業: 平均=1.6%, 標準偏差=1.6% ============================================================ LQ(製造業特化係数)上位・下位5都道府県 ============================================================ 製造業LQ 上位5: 都道府県 LQ_製造業 従業者割合_製造業 滋賀県 1.768323 26.864036 三重県 1.714782 26.050648 富山県 1.700213 25.829312 静岡県 1.677043 25.477323 群馬県 1.655047 25.143170 製造業LQ 下位5: 都道府県 LQ_製造業 従業者割合_製造業 福岡県 0.714358 10.852389 高知県 0.660001 10.026608 北海道 0.569658 8.654145 東京都 0.385602 5.857991 沖縄県 0.362910 5.513265
sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。321 322 323 324 325 326 327 328 329 330 | print() print("=" * 60) print("消費支出との相関分析") print("=" * 60) corr_vars = ['従業者割合_製造業', '従業者割合_建設業', '従業者割合_情報通信業', 'LQ_製造業', '高齢化率', '人口密度', '有効求人倍率_代理', '転入率'] for var in corr_vars: r, p = stats.pearsonr(df[var].dropna(), df.loc[df[var].notna(), '消費支出(二人以上の世帯)']) sig = "**" if p < 0.01 else "*" if p < 0.05 else " " print(f" {var:20s}: r={r:+.3f} (p={p:.4f}) {sig}") |
============================================================ 消費支出との相関分析 ============================================================ 従業者割合_製造業 : r=+0.394 (p=0.0061) ** 従業者割合_建設業 : r=-0.437 (p=0.0021) ** 従業者割合_情報通信業 : r=+0.171 (p=0.2511) LQ_製造業 : r=+0.394 (p=0.0061) ** 高齢化率 : r=-0.382 (p=0.0080) ** 人口密度 : r=+0.236 (p=0.1106) 有効求人倍率_代理 : r=+0.448 (p=0.0016) ** 転入率 : r=+0.318 (p=0.0292) *
stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。np.cumsum(arr) は累積和、np.linspace(a, b, n) は「aからbを等間隔でn個」。NumPyの定石です。331 332 333 334 335 336 337 338 339 340 341 | print() print("=" * 60) print("OLS 重回帰分析(目的変数:消費支出)") print("=" * 60) reg_vars = ['従業者割合_製造業', '従業者割合_情報通信業', '高齢化率', '人口密度', '有効求人倍率_代理'] df_reg = df[['消費支出(二人以上の世帯)'] + reg_vars].dropna() y = df_reg['消費支出(二人以上の世帯)'].values X = df_reg[reg_vars].values |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。{値:.2f}(小数2桁)、{値:,}(3桁区切り)、{値:>10}(右寄せ10桁)など、覚えると出力が一気に整います。342 343 344 345 346 347 348 | # 標準化 y_std = (y - y.mean()) / y.std() X_std = (X - X.mean(axis=0)) / X.std(axis=0) X_sm = sm.add_constant(X_std) model = sm.OLS(y_std, X_sm).fit() print(model.summary()) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。349 350 351 352 353 354 355 356 357 358 | # 標準化偏回帰係数 coefs = model.params[1:] # 定数項除く pvals = model.pvalues[1:] conf = pd.DataFrame(model.conf_int()).iloc[1:] print() print("標準化偏回帰係数:") for name, c, p in zip(reg_vars, coefs, pvals): sig = "**" if p < 0.01 else "*" if p < 0.05 else " " print(f" {name:25s}: β={c:+.4f} (p={p:.4f}) {sig}") |
============================================================
OLS 重回帰分析(目的変数:消費支出)
============================================================
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 0.423
Model: OLS Adj. R-squared: 0.352
Method: Least Squares F-statistic: 6.001
Date: Mon, 18 May 2026 Prob (F-statistic): 0.000297
Time: 11:23:38 Log-Likelihood: -53.784
No. Observations: 47 AIC: 119.6
Df Residuals: 41 BIC: 130.7
Df Model: 5
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const -7.355e-16 0.119 -6.2e-15 1.000 -0.240 0.240
x1 0.4067 0.148 2.742 0.009 0.107 0.706
x2 -0.0445 0.272 -0.164 0.871 -0.593 0.504
x3 -0.0961 0.185 -0.520 0.606 -0.470 0.277
x4 -0.1694 0.292 -0.580 0.565 -0.760 0.421
x5 0.6101 0.300 2.036 0.048 0.005 1.215
==============================================================================
Omnibus: 4.062 Durbin-Watson: 2.167
Prob(Omnibus): 0.131 Jarque-Bera (JB): 2.912
Skew: -0.534 Prob(JB): 0.233
Kurtosis: 3.588 Cond. No. 5.67
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
標準化偏回帰係数:
従業者割合_製造業 : β=+0.4067 (p=0.0090) **
従業者割合_情報通信業 : β=-0.0445 (p=0.8707)
高齢化率 : β=-0.0961 (p=0.6060)
人口密度 : β=-0.1694 (p=0.5654)
有効求人倍率_代理 : β=+0.6101 (p=0.0482) *.dropna() は欠損行を除去、.copy() は独立したコピーを作る。pandasで警告を防ぐ定石。359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | print("図4 生成中...") var_labels_jp = { '従業者割合_製造業': '製造業\n従業者割合', '従業者割合_情報通信業': '情報通信業\n従業者割合', '高齢化率': '高齢化率', '人口密度': '人口密度', '有効求人倍率_代理': '有効求人倍率\n(代理)', } coef_vals = np.array(model.params[1:]) pval_vals = np.array(model.pvalues[1:]) ci_low = pd.DataFrame(model.conf_int()).iloc[1:, 0].values ci_high = pd.DataFrame(model.conf_int()).iloc[1:, 1].values labels_jp = [var_labels_jp[v] for v in reg_vars] colors_bar = ['#e05c5c' if c > 0 else '#4e9af1' for c in coef_vals] sig_markers = ['**' if p < 0.01 else '*' if p < 0.05 else '' for p in pval_vals] fig4, ax4 = plt.subplots(figsize=(9, 6)) y_pos = np.arange(len(labels_jp)) bars = ax4.barh(y_pos, coef_vals, color=colors_bar, alpha=0.82, edgecolor='white', linewidth=0.5, height=0.55) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | # 信頼区間 for i, (lo, hi) in enumerate(zip(ci_low, ci_high)): ax4.plot([lo, hi], [i, i], 'k-', linewidth=2.5, alpha=0.7) ax4.plot([lo, lo], [i-0.08, i+0.08], 'k-', linewidth=1.5, alpha=0.7) ax4.plot([hi, hi], [i-0.08, i+0.08], 'k-', linewidth=1.5, alpha=0.7) # 係数値と有意性マーカー for i, (c, sig) in enumerate(zip(coef_vals, sig_markers)): offset = 0.02 if c >= 0 else -0.02 align = 'left' if c >= 0 else 'right' ax4.text(c + offset, i, f'{c:+.3f}{sig}', va='center', ha=align, fontsize=10, fontweight='bold', color='#333333') ax4.axvline(x=0, color='black', linewidth=1.2, alpha=0.7) ax4.set_yticks(y_pos) ax4.set_yticklabels(labels_jp, fontsize=10) ax4.set_xlabel('標準化偏回帰係数(β)', fontsize=12) ax4.set_title('重回帰分析:地域消費支出の決定要因\n(標準化偏回帰係数と95%信頼区間、n=47都道府県)', fontsize=13, fontweight='bold') ax4.xaxis.grid(True, alpha=0.3, linestyle='--') ax4.set_axisbelow(True) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | # 凡例(有意性) ax4.text(0.99, 0.02, '**p<0.01 *p<0.05 (95%CI)', transform=ax4.transAxes, ha='right', va='bottom', fontsize=9, color='#555555', bbox=dict(boxstyle='round,pad=0.3', fc='white', alpha=0.7)) # 統計値の注記 r2_adj = model.rsquared_adj ax4.text(0.99, 0.98, f'修正済みR²={r2_adj:.3f}', transform=ax4.transAxes, ha='right', va='top', fontsize=10, color='#222222', bbox=dict(boxstyle='round,pad=0.3', fc='#fff9c4', ec='#f9a825', alpha=0.9)) plt.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2020_H5_3_fig4.png'), bbox_inches='tight') plt.close(fig4) print(f" -> 2020_H5_3_fig4.png 保存完了 (修正済みR²={r2_adj:.3f})") |
図4 生成中... -> 2020_H5_3_fig4.png 保存完了 (修正済みR²=0.352)
[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | print() print("=" * 60) print("最終統計サマリー(HTML作成用)") print("=" * 60) # 製造業LQが高い都道府県(製造業特化地域) lq_high = df[df['LQ_製造業'] >= 1.5][['都道府県', 'LQ_製造業', '従業者割合_製造業', '消費支出(二人以上の世帯)']].sort_values('LQ_製造業', ascending=False) print("製造業LQ≥1.5の都道府県:") print(lq_high.to_string(index=False)) print() mfg_csp_r, mfg_csp_p = stats.pearsonr( df['従業者割合_製造業'].dropna(), df.loc[df['従業者割合_製造業'].notna(), '消費支出(二人以上の世帯)'] ) print(f"製造業割合 vs 消費支出: r={mfg_csp_r:.3f}, p={mfg_csp_p:.4f}") ict_csp_r, ict_csp_p = stats.pearsonr( df['従業者割合_情報通信業'].dropna(), df.loc[df['従業者割合_情報通信業'].notna(), '消費支出(二人以上の世帯)'] ) print(f"情報通信業割合 vs 消費支出: r={ict_csp_r:.3f}, p={ict_csp_p:.4f}") aging_csp_r, aging_csp_p = stats.pearsonr( df['高齢化率'].dropna(), df.loc[df['高齢化率'].notna(), '消費支出(二人以上の世帯)'] ) print(f"高齢化率 vs 消費支出: r={aging_csp_r:.3f}, p={aging_csp_p:.4f}") mfg_mean = df['従業者割合_製造業'].mean() mfg_std = df['従業者割合_製造業'].std() csp_mean = df['消費支出(二人以上の世帯)'].mean() csp_std = df['消費支出(二人以上の世帯)'].std() print() print(f"製造業従業者割合 全国平均: {mfg_mean:.1f}% ± {mfg_std:.1f}%") print(f"消費支出 全国平均: {csp_mean:.0f}円 ± {csp_std:.0f}円") print() print("全図生成完了。") |
============================================================ 最終統計サマリー(HTML作成用) ============================================================ 製造業LQ≥1.5の都道府県: 都道府県 LQ_製造業 従業者割合_製造業 消費支出(二人以上の世帯) 滋賀県 1.768323 26.864036 319456 三重県 1.714782 26.050648 277102 富山県 1.700213 25.829312 316801 静岡県 1.677043 25.477323 300439 群馬県 1.655047 25.143170 310407 岐阜県 1.631964 24.792493 313314 栃木県 1.597127 24.263251 297278 愛知県 1.566532 23.798455 319344 長野県 1.528785 23.225020 298965 製造業割合 vs 消費支出: r=0.394, p=0.0061 情報通信業割合 vs 消費支出: r=0.171, p=0.2511 高齢化率 vs 消費支出: r=-0.382, p=0.0080 製造業従業者割合 全国平均: 17.3% ± 5.4% 消費支出 全国平均: 289630円 ± 19187円 全図生成完了。
sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。本研究は、SSDSE-E(産業別従業者数・県民所得)とSSDSE-B(消費支出・雇用)を用いて、47都道府県の産業構造と地域経済水準の関係を相関分析・重回帰分析によって検証した。
政策的含意:製造業の集積・維持と雇用創出が地域経済の底上げに有効であることが統計的に支持された。「ものづくり地域」の競争力強化は、単に産業政策にとどまらず、地域住民の消費水準向上と生活の質(QoL)改善につながると考えられる。
データ出典: SSDSE-E-2026(産業別従業者数・県民所得 2021年度)、SSDSE-B-2026(消費支出・雇用 2022年度) — 統計センター公表実データ。
再現コード: code/2020_H5_3_shorei.py
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。