このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
1990年代以降、先進国の経済成長を牽引するのはモノの製造よりも知識・情報・イノベーションであるという「知識経済(Knowledge Economy)」の概念が注目されている。日本でも大学集積・高度人材の移動・教育投資が地域の産業競争力と深く関わると指摘されてきた。
まず「地域イノベーション・知識産業と経済成長の関係主成分分析と回帰」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
しかし、都道府県レベルで「知識産業の集積度」を統合的に測る指標はなく、個別指標の寄せ集めに留まることが多い。本研究は、SSDSE-B(都道府県別統計)を用い、主成分分析(PCA)によって複数の教育・人口移動指標を「知識経済指数(PC1スコア)」に統合し、それと消費支出水準との関係を重回帰で検証する。
SSDSE-B PCA Ward法 重回帰分析 知識経済指数
SSDSE-B-2026(社会・人口統計体系データセット・都道府県版)の2022年断面データを使用。47都道府県すべてのデータが揃っており、欠損値なし(n=47)。
| 変数名 | 元データ列 | 経済学的解釈 |
|---|---|---|
| 大学進学率 | 高等学校卒業者のうち進学者数 / 高等学校卒業者数 | 高等教育へのアクセス・集積度 |
| 大学学生割合 | 大学学生数 / 総人口 | 知識サービス業の代理(高度人材の蓄積) |
| 教育費 | 教育費(二人以上の世帯)[円/月] | 教育投資水準 |
| 転入率 | 転入者数(日本人移動者)/ 総人口 | 知識労働者の集積・人材流動性 |
| 高校等数/万人 | 高等学校数 / 総人口 × 10,000 | 教育インフラの普及度 |
| 変数名 | 元データ列 | 用途 |
|---|---|---|
| 消費支出 | 消費支出(二人以上の世帯)[円/月] | 所得水準・生活水準の代理 → 目的変数 |
| 求人倍率 | 月間有効求人数 / 月間有効求職者数 | 労働市場の需給バランス(参考指標) |
1 2 3 4 5 6 7 8 9 10 11 12 13 | df2022['大学進学率'] = ( df2022['高等学校卒業者のうち進学者数'] / df2022['高等学校卒業者数'] ) df2022['大学学生割合'] = ( df2022['大学学生数'] / df2022['総人口'] ) # 第三次産業(知識サービス)の代理 df2022['教育費'] = df2022['教育費(二人以上の世帯)'] df2022['転入率'] = ( df2022['転入者数(日本人移動者)'] / df2022['総人口'] ) df2022['高校等数_万人'] = ( df2022['高等学校数'] / df2022['総人口'] * 10000 ) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # 経済指標(2変数) df2022['消費支出'] = df2022['消費支出(二人以上の世帯)'] df2022['求人倍率'] = ( df2022['月間有効求人数(一般)'] / df2022['月間有効求職者数(一般)'] ) # 地域区分 region_map = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄' } region_colors = { '北海道・東北': '#4e9af1', '関東': '#e05c5c', '中部': '#f0a500', '近畿': '#5cb85c', '中国・四国': '#9b59b6', '九州・沖縄': '#f39c12' } df2022['地域区分'] = df2022['都道府県'].map(region_map) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。43 44 45 46 47 48 49 50 | Z = linkage(X_scaled, method='ward') labels_k4 = fcluster(Z, t=4, criterion='maxclust') df2022['cluster'] = labels_k4 print("\n=== Ward法クラスタ(k=4)===") for c in sorted(df2022['cluster'].unique()): prefs = df2022[df2022['cluster'] == c]['都道府県'].tolist() print(f" クラスタ{c}: {prefs}") |
=== Ward法クラスタ(k=4)=== クラスタ1: ['埼玉県', '神奈川県', '滋賀県'] クラスタ2: ['東京都', '京都府'] クラスタ3: ['宮城県', '茨城県', '栃木県', '群馬県', '千葉県', '石川県', '山梨県', '岐阜県', '静岡県', '愛知県', '三重県', '大阪府', '兵庫県', '奈良県', '岡山県', '広島県', '香川県', '福岡県'] クラスタ4: ['北海道', '青森県', '岩手県', '秋田県', '山形県', '福島県', '新潟県', '富山県', '福井県', '長野県', '和歌山県', '鳥取県', '島根県', '山口県', '徳島県', '愛媛県', '高知県', '佐賀県', '長崎県', '熊本県', '大分県', '宮崎県', '鹿児島県', '沖縄県']
[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | print("\n" + "="*50) print("=== HTML生成用 統計値サマリ ===") print("="*50) print(f"分析対象: 47都道府県(2022年断面)") print(f"PC1 説明分散比: {explained_var[0]*100:.1f}%") print(f"PC2 説明分散比: {explained_var[1]*100:.1f}%") print(f"PC3 説明分散比: {explained_var[2]*100:.1f}%") print(f"PC1+PC2 累積: {(explained_var[0]+explained_var[1])*100:.1f}%") print(f"PC1+PC2+PC3 累積: {sum(explained_var[:3])*100:.1f}%") print(f"重回帰 R2: {model.rsquared:.4f}") print(f"重回帰 R2adj: {model.rsquared_adj:.4f}") print(f"重回帰 F統計量: {model.fvalue:.2f}") print(f"重回帰 p(F): {model.f_pvalue:.4f}") print(f"beta_PC1: {beta_coefs[0]:.4f} (p={beta_pvals[0]:.4f})") print(f"beta_PC2: {beta_coefs[1]:.4f} (p={beta_pvals[1]:.4f})") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。{値:.2f}(小数2桁)、{値:,}(3桁区切り)、{値:>10}(右寄せ10桁)など、覚えると出力が一気に整います。66 67 68 69 70 71 72 | # 負荷量 print("\n負荷量行列 PC1:") for j, vl in enumerate(feature_cols): print(f" {vl}: {loadings[0,j]:.4f}") print("負荷量行列 PC2:") for j, vl in enumerate(feature_cols): print(f" {vl}: {loadings[1,j]:.4f}") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。plt.subplots(figsize=(W, H)) で図サイズ指定、fig.savefig(..., bbox_inches='tight') で余白を自動で詰めて保存。73 74 75 76 77 78 79 80 81 82 83 | # クラスタ別都道府県 print("\nクラスタ別都道府県:") for c in sorted(df2022['cluster'].unique()): prefs = df2022[df2022['cluster'] == c]['都道府県'].tolist() pc1_m = df2022[df2022['cluster'] == c]['PC1_知識経済指数'].mean() print(f" クラスタ{c}(PC1平均={pc1_m:.2f}): {', '.join(prefs)}") print("\n図ファイル確認:") for i in range(1, 5): fp = os.path.join(FIG_DIR, f'2019_U3_fig{i}.png') print(f" fig{i}: {'OK' if os.path.exists(fp) else 'NG'} - {fp}") |
================================================== === HTML生成用 統計値サマリ === ================================================== 分析対象: 47都道府県(2022年断面) PC1 説明分散比: 62.1% PC2 説明分散比: 15.6% PC3 説明分散比: 10.5% PC1+PC2 累積: 77.7% PC1+PC2+PC3 累積: 88.3% 重回帰 R2: 0.3465 重回帰 R2adj: 0.3168 重回帰 F統計量: 11.67 重回帰 p(F): 0.0001 beta_PC1: 0.5381 (p=0.0001) beta_PC2: -0.2388 (p=0.0565) 負荷量行列 PC1: 大学進学率: 0.4912 大学学生割合: 0.4253 教育費: 0.4028 転入率: 0.4481 高校等数_万人: -0.4635 負荷量行列 PC2: 大学進学率: 0.2215 大学学生割合: 0.6745 教育費: -0.6263 転入率: 0.0127 高校等数_万人: 0.3219 クラスタ別都道府県: クラスタ1(PC1平均=3.24): 埼玉県, 神奈川県, 滋賀県 クラスタ2(PC1平均=4.83): 東京都, 京都府 クラスタ3(PC1平均=0.63): 宮城県, 茨城県, 栃木県, 群馬県, 千葉県, 石川県, 山梨県, 岐阜県, 静岡県, 愛知県, 三重県, 大阪府, 兵庫県, 奈良県, 岡山県, 広島県, 香川県, 福岡県 クラスタ4(PC1平均=-1.28): 北海道, 青森県, 岩手県, 秋田県, 山形県, 福島県, 新潟県, 富山県, 福井県, 長野県, 和歌山県, 鳥取県, 島根県, 山口県, 徳島県, 愛媛県, 高知県, 佐賀県, 長崎県, 熊本県, 大分県, 宮崎県, 鹿児島県, 沖縄県 図ファイル確認: fig1: OK - html/figures/2019_U3_fig1.png fig2: OK - html/figures/2019_U3_fig2.png fig3: OK - html/figures/2019_U3_fig3.png fig4: OK - html/figures/2019_U3_fig4.png
.dropna() は欠損行を除去、.copy() は独立したコピーを作る。pandasで警告を防ぐ定石。5つの知識産業関連変数を StandardScaler で標準化(平均0・分散1)した後、sklearn の PCA を適用した。第1主成分(PC1)が全分散の 62.1%、第2主成分(PC2)が 15.6% を説明し、PC1+PC2 の累積寄与率は 77.7% に達した。
PCAは多変量データの分散を最大化する方向(主成分)を順次求める次元削減法。標準化が前提で、変数の単位が異なっても比較可能になる。
85 86 87 88 89 90 | fig, ax = plt.subplots(figsize=(9, 7)) for region, color in region_colors.items(): mask = df2022['地域区分'] == region ax.scatter(scores[mask, 0], scores[mask, 1], c=color, label=region, s=60, zorder=3, alpha=0.85) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | # 都道府県ラベル(全47) for i, row in df2022.iterrows(): ax.annotate(row['都道府県'], (scores[i, 0], scores[i, 1]), fontsize=7, ha='center', va='bottom', xytext=(0, 4), textcoords='offset points', color='#333333') # 変数ベクトル(バイプロット) scale = 2.5 for j, vl in enumerate(var_labels): ax.annotate('', xy=(loadings[0, j]*scale, loadings[1, j]*scale), xytext=(0, 0), arrowprops=dict(arrowstyle='->', color='#1565C0', lw=1.5)) ax.text(loadings[0, j]*scale*1.1, loadings[1, j]*scale*1.1, vl, fontsize=8, color='#1565C0', ha='center', va='center') ax.axhline(0, color='gray', lw=0.6, ls='--', alpha=0.5) ax.axvline(0, color='gray', lw=0.6, ls='--', alpha=0.5) ax.set_xlabel(f'PC1(説明分散比 {explained_var[0]*100:.1f}%)', fontsize=12) ax.set_ylabel(f'PC2(説明分散比 {explained_var[1]*100:.1f}%)', fontsize=12) ax.set_title('図1:PCAバイプロット(知識経済変数、2022年、47都道府県)', fontsize=13, fontweight='bold') ax.legend(title='地域区分', loc='lower right', fontsize=9, title_fontsize=9) ax.grid(True, alpha=0.3) fig.tight_layout() fig.savefig(os.path.join(FIG_DIR, '2019_U3_fig1.png'), dpi=150, bbox_inches='tight') plt.close(fig) print("\n[保存] 図1: PCAバイプロット") |
[保存] 図1: PCAバイプロット
ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。各変数が各主成分とどのように関連しているかを、負荷量ヒートマップで可視化した。PC1では大学進学率(+0.491)・転入率(+0.448)・大学学生割合(+0.425)・教育費(+0.403)が正の高負荷量を示し、高校等数/万人(−0.464)が負に強く寄与している。
| 主成分 | 正の高負荷量変数 | 負の高負荷量変数 | 解釈 |
|---|---|---|---|
| PC1 (62.1%) |
大学進学率(+0.491) 転入率(+0.448) 大学学生割合(+0.425) 教育費(+0.403) |
高校等数/万人(−0.464) | 知識経済集積度 都市・大学集積型↑ 過疎・地方型↓ |
| PC2 (15.6%) |
大学学生割合(+0.675) | 教育費(−0.626) | 学生集積vs家計教育費 学生多いが家計負担低↑ 家計教育費高いが学生少↓ |
| PC3 (10.5%) |
教育費 大学進学率 |
転入率 | 教育投資vs流動性 |
負荷量は「各変数が主成分とどれだけ相関しているか」、スコアは「各観測値(都道府県)の主成分上での座標」。バイプロットはこの2つを1枚の図に重ねて表示する。
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | fig, ax = plt.subplots(figsize=(8, 4)) load_matrix = loadings[:3, :] # (3, 5) short_labels = ['大学\n進学率', '大学学生\n割合', '教育費', '転入率', '高校等数\n/万人'] im = ax.imshow(load_matrix, cmap='RdBu_r', vmin=-1, vmax=1, aspect='auto') plt.colorbar(im, ax=ax, label='負荷量') ax.set_xticks(range(len(short_labels))) ax.set_xticklabels(short_labels, fontsize=10) ax.set_yticks(range(3)) ax.set_yticklabels([f'PC{i+1}({explained_var[i]*100:.1f}%)' for i in range(3)], fontsize=10) for r in range(3): for c in range(len(short_labels)): val = load_matrix[r, c] ax.text(c, r, f'{val:.3f}', ha='center', va='center', fontsize=11, fontweight='bold', color='white' if abs(val) > 0.5 else '#222') ax.set_title('図2:主成分負荷量ヒートマップ(PC1〜PC3)', fontsize=12, fontweight='bold') fig.tight_layout() fig.savefig(os.path.join(FIG_DIR, '2019_U3_fig2.png'), dpi=150, bbox_inches='tight') plt.close(fig) print("[保存] 図2: 負荷量ヒートマップ") |
[保存] 図2: 負荷量ヒートマップ
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。標準化した5変数を用いてWard法(階層的クラスタリング)を適用し、k=4でクラスタを分割した。デンドログラムの赤破線がk=4のカット位置を示す。
東京都・京都府
PC1平均≈4.83(最高)
大学学生割合・大学進学率・転入率いずれも突出して高い。
日本を代表する知識産業集積地。
埼玉県・神奈川県・滋賀県
PC1平均≈3.24
首都圏・大都市近郊で大学集積・転入率が高い。
知識経済が発達した大都市圏郊外。
宮城・茨城・千葉・愛知・大阪・福岡など18府県
PC1平均≈0.63
地方中核都市・政令市を持つ県が中心。
大学・産業が一定程度集積している。
北海道・東北・北陸・四国・九州南部など24県
PC1平均≈−1.28
農村部・過疎地を多く含む。大学・転入者が少なく
高校等数/万人は相対的に高い。
Ward法は「クラスタ内の二乗和を最小化するように統合」する手法で、均等サイズのクラスタを形成しやすい特徴がある。最適クラスタ数kはデンドログラムの「長い枝」がどこにあるかで判断する。
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | fig, ax = plt.subplots(figsize=(14, 6)) # クラスタ4のカット高さを取得 sorted_z = np.sort(Z[:, 2]) cut_height = (sorted_z[-3] + sorted_z[-4]) / 2 # 4クラスタ境界 dendrogram(Z, labels=list(df2022['都道府県']), ax=ax, leaf_rotation=90, leaf_font_size=9, color_threshold=cut_height) ax.axhline(cut_height, color='red', ls='--', lw=1.5, label=f'k=4 カット(高さ≈{cut_height:.2f})') ax.set_title('図3:Ward法デンドログラム(47都道府県、k=4)', fontsize=12, fontweight='bold') ax.set_xlabel('都道府県', fontsize=10) ax.set_ylabel('距離(Ward法)', fontsize=10) ax.legend(fontsize=9) fig.tight_layout() fig.savefig(os.path.join(FIG_DIR, '2019_U3_fig3.png'), dpi=150, bbox_inches='tight') plt.close(fig) print("[保存] 図3: Wardデンドログラム") |
[保存] 図3: Wardデンドログラム
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。s[:-n]「末尾n文字を除く」/s[n:]「先頭n文字を除く」。スライス [start:stop:step] はリスト・タプル・文字列共通の基本ワザです。PC1(知識経済指数)とPC2を説明変数、消費支出(二人以上世帯)を目的変数として OLS 重回帰を実施した。PC1は1%水準で有意(β=0.538, p<0.001)、PC2は限界的有意(β=−0.239, p=0.057)。
| 変数 | 標準化偏回帰係数 (β) | t値 | p値 | 95%信頼区間 | 有意性 |
|---|---|---|---|---|---|
| PC1(知識経済指数) | +0.538 | 4.415 | <0.001 | [+0.271, +0.805] | *** |
| PC2 | −0.239 | −1.959 | 0.057 | [−0.483, +0.008] | †(傾向) |
| 定数項 | — | 125.2 | <0.001 | — | — |
† p<0.10 *** p<0.001。N=47都道府県。目的変数:消費支出(二人以上世帯)。
単位の異なる変数を比較するために、目的変数・説明変数をすべて標準化(z得点)してから推定した回帰係数がβ係数。「1標準偏差の変化に対する目的変数の標準偏差単位での変化」を表し、変数の相対的な影響力を比較できる。
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 | fig, ax = plt.subplots(figsize=(7, 4)) pred_names = ['PC1\n(知識経済指数)', 'PC2\n(教育費・転入)'] colors_bar = ['#1565C0' if p < 0.05 else '#aaaaaa' for p in beta_pvals] bars = ax.barh(pred_names, beta_coefs, color=colors_bar, edgecolor='white', height=0.5) # エラーバー(95%CI) ci = model_std.conf_int() if hasattr(ci, 'iloc'): ci_low = ci.iloc[1:, 0].values ci_high = ci.iloc[1:, 1].values else: ci_low = ci[1:, 0] ci_high = ci[1:, 1] for i, (lo, hi, val) in enumerate(zip(ci_low, ci_high, beta_coefs)): ax.plot([lo, hi], [i, i], color='#333', lw=2, zorder=5) ax.text(val + 0.02 if val >= 0 else val - 0.02, i, f'{val:.3f}\n(p={beta_pvals[i]:.3f})', va='center', ha='left' if val >= 0 else 'right', fontsize=9, color='#333') ax.axvline(0, color='black', lw=1) ax.set_xlabel('標準化偏回帰係数 (β)', fontsize=11) ax.set_title('図4:標準化偏回帰係数(PC1, PC2 → 消費支出)', fontsize=12, fontweight='bold') ax.set_xlim(-1.2, 1.2) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。np.cumsum(arr) は累積和、np.linspace(a, b, n) は「aからbを等間隔でn個」。NumPyの定石です。188 189 190 191 192 193 194 195 196 197 198 | # 凡例 from matplotlib.patches import Patch legend_els = [Patch(color='#1565C0', label='p<0.05(有意)'), Patch(color='#aaaaaa', label='p≥0.05(非有意)')] ax.legend(handles=legend_els, fontsize=9, loc='lower right') ax.grid(axis='x', alpha=0.3) fig.tight_layout() fig.savefig(os.path.join(FIG_DIR, '2019_U3_fig4.png'), dpi=150, bbox_inches='tight') plt.close(fig) print("[保存] 図4: 標準化偏回帰係数プロット") |
<string>:34: UserWarning: Glyph 8805 (\N{GREATER-THAN OR EQUAL TO}) missing from font(s) Hiragino Sans.
<string>:35: UserWarning: Glyph 8805 (\N{GREATER-THAN OR EQUAL TO}) missing from font(s) Hiragino Sans.
[保存] 図4: 標準化偏回帰係数プロットimport pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。{値:.2f}(小数2桁)、{値:,}(3桁区切り)、{値:>10}(右寄せ10桁)など、覚えると出力が一気に整います。本分析の結果、知識経済指数(PC1)と消費支出水準の間に有意な正の関係が確認された。この知見は地域振興政策に以下の示唆を与える。
200 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 | 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 from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA from scipy.cluster.hierarchy import dendrogram, linkage, fcluster 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) 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) df2022 = df_b[df_b['年度'] == 2022].copy().reset_index(drop=True) print(f"2022年断面データ: {len(df2022)} 都道府県") |
2022年断面データ: 47 都道府県
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)。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。df['地域コード'].str.match(r'^R\d{5}', ...) — 正規表現で「R+数字5桁」の行(47都道府県)だけTrueにし、真偽値で行をフィルタ。.astype(int) — 列を整数に変換(年度などを数値比較するため)。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | feature_cols = ['大学進学率', '大学学生割合', '教育費', '転入率', '高校等数_万人'] var_labels = ['大学進学率', '大学学生割合\n(知識集積)', '教育費', '転入率', '高校等数\n/万人'] X = df2022[feature_cols].values scaler = StandardScaler() X_scaled = scaler.fit_transform(X) pca = PCA(n_components=3) scores = pca.fit_transform(X_scaled) # shape (47, 3) loadings = pca.components_ # shape (3, 5) explained_var = pca.explained_variance_ratio_ print("\n=== PCA 説明分散比 ===") for i, ev in enumerate(explained_var): print(f" PC{i+1}: {ev:.4f} ({ev*100:.1f}%)") print(f" PC1+PC2: {(explained_var[0]+explained_var[1])*100:.1f}%") # 知識経済指数 = PC1スコア(符号調整:大学進学率がPC1正になるよう) # PC1が大学進学率・大学学生割合で正→そのまま if loadings[0, 0] < 0: # 大学進学率の負荷量が負なら符号反転 scores[:, 0] = -scores[:, 0] loadings[0, :] = -loadings[0, :] df2022['PC1_知識経済指数'] = scores[:, 0] df2022['PC2'] = scores[:, 1] |
=== PCA 説明分散比 === PC1: 0.6212 (62.1%) PC2: 0.1561 (15.6%) PC3: 0.1053 (10.5%) PC1+PC2: 77.7%
StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。251 252 253 254 255 256 | y_cons = df2022['消費支出'].values X_reg = sm.add_constant(np.column_stack([scores[:, 0], scores[:, 1]])) model = sm.OLS(y_cons, X_reg).fit() print("\n=== 重回帰分析結果(PC1, PC2 → 消費支出)===") print(model.summary()) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | # 標準化偏回帰係数(beta) y_std = (y_cons - y_cons.mean()) / y_cons.std() X_std = np.column_stack([ (scores[:, 0] - scores[:, 0].mean()) / scores[:, 0].std(), (scores[:, 1] - scores[:, 1].mean()) / scores[:, 1].std() ]) X_std_wc = sm.add_constant(X_std) model_std = sm.OLS(y_std, X_std_wc).fit() beta_coefs = model_std.params[1:] # PC1, PC2 の標準化偏回帰係数 beta_pvals = model_std.pvalues[1:] print("\n=== 標準化偏回帰係数 ===") print(f" beta_PC1 = {beta_coefs[0]:.4f} (p={beta_pvals[0]:.4f})") print(f" beta_PC2 = {beta_coefs[1]:.4f} (p={beta_pvals[1]:.4f})") print(f" R2 = {model.rsquared:.4f}, R2adj = {model.rsquared_adj:.4f}") print(f" F = {model.fvalue:.4f}, p(F) = {model.f_pvalue:.4f}") |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。273 274 275 276 277 | # 求人倍率との回帰も補足確認 X_reg2 = sm.add_constant(np.column_stack([scores[:, 0], scores[:, 1]])) y_kyu = df2022['求人倍率'].values model2 = sm.OLS(y_kyu, X_reg2).fit() print(f"\n=== PC → 求人倍率 R2 = {model2.rsquared:.4f} ===") |
=== 重回帰分析結果(PC1, PC2 → 消費支出)===
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 0.347
Model: OLS Adj. R-squared: 0.317
Method: Least Squares F-statistic: 11.67
Date: Mon, 18 May 2026 Prob (F-statistic): 8.60e-05
Time: 11:23:31 Log-Likelihood: -519.70
No. Observations: 47 AIC: 1045.
Df Residuals: 44 BIC: 1051.
Df Model: 2
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 2.896e+05 2313.213 125.207 0.000 2.85e+05 2.94e+05
x1 5795.3801 1312.514 4.415 0.000 3150.181 8440.579
x2 -5129.1352 2618.064 -1.959 0.056 -1.04e+04 147.226
==============================================================================
Omnibus: 1.775 Durbin-Watson: 1.849
Prob(Omnibus): 0.412 Jarque-Bera (JB): 1.039
Skew: -0.338 Prob(JB): 0.595
Kurtosis: 3.272 Cond. No. 1.99
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
=== 標準化偏回帰係数 ===
beta_PC1 = 0.5381 (p=0.0001)
beta_PC2 = -0.2388 (p=0.0565)
R2 = 0.3465, R2adj = 0.3168
F = 11.6673, p(F) = 0.0001
=== PC → 求人倍率 R2 = 0.2196 ===sm.add_constant(X) — 切片項(定数1の列)を先頭に追加。statsmodelsで必須。sm.OLS(y, X).fit() — 最小二乗法でモデルを推定。model.params, model.pvalues, model.conf_int() で結果取得。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。本研究では SSDSE-B(都道府県別統計・2022年断面)を用い、地域の知識産業集積と経済水準(消費支出)の関係を分析した。主な知見を以下に要約する。
| 項目 | 結果 | 意義 |
|---|---|---|
| PCA 第1主成分 | 説明分散比 62.1% | 5変数の情報を1指標に集約。「知識経済指数」として活用可能 |
| 負荷量(PC1) | 大学進学率・転入率・大学学生割合・教育費が正、高校等数/万人が負 | 都市型知識集積vs地方型を分離する軸 |
| Ward法クラスタ | k=4(超集積・高集積・中核・過疎型) | 政策立案に資する地域類型化 |
| 重回帰(PC1→消費支出) | β=+0.538, p<0.001, R²=0.347 | 知識経済集積が消費水準と有意に正相関 |
使用データ:SSDSE-B-2026(政府統計の総合窓口 e-Stat 公開データ)。分析対象:47都道府県・2022年断面(n=47)。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。