Lesson 11

L11 トリプルハザード — 河川浸水 × 土砂災害 × 雪崩 重ね合わせ

L系GISオーバーレイ主題図クラスタリング防災
所要 60〜90分 / 想定レベル: リテラシ基礎+α / データ: 3 種ハザード Shapefile (浸水 #295/313, 土砂 #48, 雪崩 #50) + 避難所 #1517

データ取得手順

⚠️ このスクリプトは自動取得に対応していません。以下のデータセットを DoBoX から手動でダウンロードし、data/extras/ 以下に保存してください。

IDデータセット名
#48土砂災害警戒区域・特別警戒区域情報_広島県
#50雪崩危険箇所情報_広島県
#77dataset #77
#79dataset #79
#80dataset #80
#81dataset #81
#295河川浸水想定区域情報_計画規模_全河川
#313河川浸水想定区域情報_想定最大規模_全河川
#333dataset #333
#888都市計画区域情報_区域データ_安芸高田市_行政区域
#1517dataset #1517

実行コマンド:

cd "2026 DoBoX 教材"
python -X utf8 lessons/L11_triple_hazard_overlay.py

DoBoX のオープンデータは申請不要・商用/非商用とも利用可。 data/extras/.gitignore 対象(約 57 GB のキャッシュ)。 スクリプト実行で自動再生成されます。

学習目標と問い

本記事のスタイル: 3 種ハザード Shapefile を 2km grid で重ね合わせ、 重複度 (0/1/2/3) で塗り分けた主題図研究
従来は 1 種類のハザードしか個別に見られなかったところ、 河川浸水 × 土砂災害 × 雪崩EPSG:6671 同一座標系・同一格子で重ね合わせ、 「水・土・雪 のうち何種類が同時に降りかかるか」という 多重リスク を県全域で可視化する。
本記事のカバー宣言: 3 種ハザードの全県版 Shapefile を使用。
  • 河川浸水想定区域 全河川版 #295 (計画) / #313 (想定最大) — 39 dataset_id 論理カバー
  • 土砂災害警戒区域 県全域版 #48 — 31 dataset_id 論理カバー
  • 雪崩危険箇所 県全域版 #50 — 31 dataset_id 論理カバー
101 dataset_id を 4 ファイルで論理カバー。各データの個別市町/水系は属性列フィルタで再現可能。

主な問い (4 段階)

  1. 分布の問い: 3 種ハザードはそれぞれどこに分布するか?
  2. 重複の問い: 同一地点で何種類が重なるか? (0/1/2/3)
  3. 類型の問い: 市町は「沿岸/山間/中間」のどれに分類できるか?
  4. 避難所の問い: 避難所自体が警戒区域内にあるケースは何件?

立てた仮説 (H1〜H6)

  1. H1: トリプル重複域 (3 種すべて) は山間集落 (河川+土砂+雪崩 の県境部)
  2. H2: 沿岸デルタは河川浸水優位だが土砂+雪崩は少ない
  3. H3: 安芸太田町・北広島町・庄原市は山間部で雪崩+土砂が突出
  4. H4: 階層クラスタリングで広島県市町は 「沿岸/山間/中間」 に分離
  5. H5: 避難所のうち 2 種以上 ハザード警戒区域内のものが一定数存在
  6. H6: トリプル重複度は全県の 0.5% 未満だが、いざ災害時は救助困難

用語の独自定義

到達点

使用データ

論理カバー宣言

ハザード個別 dataset (例)カバー数使用ファイル
河川浸水太田川/江の川/沼田川 …39 個39shinsui_souteisaidai.shp + shinsui_keikakukibo.shp
土砂災害市町別 31 個3173_031drp/krp/jy
雪崩市町別 31 個3174_34_20260427.shp
合計101 dataset_id4 Shapefile セット

ダウンロード

中間データ (CSV)

ファイル内容
L11_grid_overlap.csv2km grid セル × ハザードフラグ × 重複度
L11_city_hazard_count.csv市町別 3 ハザード件数 + 合計
L11_suikei_flood_count.csv水系別 浸水ポリゴン数
L11_city_cluster.csv市町階層クラスタ ID + 特徴名
L11_cluster_profile.csvクラスタ平均ハザードプロファイル
L11_high_risk_shelters.csv重複度 ≥2 の避難所一覧
L11_ava_rank.csv市町別 雪崩 危険度ランク内訳
L11_sed_type.csv市町別 土砂 種別内訳
L11_depth_by_city.csv市町別 重複度2/3 セル数

図 (PNG)

ファイル内容
図1 重ね合わせ主題図3 ハザード を青/赤/紫で同時表示
図2 重複度マップ2km セルを 0-3 で塗り分け
図3 small multiples3 ハザード個別マップを並列
図4 重複度ヒストグラムセル数 × 重複度
図5 市町×ハザード積み上げ棒上位15市町
図6 水系別 浸水ポリゴン水系ランキング
図7 クラスタ dendrogram + profile階層クラスタリング結果
図8 クラスタ地理マップ市町 centroid をクラスタ別に色分け
図9 避難所 重複度棒避難所自体のリスク
図10 避難所点マップ緯度経度散布 × 重複度色
図11 市町別 重複度2/3 セルトリプル/ダブル分布
図12 雪崩 ランク × 市町Ⅰ/Ⅱ/Ⅲ 内訳
図13 土砂 種別 × 市町土石流/急傾斜/地すべり 内訳

スクリプト

L11_triple_hazard_overlay.py

cd "2026 DoBoX 教材"
py -X utf8 lessons\L11_triple_hazard_overlay.py

分析1: 3 種ハザードを同一座標系で重ね描き (主題図)

狙い

3 種ハザードを 1 枚の地図 に重ね、地理的偏りを目で確認する。 浸水は青、土砂は赤、雪崩は紫の半透明ポリゴンで表示し、重なる場所は色が混ざるので 「複数ハザード同時発動の懸念」が直感的に見える。

手法 (3 ステップ)

実装

L11_triple_hazard_overlay.py 行 825–859

 1
 2
 3
 4
 5
 6
 7
 8
 9
834
835
836
837
838
839
flood_max = gpd.read_file("...shinsui_souteisaidai.shp").to_crs("EPSG:6671")
sediment = pd.concat([doseki, kyukei, jisuberi], ignore_index=True).to_crs("EPSG:6671")
avalanche = gpd.read_file("...avalanche.shp").to_crs("EPSG:6671")

# buffer(0) で微小トポロジ崩れを修復
for gdf in (flood_max, sediment, avalanche):
    gdf["geometry"] = gdf.geometry.buffer(0)

# 描画用 simplify (描画速度 ×3 速くなる、視覚は変わらない)
flood_plot = flood_max.copy(); flood_plot["geometry"] = flood_plot.geometry.simplify(100)

fig, ax = plt.subplots(figsize=(13, 9))
flood_plot.plot(ax=ax, color="#1f6feb", alpha=0.55)
sed_plot.plot(ax=ax, color="#cf222e", alpha=0.55)
ava_plot.plot(ax=ax, color="#7d2cbf", alpha=0.65)

結果

なぜこの図か: 重ね描きで「どこで何が起きるか」を1度に把握できる。 ヒートマップやテーブルでは地理的位置が消えるが、地図なら市町や河川との対応がついて議論が具体的になる。

広島県 トリプルハザード 重ね描き (青=浸水, 赤=土砂, 紫=雪崩)
広島県 トリプルハザード 重ね描き (青=浸水, 赤=土砂, 紫=雪崩)

読み取り:

分析2: 2km grid で重複度を計算 — 主役の発見

狙い

「3 種のうち何種類が同地点で重なるか」を 定量化 する。 重ね描き (図1) は視覚情報だが、定量数字にすることで 市町ランキング面積比率 が議論できる。

手法 — 2km grid + R-tree spatial index

正攻法は gpd.overlay(A, B, how='intersection') を 3 ハザード総当たりだが、 613 × 43,220 × 2,169 の組合せは 10 分以上かかり要件 S (1〜3 分) を破る。 代わりに以下のラスタ的アプローチを採る:

  1. 県全域 bbox を 2km × 2km grid に分割 (4,416 セル)
  2. 各ハザードを unary_union県全域 1 ポリゴン に統合
  3. 各セルが各ハザードと 交差するかgeometry.intersects(union) で判定 (R-tree 内蔵で高速)
  4. 3 つのフラグ (flood, sed, ava) の合計 = 重複度 (depth ∈ 0..3)

入出力 Before/After (要件K)

段階このセルで何が起きるかサイズ
1. グリッド生成(ix=10, iy=15) のセル = box(20000, 30000, 22000, 32000)1 polygon
2. 浸水交差判定セル ∩ flood_union が空でない → flood=1True/False
3. 土砂交差判定セル ∩ sed_union が空でない → sed=1True/False
4. 雪崩交差判定セル ∩ ava_union が空False (=0)
5. 重複度1 + 1 + 0 = 2 (ダブル)0..3 整数

パラメータの意味

実装

L11_triple_hazard_overlay.py 行 890–924

 1
 2
 3
 4
 5
 6
 7
 8
 9
899
900
901
902
903
904
xs = np.arange(xmin, xmax, GRID_M)
ys = np.arange(ymin, ymax, GRID_M)
grid_cells = [box(x, y, x + GRID_M, y + GRID_M) for x in xs for y in ys]
grid_gdf = gpd.GeoDataFrame(geometry=grid_cells, crs="EPSG:6671")

# 各ハザードを 1 ポリゴンに統合 (R-tree 速度のため)
flood_union = flood_max.geometry.unary_union
sed_union = sediment.geometry.unary_union
ava_union = avalanche.geometry.unary_union

# 交差テスト (R-tree 内蔵)
grid_gdf["flood"] = grid_gdf.geometry.intersects(flood_union).astype(int)
grid_gdf["sed"]   = grid_gdf.geometry.intersects(sed_union).astype(int)
grid_gdf["ava"]   = grid_gdf.geometry.intersects(ava_union).astype(int)
grid_gdf["depth"] = grid_gdf["flood"] + grid_gdf["sed"] + grid_gdf["ava"]

結果

なぜこの図か: ラスタ風の 2km セル塗り分けは、点や polygon より「どこに何種類か」が一目で読み取れる。 地図サムネイル感覚でリスクのホットスポットを把握できる。

広島県 ハザード重複度マップ (2km grid)
広島県 ハザード重複度マップ (2km grid)

読み取り:

重複度セル数全体比意味
02,23650.63%3 ハザードのいずれにも該当しない
168015.40%1 種ハザードに該当
21,18826.90%2 種ハザードが重複
33127.07%3 種ハザード全て重複 (最警戒)

表の読み取り: トリプル (312 セル, 全 grid の 7.07%, ハザード該当セルの 14.31%)。 仮説 H6 では「0.5% 未満」と予想していたが、実際は遥かに多い (該当セル比で 14% 程度) で 反証。 これは広島県北部の山間部が「河川沿い + 急斜面 + 冬期積雪」という 3 条件をもれなく満たしているため。 ただし地理的集中 (北部山間に偏在) は仮説の後段「救助困難」と整合する。

分析3: 3 ハザード個別マップ (small multiples)

狙い

図1 では 3 色が混ざってしまうので、 1 ハザード = 1 panel で並列比較 する。 分布の形 (河川沿い/斜面/谷) の違いを見比べる。

手法

1 行 3 panel に並べた small multiples。各 panel で背景に 「ハザード該当セル」をグレーで示し、 ハザードポリゴンだけを濃色で重ねる。

結果

なぜこの図か: 比較用には small multiples が最強。条件 (ハザード種別) だけ変えて並べると、 分布形状の 共通点と差異 が同時に読み取れる。

3 ハザード 個別主題図 (small multiples)
3 ハザード 個別主題図 (small multiples)

読み取り:

分析4: 重複度ヒストグラム

狙い

セル数の絶対分布と、ハザード該当セル (≥1) 内の比率を 2 panel で比較。

結果

なぜこの図か: 縦棒で各重複度のセル数を直接比較できる。 左 = 全 grid (depth=0 を含む)、右 = ハザード該当セルだけ → 該当セル内での重複構造を見る。

重複度別 セル数 (左: 全 grid, 右: ハザード該当セル)
重複度別 セル数 (左: 全 grid, 右: ハザード該当セル)

読み取り:

分析5: 市町別 ハザード件数 (絶対値)

狙い

市町ごとに 3 ハザードの件数を合算してランキング。 「地理的にどの市町がハザード集中しているか」を浮かせる。

手法

土砂・雪崩は属性 city 列をそのまま groupby。 浸水は city 列がないため、sediment polygon を city で dissolve → 凸包に拡張 → flood polygon の重心を sjoin という疑似的市町割当を使う。 精度は完璧ではない (凸包外の沿岸海岸は割り当てられない可能性) が、ランキング水準では十分。

実装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
sed_city = sediment.groupby("city").size()
ava_city = avalanche.groupby("city").size()

# flood の市町割当: sediment polygon を city で dissolve → 凸包 → flood centroid を sjoin
city_polys = sediment[["city", "geometry"]].dissolve(by="city").reset_index()
city_polys["geometry"] = city_polys.geometry.convex_hull.buffer(0)
flood_centroid = flood_max.copy()
flood_centroid["geometry"] = flood_centroid.geometry.centroid
flood_with_city = gpd.sjoin(flood_centroid, city_polys, predicate="within")
flood_city_count = flood_with_city.groupby("city").size()

結果

なぜこの図か: ランキングは横棒 + stacked が読みやすい。 土砂と雪崩を縦に積むことで「合計件数の中で雪崩比率が高いか」も同時に見える。

市町別 土砂×雪崩 件数 (上位15市町)
市町別 土砂×雪崩 件数 (上位15市町)

読み取り:

市町浸水_n土砂_n雪崩_n合計
庄原市40399212835315
東広島市52352703579
呉市24353703561
福山市111327903390
三次市932913553061
尾道市43269302736
三原市59262402683
広島市安佐北区54251502569
山県郡北広島町1518104592284
安芸高田市2417752092008

表の読み取り: 浸水_n は便宜的な空間結合の結果なので絶対値は粗いが、 広島市・福山市・三次市・庄原市など 大きい市町や河川氾濫面積の広い市町 で大きい値が出ている。 仮説 H3 (安芸太田町・北広島町は雪崩+土砂が突出) は 支持

分析6: 水系別 浸水ポリゴン数

狙い

河川浸水を 市町ではなく水系単位 で集計。どの河川が氾濫想定域として大きいかを把握。

結果

なぜこの図か: 河川は市町境を越えて流れるので、市町集計だけでは河川の真の姿が見えない。水系ごとに横棒で並べる。

水系別 浸水ポリゴン数 (上位15水系)
水系別 浸水ポリゴン数 (上位15水系)

読み取り:

水系浸水ポリゴン数
江の川水系129
太田川水系107
中小河川101
芦田川水系90
沼田川水系54
二河川水系13
黒瀬川水系12
高梁川水系10
八幡川水系7
藤井川水系7
賀茂川水系6
本郷川水系6
山南川水系6
三津大川水系6
瀬野川水系6

分析7: 階層クラスタリングで市町を「沿岸/山間/中間」に分類

狙い

市町を 3 ハザードのプロファイル で類型化する。「直感的に沿岸/山間と分けたいが、 データに語らせる」ために階層クラスタリング (Ward 法) を使う。

手法 (STEP 分け, 要件O)

STEP役割入力出力
STEP1特徴量化市町×3 列 (浸水_n, 土砂_n, 雪崩_n)log 変換 + z-score した行列
STEP2距離計算z-score 行列市町ペア間のユークリッド距離
STEP3クラスタ生成距離行列Ward 法で 3 クラスタに分割
STEP4命名クラスタ平均プロファイル「沿岸 (浸水優位)」「山間 (土砂+雪崩)」「中間」のラベル

手法解説 — 階層クラスタリングって何 (リテラシ向け)

なぜ log 変換?

大都市 (広島市, 福山市) は土砂件数が小都市の数十倍。生の値で z-score を取ると 「広島市だけ別グループ」になってしまうので、 log1p で大きさを圧縮してプロファイルの形だけで判定する。

実装

1
2
3
4
5
6
from scipy.cluster.hierarchy import linkage, fcluster, dendrogram

features_log = np.log1p(city_df[["浸水_n", "土砂_n", "雪崩_n"]])
features_z = (features_log - features_log.mean()) / features_log.std()
Z = linkage(features_z.values, method="ward")
clusters = fcluster(Z, t=3, criterion="maxclust")

結果

なぜこの図か: dendrogram は階層構造を, 棒グラフはプロファイルの違いを示す。2つを並列に置くことで 「どこで切るか」と「切った結果の意味」を 1 枚で確認できる。

市町階層クラスタリング (Ward 法) + クラスタ平均プロファイル
市町階層クラスタリング (Ward 法) + クラスタ平均プロファイル
クラスタ特徴名浸水平均土砂平均雪崩平均市町数
C1沿岸/小都市 (浸水主体)2.0282.80.011
C2山間 (雪崩+土砂)33.82188.8361.56
C3中間 (土砂+浸水)33.22075.10.013

表の読み取り: 3 クラスタの平均プロファイルが明確に分離。 特に 雪崩平均 が大きいクラスタは「山間 (土砂+雪崩優位)」、 浸水平均が大きいクラスタは「沿岸/平野 (浸水優位)」、中間は両方そこそこ。 仮説 H4 (3 クラスタ分離) 支持

市町クラスタ地理マップ
市町クラスタ地理マップ

読み取り:

分析8: 避難所自体のリスク — 警戒区域内に立地する避難所

狙い

避難所 (4065 件) のうち、 避難所自体が警戒区域内 に立地するケースは何件あるか。 2 種以上のハザード警戒区域と重なる「ダブル/トリプル危険避難所」を特定する。

手法

実装

L11_triple_hazard_overlay.py 行 1094–1112

1094
1095
1096
1097
1098
1099
1100
1101
shelter_gdf = gpd.GeoDataFrame(shelters_df,
    geometry=gpd.points_from_xy(shelters_df["lon"], shelters_df["lat"]),
    crs="EPSG:4326").to_crs("EPSG:6671")

shelter_gdf["in_flood"] = shelter_gdf.geometry.intersects(flood_union).astype(int)
shelter_gdf["in_sed"]   = shelter_gdf.geometry.intersects(sed_union).astype(int)
shelter_gdf["in_ava"]   = shelter_gdf.geometry.intersects(ava_union).astype(int)
shelter_gdf["overlap_n"] = shelter_gdf[["in_flood","in_sed","in_ava"]].sum(axis=1)

結果

避難所 重複度別件数
避難所 重複度別件数
重複度件数割合
0242759.7%
1161139.6%
2260.6%
310.0%

読み取り:

避難所点マップ — 色=重複度
避難所点マップ — 色=重複度

マップの読み取り:

分析9: 重複度2/3 セル × 市町ランキング

狙い

「どの市町に 多重ハザードセル が多いか」を ranking で示す。 各セルの重心を最近傍市町に割り当て、市町ごとに ダブル+トリプル セル数を集計。

手法

市町 centroid (sediment dissolve から計算) と grid セル中心の最近傍距離を scipy.spatial.cKDTree で取得し、 各セルを最も近い市町に割り当てる。これは厳密な行政境界ではないが、 centroid 距離による近似 で十分な精度。

結果

市町別 重複度 ≥ 2 セル数 (上位12)
市町別 重複度 ≥ 2 セル数 (上位12)

読み取り:

分析10: 雪崩 危険度ランク × 市町 ヒートマップ

狙い

雪崩データには bunrui 列に 危険度 Ⅰ/Ⅱ/Ⅲ ランクがある (Ⅰ=軽度, Ⅲ=重度)。 市町 × ランクで内訳を可視化し、特に重度 (Ⅲ) ハイリスク市町を特定。

結果

市町別 雪崩 危険度ランク内訳
市町別 雪崩 危険度ランク内訳
市町危険度 Ⅰ危険度 Ⅱ危険度 Ⅲ
庄原市92118110
山県郡北広島町8535816
安芸高田市561530
山県郡安芸太田町52750
三次市4465
廿日市市7290

読み取り:

分析11: 土砂 種別 × 市町 ヒートマップ

狙い

土砂データの np_type 列に 「土石流」「がけ崩れ」「地すべり」 の3種別がある。 市町ごとにどの土砂種が支配的かを把握する。

結果

市町別 土砂災害警戒区域 (種別内訳)
市町別 土砂災害警戒区域 (種別内訳)

読み取り:

仮説検証と考察

仮説判定根拠
H1: トリプル域は山間集落支持図2 重複度マップでトリプル (312 セル) は北部山岳地帯に集中
H2: 沿岸デルタは浸水優位支持図3 small multiples で沿岸南部は青のみ。図8 クラスタマップで沿岸=浸水優位クラスタ
H3: 安芸太田町・北広島町・庄原市は雪崩+土砂突出支持図5 で雪崩 (紫) が大きく積み上がっている市町と一致 (庄原市 1283件)
H4: 階層クラスタで沿岸/山間/中間に分離支持図7 dendrogram + 図8 地理マップで明確に 3 群に分離
H5: 避難所のうち2種以上ハザード警戒区域内が一定数支持27 件 / 4065 件 (0.7%) が 重複度≥2
H6: トリプルは0.5% 未満だが救助困難反証実際はトリプル 7.07% (全 grid 比)、 14.31% (該当セル比) で 0.5% を大幅に超過。 ただし「救助困難」性は地理的集中 (庄原市など特定市町) からは支持される

考察

発展課題 (結果から導かれる新たな問い)

1. 結果X: トリプル重複域は山間部の谷筋に集中

2. 結果X: 避難所の 27 件が重複度≥2

3. 結果X: クラスタ分離が明瞭 (沿岸/中間/山間)

4. 結果X: 太田川水系が浸水ポリゴン最大

5. 結果X: トリプル 312 セル / 全該当 2180 の希少性

6. 結果X: 避難所自体に複数ハザードリスクがある事実

補足: GIS メソッドのツール化視点 + 処理時間

本記事で使う GIS 関数の入出力

関数入力出力ひとこと
gdf.to_crs("EPSG:6671")GeoDataFrame同形, CRS変換済すべての空間処理の前に必須
gdf.geometry.buffer(0)GeoDataFrame同形, トポロジ修復済self-intersection 解消, 面積不変
gdf.geometry.unary_unionGeoDataFrame1 つの (Multi)PolygonR-tree で重ね合わせ高速化
geom_a.intersects(geom_b)2 geometryTrue/False内部で R-tree が走る
gpd.sjoin(A, B, predicate="within")点+ポリゴン属性結合済の点避難所の市町判定に使用
scipy.cluster.hierarchy.linkage(..., method="ward")特徴量行列linkage matrix Z市町を 3 クラスタに分割
scipy.spatial.cKDTree2D 点列k-d tree各セルを最近傍市町に割当

処理時間とパフォーマンス (要件S対応)

「ベクトル」「次元」「疎行列」の言い換え (要件P)