この教材は原論文と同じデータを読み込み、同じ手順で計算し直しています。画面に出る数値と図は、あなたのブラウザがその場で計算した結果です。
| 原論文が使ったデータ | SSDSE-E・jSTAT MAP・指定緊急避難場所一覧表 分析単位:その他 中核手法:統計GIS・相関分析 |
|---|---|
| この教材が使うデータ |
|
| 原論文(PDF) | 南海トラフ地震に備えて ~指定避難所に3人に1人が避難できず、災害時の医療体制は本当に十分か?~ 優秀賞/ |
原論文と同じ粒度のデータは、この教材にも同梱しています。これを読み込めば、原論文と同じ細かさで分析をやり直せます(下の「🐍 ブラウザで動かす」でコードを書き換えて試せます)。ただし原論文が使った項目がすべて収録されているとは限りません。足りない項目は、上の「できないこと」に書いた出典から取ってくる必要があります。
▶ ここに書いてある分析は、ページ下部の「🐍 ブラウザで動かす」でそのまま実行できます(インストール不要)。動かしているのは code/2019_H2_yushu.py(245 行)そのものです。
このページの再現分析(図1・図2の全国比較)を自分で動かすには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
※ 原論文の分析のうち、SSDSEを使う全国比較(図1・図2)は実データで再現できます。一方、jSTAT MAP(統計GIS)上で行われた松山南高校半径3km圏の地図分析(原論文 図3〜図12・表1)は対話的な地図操作にもとづくため、スクリプトでは再計算できません。該当部分の数値は原論文の報告値として本文の表と図3・図4に示します(詳細は「データと再現範囲」参照)。
政府地震調査研究推進本部によると、30年以内に南海トラフ地震が起きる確率は70〜80%と予想されている(原論文執筆当時)。 愛媛県が発表した松山市の被害想定では、最大で震度7の揺れとなり、火災での焼失をあわせると建物全壊棟数は3万5千棟を超え、死者数715人、負傷者数5,707人になると想定されている(改訂版まつやま防災マップ)。
自然災害は避けることができないうえ、ある日突然発生する。しかし、日頃から防災対策をし、避難所の確保や負傷者の救護を迅速に行うことができれば、被害を最小限に抑えられるのではないか。 そこで著者らは、避難所と災害時の医療体制の現状と問題点を統計データで明らかにし、改善策を提案することを目指した。
SSDSE(教育用標準データセット) jSTAT MAP(統計GIS) 徒歩10分到達圏(バッファ分析) 収容力ギャップ分析
| データ・資料 | 用途 |
|---|---|
| SSDSE(教育用標準データセット) 独立行政法人統計センター | 各都道府県庁所在市の「避難所1か所当たりの人数」「人口1万人あたりの医師数」の計算(図1・図2) |
| jSTAT MAP(地図で見る統計GIS) e-Stat 政府統計の総合窓口 | 松山南高校を中心とした半径3km圏への指定避難所・5診療科のプロット、圏内人口の集計、徒歩10分到達圏の作図(図3〜図12) |
| 改訂版まつやま防災マップ・指定緊急避難場所一覧表 松山市ホームページ | 被害想定、指定避難所の場所・収容可能人数・給食施設の有無 |
| 不動産の表示に関する公正競争規約施行規則 | 「徒歩1分=80m」という到達圏の基準(徒歩10分=800m) |
| 指標 | 計算方法(原論文 2節) |
|---|---|
| 避難所1か所当たりの人数 | 総人口 ÷ 避難所数。避難所=小学校+中学校+高等学校+公民館とみなす(SSDSEから計算) |
| 人口1万人あたりの医師数 | 医師数 ÷ 総人口 × 10000 |
| 収容率(本ページでの呼び方) | 合計収容可能人数 ÷ 圏内人口総数 × 100(原論文 表1 の計算:142,164÷207,828×100≒68.40%) |
まずSSDSEを使い、各都道府県庁所在市(東京は23区を合算)について「避難所1か所当たりの人数」と「人口1万人あたりの医師数」を計算し、松山市を全国の中に位置づける。 原論文の図1・図2は47市を横に並べた棒グラフで、本ページでは同じ指標をランキング形式の横棒グラフとして SSDSE-A-2025 の実データから再計算した。
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | import os import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt plt.rcParams['font.family'] = 'Hiragino Sans' plt.rcParams['axes.unicode_minus'] = False plt.rcParams['figure.dpi'] = 150 FIG_DIR = 'html/figures' DATA_A = 'data/raw/SSDSE-A-2025.csv' os.makedirs(FIG_DIR, exist_ok=True) # ── データ読み込み(SSDSE-A:市区町村データ) ────────────────── # 1行目=項目コード、2行目=年度、3行目=日本語の項目名。コード行をヘッダーに使う df_a = pd.read_csv(DATA_A, encoding='cp932', header=0, skiprows=[1, 2]) df_a = df_a.rename(columns={ 'SSDSE-A-2025': '地域コード', 'Prefecture': '都道府県', 'Municipality': '市区町村', 'A1101': '総人口', 'E2101': '小学校数', 'E3101': '中学校数', 'E4101': '高等学校数', 'G1201': '公民館数', 'I6100': '医師数', }) cols = ['総人口', '小学校数', '中学校数', '高等学校数', '公民館数', '医師数'] df_a[cols] = df_a[cols].apply(pd.to_numeric, errors='coerce') |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。pd.read_csv(..., encoding='cp932', skiprows=[1, 2]) — SSDSEはShift_JIS系(cp932)で、先頭3行がコード・年度・項目名の3段ヘッダー。コード行だけをヘッダーに残して読む。rename(columns={...}) — 項目コード(A1101など)を日本語名に付け替えて、以降のコードを読みやすくする。apply(pd.to_numeric, errors='coerce') — 数値化できないセル('-'など)をNaNに変換。集計前の定番処理。69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | # ── 都道府県庁所在市の抽出(東京は原論文にならい23区を合算) ────── capitals = { '北海道': '札幌市', '青森県': '青森市', '岩手県': '盛岡市', '宮城県': '仙台市', '秋田県': '秋田市', '山形県': '山形市', '福島県': '福島市', '茨城県': '水戸市', '栃木県': '宇都宮市', '群馬県': '前橋市', '埼玉県': 'さいたま市', '千葉県': '千葉市', '神奈川県': '横浜市', '新潟県': '新潟市', '富山県': '富山市', '石川県': '金沢市', '福井県': '福井市', '山梨県': '甲府市', '長野県': '長野市', '岐阜県': '岐阜市', '静岡県': '静岡市', '愛知県': '名古屋市', '三重県': '津市', '滋賀県': '大津市', '京都府': '京都市', '大阪府': '大阪市', '兵庫県': '神戸市', '奈良県': '奈良市', '和歌山県': '和歌山市', '鳥取県': '鳥取市', '島根県': '松江市', '岡山県': '岡山市', '広島県': '広島市', '山口県': '山口市', '徳島県': '徳島市', '香川県': '高松市', '愛媛県': '松山市', '高知県': '高知市', '福岡県': '福岡市', '佐賀県': '佐賀市', '長崎県': '長崎市', '熊本県': '熊本市', '大分県': '大分市', '宮崎県': '宮崎市', '鹿児島県': '鹿児島市', '沖縄県': '那覇市', } rows = [] for pref, city in capitals.items(): rows.append(df_a[(df_a['都道府県'] == pref) & (df_a['市区町村'] == city)][cols].iloc[0]) df_cap = pd.DataFrame(rows) df_cap.insert(0, '市', list(capitals.values())) # 東京23区(地域コード R13101〜R13123)を合算して1行にする wards23 = df_a[df_a['地域コード'].astype(str).str.match(r'R131[0-2]\d')] tokyo = wards23[cols].sum() tokyo['市'] = '東京23区' df_cap = pd.concat([df_cap, tokyo.to_frame().T], ignore_index=True) df_cap[cols] = df_cap[cols].apply(pd.to_numeric) print(f'都道府県庁所在市 {len(df_cap)} 市(東京23区を含む)') print(f'東京23区の合算人口: {int(tokyo["総人口"]):,} 人') |
都道府県庁所在市 47 市(東京23区を含む) 東京23区の合算人口: 9,733,276 人
capitals に「都道府県→県庁所在市」の対応を持たせ、1市ずつ抽出します。sum() で合算して1行を作ります。原論文の図1・図2が「東京23区」で比較しているのに合わせた処理です。str.match(r'R131[0-2]\d') のように正規表現でコード帯を指定すると、23行を列挙せずに済みます。99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | # ── 指標の計算(原論文 2節の定義どおり) ───────────────────────── # 避難所 = 小学校+中学校+高等学校+公民館 とみなす(原論文の定義) df_cap['避難所数'] = (df_cap['小学校数'] + df_cap['中学校数'] + df_cap['高等学校数'] + df_cap['公民館数']) df_cap['避難所1か所当たり人数'] = df_cap['総人口'] / df_cap['避難所数'] df_cap['人口1万人あたり医師数'] = df_cap['医師数'] / df_cap['総人口'] * 10000 mean_shelter = df_cap['避難所1か所当たり人数'].mean() mean_doctor = df_cap['人口1万人あたり医師数'].mean() m = df_cap[df_cap['市'] == '松山市'].iloc[0] print(f'\n【避難所1か所当たりの人数】47市平均: {mean_shelter:,.0f} 人') print('上位5市:') top5 = df_cap.nlargest(5, '避難所1か所当たり人数') for _, r in top5.iterrows(): print(f" {r['市']}: {r['避難所1か所当たり人数']:,.0f} 人") print(f"松山市: {m['避難所1か所当たり人数']:,.0f} 人(平均の {m['避難所1か所当たり人数']/mean_shelter:.2f} 倍)") print(f'\n【人口1万人あたりの医師数】47市平均: {mean_doctor:.1f} 人') low5 = df_cap.nsmallest(5, '人口1万人あたり医師数') print('下位5市:') for _, r in low5.iterrows(): print(f" {r['市']}: {r['人口1万人あたり医師数']:.1f} 人") print(f"松山市: {m['人口1万人あたり医師数']:.1f} 人(平均より " f"{'低い' if m['人口1万人あたり医師数'] < mean_doctor else '高い'})") |
【避難所1か所当たりの人数】47市平均: 3,472 人 上位5市: 横浜市: 6,132 人 東京23区: 5,814 人 札幌市: 5,497 人 大阪市: 5,164 人 名古屋市: 5,114 人 松山市: 3,431 人(平均の 0.99 倍) 【人口1万人あたりの医師数】47市平均: 36.5 人 下位5市: さいたま市: 21.1 人 宇都宮市: 22.8 人 山口市: 23.8 人 横浜市: 24.3 人 青森市: 24.5 人 松山市: 32.5 人(平均より 低い)
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | # ── 図1:避難所1か所当たりの人数(原論文 図1 の再現) ───────────── d1 = df_cap.sort_values('避難所1か所当たり人数', ascending=True) colors1 = ['#C62828' if c == '松山市' else ('#F57C00' if c in ('東京23区', '札幌市', '名古屋市', '大阪市', '横浜市') else '#78909C') for c in d1['市']] fig1, ax1 = plt.subplots(figsize=(9, 13)) ax1.barh(d1['市'], d1['避難所1か所当たり人数'], color=colors1, alpha=0.9, height=0.72) ax1.axvline(mean_shelter, color='#333333', linewidth=2, linestyle='--', label=f'47市平均 {mean_shelter:,.0f} 人', zorder=5) ax1.set_xlabel('避難所1か所当たりの人数(人)', fontsize=12) ax1.set_title('都道府県庁所在市別 避難所1か所当たりの人数\n' '(避難所=小学校+中学校+高等学校+公民館、SSDSE-A-2025で再計算)', fontsize=13, fontweight='bold', pad=12) ax1.tick_params(axis='y', labelsize=8.5) ax1.grid(True, axis='x', alpha=0.3) ax1.legend(loc='lower right', fontsize=10) plt.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2019_H2_fig1.png'), dpi=150, bbox_inches='tight') plt.close(fig1) print('\n図1 保存完了(避難所1か所当たりの人数)') |
図1 保存完了(避難所1か所当たりの人数)
sort_values(...) で小さい順に並べ、barh で横棒に。5大都市を橙、松山市を赤で塗り分けます。ax.axvline(平均, linestyle='--') — 平均の基準線。原論文の図1も平均線との比較で「大都市ほど多い」「松山市は平均並み」を読み取っています。
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | # ── 図2:人口1万人あたりの医師数(原論文 図2 の再現) ───────────── d2 = df_cap.sort_values('人口1万人あたり医師数', ascending=True) colors2 = ['#C62828' if c == '松山市' else ('#1565C0' if c == 'さいたま市' else '#78909C') for c in d2['市']] fig2, ax2 = plt.subplots(figsize=(9, 13)) ax2.barh(d2['市'], d2['人口1万人あたり医師数'], color=colors2, alpha=0.9, height=0.72) ax2.axvline(mean_doctor, color='#333333', linewidth=2, linestyle='--', label=f'47市平均 {mean_doctor:.1f} 人', zorder=5) ax2.set_xlabel('人口1万人あたりの医師数(人)', fontsize=12) ax2.set_title('都道府県庁所在市別 人口1万人あたりの医師数\n' '(SSDSE-A-2025で再計算。赤=松山市、青=さいたま市)', fontsize=13, fontweight='bold', pad=12) ax2.tick_params(axis='y', labelsize=8.5) ax2.grid(True, axis='x', alpha=0.3) ax2.legend(loc='lower right', fontsize=10) plt.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2019_H2_fig2.png'), dpi=150, bbox_inches='tight') plt.close(fig2) print('図2 保存完了(人口1万人あたりの医師数)') |
図2 保存完了(人口1万人あたりの医師数)
医師数の実数を比べれば、人口の多い横浜市が松山市より多いのは当たり前である。地域を公平に比べるには、総人口で割って「人口1万人あたり」に標準化する必要がある。避難所も同様に「1か所当たりの人数」に直すことで、規模の違う市を同じ物差しで比較できる。
ただし割り算の分母を何にするか(総人口?夜間人口?高齢者人口?)で結果の意味は変わる。指標を自作するときは定義式を必ず明記すること——原論文が2節で「避難所を小学校、中学校、高等学校、公民館とした」と明示しているのは良い実践である。
ここからが本研究の核心である。著者らは jSTAT MAP を用いて、松山南高校を中心とした半径3km圏の松山市指定避難所を統計GISの地図上にプロットした(原論文 図3。地図は原論文参照)。 指定避難所とは、災害により短期間の避難生活を余儀なくされた場合に、一定期間の避難生活を行う施設のことである。
統計GISで集計した圏内の人口総数と、松山市の指定緊急避難場所一覧表に記載された収容可能人数を突き合わせる。以下は原論文 表1 の報告値である。
| 項目 | 値(原論文 表1) |
|---|---|
| 人口総数(人口・jSTAT MAPで集計) | 207,828 人 |
| 合計収容可能人数(指定緊急避難場所一覧表より) | 142,164 人 |
| 指定避難所の数 | 67 か所 |
164 165 166 167 168 169 170 171 172 173 174 175 176 | # ── 図3:半径3km圏の人口と収容可能人数(原論文 表1 の報告値の可視化) ── # 以下の3つの数値は原論文 表1 の報告値(jSTAT MAP・松山市指定緊急避難場所 # 一覧表から原論文が集計したもの)。本スクリプトでの再計算ではない。 pop_3km = 207828 # 黒線内エリアの人口総数(人) capacity_3km = 142164 # 合計収容可能人数(人) shelters_3km = 67 # 指定避難所の数(か所) ratio = capacity_3km / pop_3km * 100 shortage = pop_3km - capacity_3km print(f'\n【原論文 表1 の報告値】松山南高校 半径3km圏') print(f' 人口総数 : {pop_3km:,} 人') print(f' 合計収容可能人数: {capacity_3km:,} 人(避難所 {shelters_3km} か所)') print(f' 収容率 = {capacity_3km:,} / {pop_3km:,} × 100 ≒ {ratio:.2f} %') print(f' → 約 {shortage:,} 人(およそ3人に1人)が指定避難所に避難できない') |
【原論文 表1 の報告値】松山南高校 半径3km圏 人口総数 : 207,828 人 合計収容可能人数: 142,164 人(避難所 67 か所) 収容率 = 142,164 / 207,828 × 100 ≒ 68.40 % → 約 65,664 人(およそ3人に1人)が指定避難所に避難できない
pop_3km・capacity_3km・shelters_3km は原論文 表1 の報告値(jSTAT MAPと松山市一覧表から原論文が集計)で、本スクリプトで再集計したものではありません。
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | fig3, ax3 = plt.subplots(figsize=(9, 4.6)) ax3.barh(['合計収容可能人数', '人口総数'], [capacity_3km, pop_3km], color=['#1565C0', '#78909C'], alpha=0.9, height=0.55) ax3.barh(['合計収容可能人数'], [pop_3km - capacity_3km], left=[capacity_3km], color='#C62828', alpha=0.35, height=0.55, label=f'収容できない人数 約{shortage:,}人') for y, v in zip([0, 1], [capacity_3km, pop_3km]): ax3.annotate(f'{v:,} 人', (v, y), xytext=(6, 0), textcoords='offset points', va='center', fontsize=11, fontweight='bold') ax3.annotate(f'収容率 {ratio:.1f}%\n= 3人に1人が避難できない', (capacity_3km * 0.5, 0), va='center', ha='center', fontsize=11, color='white', fontweight='bold') ax3.set_xlim(0, 235000) ax3.set_title('松山南高校 半径3km圏の人口総数と指定避難所の収容可能人数\n' '(原論文 表1 の報告値の可視化。再計算ではない)', fontsize=12.5, fontweight='bold', pad=10) ax3.set_xlabel('人数(人)', fontsize=11) ax3.grid(True, axis='x', alpha=0.3) ax3.legend(loc='lower right', fontsize=10) plt.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2019_H2_fig3.png'), dpi=150, bbox_inches='tight') plt.close(fig3) print('図3 保存完了(表1の報告値の可視化)') |
図3 保存完了(表1の報告値の可視化)
「避難所は67か所ある」だけでは十分かどうか判断できない。需要(圏内人口207,828人)と供給(収容可能人数142,164人)を同じ単位(人数)で突き合わせて初めて「約68%しか収容できない」という定量的な結論が出る。
この「需要÷供給」の考え方は、保育所の待機児童、病床の逼迫率、電力需給など、社会インフラの分析全般で使われる基本技術である。分子・分母の定義(収容可能人数は1人当たり何m²で計算されているか等)を確認する癖をつけよう。
収容力の不足に加えて「距離」の問題がある。著者らは歩く速度を分速80m(不動産の表示に関する公正競争規約施行規則の基準)とし、各指定避難所を中心に徒歩10分(=800m)で到達できるエリアを地図上に描いた(原論文 図4。地図は原論文参照)。 災害時に避難所が近くにない場合、高齢者や小さい子どもをもつ家族、けがをしている人は避難するのが大変である。
その結果、徒歩10分以内に指定避難所へ到達できないエリアが4か所見つかった。各エリアの人数(jSTAT MAPで集計した原論文の報告値)は次のとおり。
| エリア | 徒歩10分以内に指定避難所へ到達できない人数(原論文の報告値) |
|---|---|
| エリア① | 約 1,400 人 |
| エリア② | 約 7,000 人 |
| エリア③ | 約 6,000 人 |
| エリア④ | 約 4,000 人 |
| 合計 | 約 18,400 人 |
次に著者らは、災害発生時に必要不可欠な医療機関を外科・産婦人科・小児科・整形外科・内科の5科に絞り、それぞれの診療所を同じ3km圏の地図にプロットした(原論文 図5〜図10。地図は原論文参照)。読み取られた特徴は次のとおり。
| 観察 | 内容(原論文 4.2節) |
|---|---|
| 共通の立地傾向 | どの診療科も交通に便利な電車の駅付近や主要道路沿いに多く立地し、そこから離れるにつれ数が少なくなる |
| 学校の近く | 幼稚園・小中学校・高校の近くには、児童・生徒の利用頻度が高い整形外科や内科が多い |
| 内科 | 患者数の多い内科は圧倒的に数が多く、ほぼ偏りなく分布——災害時にも円滑に対応可能とみられる |
| 産婦人科・小児科 | 患者の対象が限られる科は数が少なく、分布に偏りがある。外科・整形外科も同様に不足地域が存在 |
施設の「数」が足りていても、「距離」が遠ければ使えない。GISでは、施設を中心に一定距離の円(バッファ)や移動時間の到達圏を描き、どの圏にも入らない場所=サービスの空白地帯を特定する。これをバッファ分析(到達圏分析)と呼ぶ。
本研究の優れた点は、徒歩速度に「分速80m」という公的な基準(不動産の表示に関する公正競争規約施行規則)の出典を明示したこと。分析の前提となる数値には必ず根拠を付けよう。jSTAT MAPの「リッチレポート」や「エリア作成」機能を使えば、同じ分析を誰でも無料で行える。
避難所と診療所がともに不足する4つのエリアに対し、著者らは避難所や診療所の代わりになる実在の施設を提案した(原論文 6節・図12)。 提案場所の面積を jSTAT MAP で測定し、1人当たりの避難スペースを2m²として新たに何人避難できるかを計算している。以下はいずれも原論文の報告値である。
| エリア | 提案場所 | 提案の根拠 | 救護所とする診療科 | 新たに避難可能 (報告値) |
|---|---|---|---|---|
| ① | 私立幼稚園2園+大学グラウンド | 幼稚園は自園調理の給食制度があり食事を提供できる。大学グラウンドは一時避難所で、テントを張り広大な土地を活用 | 産婦人科・外科・整形外科 | 約 30,000 人 (到達困難 約1,400人 全員) |
| ② | ショッピングセンター+認定こども園 | 自衛隊と「大規模災害時における物資の供給要請に関する協定」を締結済みで物資を迅速に届けられる。こども園には給食施設 | 小児科・産婦人科・外科 | 約 16,000 人 (到達困難 約7,000人 全員) |
| ③ | 自動車教習所+私立保育所・私立幼稚園 | 教習所は教室・ロビーに加え託児室があり幼児にも過ごしやすい。保育所・幼稚園には給食施設 | 小児科・整形外科・産婦人科・外科 | 約 6,600 人 (到達困難 約6,000人 全員) |
| ④ | 松山市総合公園+南江戸公園 | 救護用・避難民用のテントを張り、広大な土地を避難スペースや応急手当場所として活用 | 小児科・整形外科・産婦人科・外科 | 約 20,000 人 (到達困難 約4,000人 全員) |
202 203 204 205 206 207 208 209 210 211 212 213 214 215 | # ── 図4:エリア①〜④の報告値の可視化(原論文 4.1節・6節) ───────── # いずれも原論文の報告値。徒歩10分=分速80m×10分=800mの到達圏に入らない # 4つの空白エリアの人数と、提案場所の導入で新たに避難可能となる人数。 areas = ['エリア①\n(私立幼稚園2園+\n大学グラウンド)', 'エリア②\n(ショッピングセンター+\n認定こども園)', 'エリア③\n(自動車教習所+\n私立保育所・幼稚園)', 'エリア④\n(松山市総合公園+\n南江戸公園)'] unreachable = [1400, 7000, 6000, 4000] # 徒歩10分で避難所に到達できない人数 new_capacity = [30000, 16000, 6600, 20000] # 提案導入で新たに避難可能となる人数 print('\n【原論文の報告値】徒歩10分で指定避難所に到達できないエリア') for a, u, n in zip(['①', '②', '③', '④'], unreachable, new_capacity): print(f' エリア{a}: 到達困難 約{u:,}人 → 提案場所の導入で新たに約{n:,}人が避難可能') print(f' 合計 : 到達困難 約{sum(unreachable):,}人 / 新規避難可能 約{sum(new_capacity):,}人') |
【原論文の報告値】徒歩10分で指定避難所に到達できないエリア エリア①: 到達困難 約1,400人 → 提案場所の導入で新たに約30,000人が避難可能 エリア②: 到達困難 約7,000人 → 提案場所の導入で新たに約16,000人が避難可能 エリア③: 到達困難 約6,000人 → 提案場所の導入で新たに約6,600人が避難可能 エリア④: 到達困難 約4,000人 → 提案場所の導入で新たに約20,000人が避難可能 合計 : 到達困難 約18,400人 / 新規避難可能 約72,600人
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | y = np.arange(len(areas)) fig4, ax4 = plt.subplots(figsize=(10, 6.2)) ax4.barh(y + 0.21, unreachable, height=0.38, color='#C62828', alpha=0.9, label='徒歩10分以内に指定避難所へ到達できない人数') ax4.barh(y - 0.21, new_capacity, height=0.38, color='#2E7D32', alpha=0.9, label='提案場所の導入で新たに避難可能となる人数') for yi, v in zip(y + 0.21, unreachable): ax4.annotate(f'約{v:,}人', (v, yi), xytext=(5, 0), textcoords='offset points', va='center', fontsize=10) for yi, v in zip(y - 0.21, new_capacity): ax4.annotate(f'約{v:,}人', (v, yi), xytext=(5, 0), textcoords='offset points', va='center', fontsize=10) ax4.set_yticks(y) ax4.set_yticklabels(areas, fontsize=9.5) ax4.invert_yaxis() ax4.set_xlim(0, 34000) ax4.set_xlabel('人数(人)', fontsize=11) ax4.set_title('避難所空白エリア①〜④の到達困難人数と提案の効果\n' '(原論文 4.1節・6節の報告値の可視化。再計算ではない)', fontsize=12.5, fontweight='bold', pad=10) ax4.grid(True, axis='x', alpha=0.3) ax4.legend(loc='lower right', fontsize=10) plt.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2019_H2_fig4.png'), dpi=150, bbox_inches='tight') plt.close(fig4) print('図4 保存完了(エリア①〜④の報告値の可視化)') |
図4 保存完了(エリア①〜④の報告値の可視化)
barh(y+0.21, ...) と barh(y-0.21, ...) で赤(到達困難)と緑(新規収容)の2系列をエリアごとに対にして描きます。本研究が審査会で「高校生のオペレーションズリサーチ(OR)の論文としては高い水準」と評価されたのは、問題の特定(空白エリアと人数)→資源の発見(給食施設・協定・広い土地をもつ実在施設)→効果の定量化(新たに何人収容できるか)という一連の流れを閉じているからである。
「避難所を増やすべきだ」という一般論ではなく、「エリア②はこのショッピングセンターとこども園。理由は協定と給食施設。効果は約16,000人」とまで具体化して初めて、政策提言として説得力を持つ。
図1で松山市は「平均並み」だった。しかし3km圏に絞って空間分布を見ると、3人に1人が避難できず、徒歩10分圏の空白が4か所も見つかった。集計値(市全体の平均)が問題なしに見えても、内部の分布に大きな偏りが隠れていることがある。
マクロ(全国比較)で自分の街を位置づけ、ミクロ(GIS)で内部の偏りを暴く——このズームイン構造は、地域分析レポートの優れたお手本である。
| データ・資料 | 出典・説明 |
|---|---|
| SSDSE-A-2025(市区町村データ) | 独立行政法人統計センター SSDSE(教育用標準データセット)。本ページの再現分析(図1・図2)に使用。原論文は2019年当時のSSDSEを使用。 |
| jSTAT MAP(地図で見る統計GIS) | 総務省統計局・独立行政法人統計センターが提供する地理情報システム(jstatmap.e-stat.go.jp)。原論文の図3〜図12の作成に使用。無料で利用できる。 |
| 改訂版まつやま防災マップ・指定緊急避難場所一覧表 | 松山市ホームページ。被害想定と各指定避難所の収容可能人数・給食施設の有無。 |
| 徒歩1分=80m の基準 | 「不動産の表示に関する公正競争規約施行規則」第5章 表示基準 第10条(不動産公正取引協議会連合会)。 |
図1・図2は SSDSE-A-2025 の実データから計算・作図(合成データ・乱数生成なし)。 図3・図4および本文の数値(207,828人/142,164人/67か所/68.40%/エリア①〜④の人数など)は原論文の報告値であり、本ページで再計算したものではない。原論文の地図(図3〜図12)は本ページでは再現していない。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計・GISの基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本ページのスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法(GIS・到達圏分析・需給ギャップ分析)は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。
この論文を理解できたか、クリックで確認しましょう。間違えても解説が出ます。
このページの分析は、この画面の中でそのまま実行できます。
Python をインストールする必要も、CSV をダウンロードする必要もありません。
下のセルの 「▶ ブラウザで実行」 を上から順に押すか、
「▶ 最初から全部実行」 で一気に流してください。
表示されるのは、本文の図表とまったく同じ計算の結果です
(動かしているのは再現スクリプト code/2019_H2_yushu.py そのもの)。
コードは書き換えられます。「✏️ 書き換える」で数字や変数を変えて ▶ を押すと、 結果がどう変わるかをその場で確かめられます(元に戻すボタンつき)。 ページを開いた時点で裏で実行環境の準備が始まっているので、待ち時間はほとんどありません。 初回だけ実行環境の取得にインターネット接続が必要です。