Lesson 50

道路規制情報 2 件統合分析 — 本日の規制 / 今後の規制から運用構造を読み解く

L50道路規制JSONGeoDataFrame包含関係災害規制西日本豪雨Format A
所要 35 分 / 想定レベル: 中級 / データ: DoBoX dataset 1257 (本日, JSON 165KB) + 1258 (今後, JSON 234KB)

データ取得手順

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

IDデータセット名
#111dataset #111
#222dataset #222
#333dataset #333
#444dataset #444
#666dataset #666
#888都市計画区域情報_区域データ_安芸高田市_行政区域
#999dataset #999
#1257道路規制情報_本日の規制
#1258道路規制情報_今後の規制

実行コマンド:

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

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

スクリプト(全体ソースコード)

⬇ L50_road_restrictions.py

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

学習目標と問い

本記事は DoBoX のシリーズ 「道路規制情報」 2 dataset (id = 1257 本日の規制 / 1258 今後の規制) を 統合し、 広島県内の道路規制の制度的・地理的・時間的構造を 1 記事で深掘り分析する。 2026-05-09 21:20:03 取得スナップショットで、 1257 = 69 件、 1258 = 149 件

本データの位置付け — 「道路規制」 とは

道路規制情報は広島県・国土交通省 (中国地方整備局) が管理する 道路で現在実施中 (1257) または今後計画されている (1258) 通行規制を リアルタイムで公開するオープンデータ。L02 (道路カメラ) や L09 (避難所最近傍カメラ) が扱う 静的なインフラ施設とは異なり、本記事は動的なイベントとして 道路を捉える。各レコードは32 列の属性 + 緯度経度 + LineString 区間ジオメトリを持つ。

2 dataset の構造的差別 — 「本日」 と「今後」 の時間スコープ

1257 (本日) と 1258 (今後) は同じ運用システムから派生する 2 ビュー:

このため、両 dataset の id 集合は95.7% 重複 (66/69)。 1258 のみに含まれる 83 件は本日まだ開始していない将来規制で、 1257 のみに含まれる 3 件は本日中に終了する短期規制。

研究の問い (主 RQ)

広島県の道路規制情報 2 dataset (本日 + 今後) は 規制種別・路線種別・規制理由・地理分布・時間軸でどう構成され、 災害起因の長期規制と工事起因の計画規制はどう分布するか? さらに「本日」 と「今後」 の時間スコープの違いから、 県と国交省の道路運用思想の差はどう読み取れるか?

仮説 H1〜H6

本記事の独自用語定義

到達点

2 dataset の構造を 6 つの仮説で照合し、道路規制という動的データセットが 広島県の道路インフラ運用思想を映す研究的ツールであることを示す。 特に 2018 西日本豪雨の 8 年継続規制1257 ⊂ 1258 包含構造という、データ解析でしか発見できない 2 つの構造的事実を 独自に同定する。

使用データ

本記事は DoBoX シリーズの 2 件 を扱う:

項目 1257 本日の規制 1258 今後の規制
dataset_id 1257 1258
DoBoX URL https://hiroshima-dobox.jp/datasets/1257 https://hiroshima-dobox.jp/datasets/1258
形式 JSON JSON
ファイルサイズ 161 KB 229 KB
レコード数 69 149
属性列数 (results 内 dict) 32 32
緯度経度有り 69 149
kukanroot (LineString) 有り 67 66
災害規制 (kisei_type=disaster) 7 7
管轄市町数 20 25
更新頻度 リアルタイム リアルタイム
取得スナップショット 2026-05-09 21:20:03 2026-05-09 21:20:03
ライセンス CC-BY 4.0 CC-BY 4.0

列構成 (results 内 dict, 32 列)

ダウンロード

DoBoX 本体 (2 件)

更新頻度はリアルタイム (~ 数分単位)。本記事は2026-05-09 21:20:03取得スナップショットを扱う。本記事の .py スクリプトを実行すると、現時点のスナップショットを自動取得して再分析する (= 結果が日々変動)。

整形済 CSV / 中間データ

図 PNG (9 枚)

再現スクリプト

再現コマンド

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

初回実行時に DoBoX から 2 件の JSON を自動 DL (data/extras/L50_road_restrictions/)。2 度目以降は既存ファイルを使うが、最新スナップショットを再取得したい場合は data/extras/L50_road_restrictions/*.json を削除してから実行。本記事の結果数値は取得日 (2026-05-09) のスナップショットに基づく。

【分析 1】 規制種別 + 路線種別構造 — 5 種別 × 8 種路線のクロス

狙い (分析 1: 規制種別 + 路線種別構造)

2 dataset の主軸は規制種別 (5 値) × 路線種別 (8 値) のクロス集計。 本セクションは H1 (one_side 支配) と H2 (国道 vs 県道の管轄分離) を検証する。 分析の論理鎖は次の通り:

  1. 5 規制種別の件数を 1257/1258 で並列に集計 → どの種別が最頻か (H1)
  2. 路線名 (rosenname) を 8 路線種別 (国道/主要地方道/一般県道/市道/町道/etc) に分類
  3. 路線種別 × dataset で件数比を見る → 国土交通省管轄 vs 県管轄の差 (H2)

手法 (Counter + groupby + 路線分類正規表現)

路線名は文字列で、"国道" "主要地方道" "一般県道" 等の キーワードを正規表現で判定して 8 カテゴリに分類する関数 classify_rosen() を導入。 DoBoX の path には U+3000 (全角空白) が混入するため、実際は "一般県道 乙瀬小方線" のような表記。半角空白に正規化してから判定する。

入力: df1257 (69 行) + df1258 (149 行) の rosenname 列。
出力: rosen_class 列 (8 カテゴリ) + 集計 DataFrame。
限界: 「指定市一般市道」 のような表記は「市道」 に分類されるが、 「広島県 北部建設事務所」 が管轄する一般農道は「広域農道」 と分類されない場合がある。 全パターン網羅は困難なので主要 7 カテゴリ + 「その他/不明」 で運用する。
代替案: 管轄 (demarcation) で分類すれば管理者ベースになるが、 表記揺れが大きい (「広島県」 「土木管理課」 「市町名」 等) ため、本記事は路線種別ベースを採用。

実装コード (Counter + groupby + 路線分類)

L50_road_restrictions.py 行 1274–1378

 1
 2
 3
 4
 5
 6
 7
 8
 9
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
# 規制種別 + 路線種別の集計
import pandas as pd, json, re
from collections import Counter

# 5 規制種別 (固定順)
KISEI_ORDER = ["blocked", "one_side", "narrows", "controll_complex", "two_way"]

# 路線分類関数 (正規表現キーワード)
def classify_rosen(name):
    if not name: return "その他/不明"
    name = name.replace(" ", " ")  # 全角空白正規化
    if "国道" in name:        return "国道"
    if "主要地方道" in name:  return "主要地方道"
    if "一般県道" in name or "県道" in name: return "一般県道"
    if "町道" in name:        return "町道"
    if "市道" in name:        return "市道"
    if "広域農道" in name:    return "広域農道"
    if "高速" in name or "自動車道" in name: return "高速・自動車道"
    return "その他/不明"

# JSON → DataFrame 整形
def build_df(records, src_label):
    rows = []
    for r in records:
        rows.append({
            "src": src_label,
            "kisei_name": r.get("kisei_name"),
            "rosenname":  (r.get("rosenname") or "").replace(" ", " "),
            "rosen_class": classify_rosen(r.get("rosenname") or ""),
            "kiseireason": r.get("kiseireason") or "(空)",
            "kisei_type":  r.get("kisei_type"),
            # ... 他 28 列省略
        })
    return pd.DataFrame(rows)

j1 = json.load(open("1257_today.json", encoding="utf-8"))
j2 = json.load(open("1258_future.json", encoding="utf-8"))
df1 = build_df(j1["results"], "1257 本日")
df2 = build_df(j2["results"], "1258 今後")

# H1: 規制種別件数比
h1 = df1["kisei_name"].value_counts().reindex(KISEI_ORDER, fill_value=0)
print(h1)
# blocked=22, one_side=38, narrows=4, controll_complex=5, two_way=0
# → one_side シェア = 55%, blocked シェア = 32% → H1 部分支持

# H2: 路線種別 × dataset
h2_1 = df1["rosen_class"].value_counts()
h2_2 = df2["rosen_class"].value_counts()
print(h2_1, h2_2)

図 1: 5 規制種別 件数比較 (1257 vs 1258)

なぜこの図か: 学習者がまず「どの規制種別が支配的か」を一目で理解できるように、 横棒で 1257/1258 を並列表示。種別ごとの絶対数と比率の両方を読める。 H1 検証 (one_side 支配 + blocked 15-25%) に最適化したレイアウト。

図 1: 5 規制種別 件数比較
図 1: 5 規制種別 件数比較

この図から読み取れること:

図 4: 路線種別 件数比較 (1257 vs 1258)

なぜこの図か: 図 1 が「どの規制か」 を見せたのに対し、本図は「どの種類の道路で起こるか」を 見せる。国道 / 主要地方道 / 一般県道 / 市道 / 町道 等の 8 カテゴリを縦軸に並べ、 1257/1258 を横並べで比較。H2 (国道 vs 県道の管轄分離) の検証に最適。

図 4: 路線種別 件数比較
図 4: 路線種別 件数比較

この図から読み取れること:

表: 規制種別集計 (5 値)

規制種別 1257 本日 件数 1257 シェア% 1258 今後 件数 1258 シェア%
通行止め #cf222e 22 31.90 22 14.80
片側交互通行 #bf8700 38 55.10 70 47.00
車線規制 #0969da 4 5.80 47 31.50
その他/複合 #8250df 5 7.20 5 3.40
対面通行 #1a7f37 0 0.00 5 3.40

この表から読み取れること: 片側交互通行 (one_side) が両 dataset で最頻 (47% / 55%)、通行止 (blocked) が次点 (15% / 32%)。対面通行 (two_way) は 1258 のみで 5 件、1257 では 0 件 → 中央分離帯撤去等の特殊規制は本日中には少ない。

表: 路線種別集計 (8 値)

路線種別 管轄 1257 件数 1257 % 1258 件数 1258 %
国道 国 (国土交通省) 16 23.20 98 65.80
主要地方道 県 (建設事務所) 22 31.90 20 13.40
一般県道 県 (建設事務所) 19 27.50 18 12.10
市道 市町 6 8.70 6 4.00
町道 市町 1 1.40 2 1.30
広域農道 県・市町 0 0.00 0 0.00
高速・自動車道 国・NEXCO 0 0.00 0 0.00
その他/不明 不明 5 7.20 5 3.40

この表から読み取れること: 1258 は国道支配 (66%) で国土交通省管轄が中心、1257 は県道支配 (59%) で県管轄が中心。同じ運用システムから派生する 2 ビューが管轄ごとに異なる時間スコープを持つという設計が読める。

【分析 2】 規制理由カテゴリ + 災害規制の長期残存 — 西日本豪雨 8 年継続

狙い (分析 2: 規制理由カテゴリ + 災害規制の長期残存)

5 規制種別と 8 路線種別だけでは「なぜ規制されているか」 は見えない。 本セクションは規制理由 (kiseireason)規制タイプ (kisei_type) の 2 軸で H3 (工事 9 vs 災害 1) と H4 (西日本豪雨の長期残存) を検証する。

手法 (キーワード辞書による理由カテゴリ化)

kiseireason は自由記述で多様な表記 ('道路改良工事', '法面崩落', '路面陥没', '下水工事', 'マンション外壁落下のおそれ' 等)。これを 4 カテゴリに集約:

入力: kiseireason 文字列 + kisei_type フラグ。
出力: reason_cat 列 (4 カテゴリ)。
限界: 同じレコードが複数キーワードを持つ場合は順序判定になる (例: 「災害復旧工事」 → 災害復旧優先で判定)。
代替案: TF-IDF + クラスタリングで自動分類できるが、 N=218 と少数なので手動キーワード辞書で十分。

2018 西日本豪雨 — 災害規制の長期残存検出

kisei_type='disaster' のレコードにstart_date が 2018-07-07 のものがあれば、 それは西日本豪雨 (= 2018年7月の集中豪雨、広島県内 100名超死亡、道路被害 数千箇所) 起因。 取得日 (2026-05-09) との差で規制継続年数を計算し、 道路復旧の極めて長い時間スケールを定量化する。

実装コード

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 規制理由カテゴリ化 + 災害規制の年齢計算
from datetime import datetime

CONSTRUCTION_KW = ["工事", "改良", "修繕", "舗装", "下水", "ガス", "水道",
                    "電線", "電話", "塗装", "外壁", "維持", "交差点"]
DISASTER_KW = ["災害", "崩落", "崩壊", "陥没", "落石", "倒木", "崩土"]

def reason_class(reason, ktype):
    if ktype == "disaster":
        return "災害 (kisei_type=disaster)"
    if not reason:
        return "理由不明"
    for kw in DISASTER_KW:
        if kw in reason: return "災害復旧"
    for kw in CONSTRUCTION_KW:
        if kw in reason: return "工事"
    return "その他"

df1["reason_cat"] = df1.apply(lambda r: reason_class(r["kiseireason"], r["kisei_type"]), axis=1)

# 災害規制の年齢
TODAY = datetime(2026, 5, 9)
disaster = df1[df1["kisei_type"] == "disaster"].copy()
disaster["start_dt"] = pd.to_datetime(disaster["start_date"], errors="coerce")
disaster["age_years"] = (TODAY - disaster["start_dt"]).dt.total_seconds() / (365.25 * 86400)
disaster_2018 = disaster[disaster["start_dt"].dt.date == datetime(2018, 7, 7).date()]
print(f"2018 西日本豪雨 起因: {len(disaster_2018)} 件残存, "
      f"最長継続 = {disaster['age_years'].max():.1f} 年")

図 7: 規制理由 Top 12 (1257 vs 1258)

なぜこの図か: 自由記述の規制理由から最頻 12 種を抽出して並べ、 「工事系が支配する」 という H3 の予想を視覚化する。1257/1258 を二系統で表示し、 同じ理由でも 1258 (今後) で多く、1257 (本日) では少ない理由 = 計画系であることが読める。

図 7: 規制理由 Top 12
図 7: 規制理由 Top 12

この図から読み取れること:

図 8: 災害規制 年表 — 西日本豪雨の長期残存

なぜこの図か: H4 (2018 西日本豪雨の長期残存) を直接視覚化する。 1257 中の disaster 規制を縦軸に並べ、横軸に時間を取り、 規制開始日 (赤丸) から 取得日 (白四角) までの線で継続期間を表現。 2018-07-07 マーカーを引いて西日本豪雨との関係を明示する。

図 8: 災害規制 年表
図 8: 災害規制 年表

この図から読み取れること:

表: 規制理由カテゴリ (4 値)

理由カテゴリ 1257 件数 1258 件数 1257 % 1258 %
工事 50 129 72.50 86.60
災害復旧 8 8 11.60 5.40
災害 (kisei_type=disaster) 7 7 10.10 4.70
理由不明 2 2 2.90 1.30
その他 2 3 2.90 2.00

この表から読み取れること: 工事カテゴリが 1258 中 129 件 (86.6%) で支配。災害カテゴリ (kisei_type='disaster') は 1258 で 7 件 (4.7%)。H3 (工事 9 vs 災害 1) を支持。1257 vs 1258 で災害比率は同程度だが、災害は長期化するため1257 (本日中の規制) でも残存する。

表: 規制理由 Top 15 (1258 ベース)

順位 規制理由 1258 件数 1257 件数
1 橋梁工事 21 7
2 道路改良工事 19 19
3 修繕工事 18 1
4 下水工事 12 0
5 電線共同溝工事 10 0
6 維持工事 10 5
7 法面工事 8 8
8 水道工事 7 0
9 ガス工事 6 0
10 災害復旧工事 4 4
11 電話工事 3 0
12 路面陥没 3 3
13 法面崩落 3 3
14 (空) 2 2
15 舗装工事 2 1

この表から読み取れること: Top 1 = 橋梁工事 (老朽化に伴う保全)、Top 2 = 道路改良工事、Top 3 = 修繕工事、Top 4 = 下水工事 ‥‥工事系カテゴリが上位を独占。災害復旧 (法面崩落・路面陥没・落石) は単独件数が少ないが、kisei_type='disaster' でフラグが立つ別軸での識別が必要。

表: 災害規制 詳細 (1257 中 disaster)

順位 路線名 路線種別 規制内容 規制理由 開始日時 終了日時 年齢(年) 延長
1 指定市一般市道 安佐北1区31号線 市道 通行止め 路面陥没 2018-07-07 00:00:00 NaT 7.84
2 指定市一般市道 安佐北1区35号線 市道 通行止め 路面陥没 2018-07-07 00:00:00 NaT 7.84
3 指定市一般市道 安佐北1区66号線 市道 通行止め 路面陥没 2018-07-07 00:00:00 NaT 7.84
4 入江・土師線 その他/不明 通行止め 橋梁崩落 2021-08-13 09:00:00 NaT 4.74 300m
5 主要地方道 広島三次線 主要地方道 片側交互通行 道路損壊 2023-07-10 12:10:00 NaT 2.83 100m
6 主要地方道 高田沖美江田島線 主要地方道 その他 災害 2024-04-04 14:10:00 NaT 2.09 24m
7 国道 186号 国道 片側交互通行 落石 2026-03-25 12:00:00 NaT 0.12 124m

この表から読み取れること: 最古は 2018-07-07 開始 (指定市一般市道 安佐北1区31号線) で、7.8 年継続。2018-07-07 西日本豪雨起因が 3 件残存。道路復旧の時間スケールは数年〜10 年に及び、被災規模 + 代替路線数が長期化を決める。H4 (西日本豪雨の長期残存) を強支持

【分析 3】 地理分布 + 規制延長分布 — 対数正規 4 桁の幅

狙い (分析 3: 地理分布 + 規制延長分布)

規制種別・路線種別・規制理由は「属性」 軸の分析だった。 本セクションは地理 (緯度経度) + 規模 (規制延長 m) という連続値軸で H5 (規制延長の対数正規分布) を検証する。 さらに市町コロプレスで規制密度の地理的偏在を読む。

手法 (geopandas sjoin + log10 ヒスト)

緯度経度 (EPSG:4326) を点に変換し、行政区域 (EPSG:6671) に投影変換した上で sjoin で市町コードを付与:

規制延長 (encho) は文字列 ('33m', '1,872m') からカンマ除去 + m 単位抽出する関数 parse_encho_m() を導入。log10 スケールで分布を見ると、 10m〜92,000m の4 桁が一様には分布せず、対数正規に近い形になるはず。

入力: 緯度経度列 + encho 列 + 行政区域 GeoJSON (140 ポリゴン)。
出力: 市町別件数表 + log10(encho) ヒスト。
限界: 一部の規制点が県外/不明 (lat/lon が広島県境外) と判定される (国道 2 号の境界部・島嶼部の精度問題)。
代替案: 地理分析を路線 (rosen_key) ベースに切り替えれば 行政区域不確定性が消えるが、密度マップが描けない。

実装コード

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 緯度経度 → 市町 sjoin + 規制延長 log10 分布
import geopandas as gpd, numpy as np, pandas as pd, re

def parse_encho_m(s):
    if pd.isna(s) or s == "": return np.nan
    s = str(s).replace(",", "").strip()
    m = re.match(r"(\d+(?:\.\d+)?)\s*([mk]?)", s)
    if not m: return np.nan
    v = float(m.group(1))
    if m.group(2) == "k": v *= 1000
    return v

df["encho_m"] = df["encho"].apply(parse_encho_m)
encho_pos = df["encho_m"].dropna()
encho_pos = encho_pos[encho_pos > 0]
log10_encho = np.log10(encho_pos)
log_range = log10_encho.max() - log10_encho.min()  # 4 桁
print(f"min={encho_pos.min():.0f}, max={encho_pos.max():.0f}, "
      f"log10 range = {log_range:.2f} 桁")

# CRS 変換 + sjoin
admin = gpd.read_file("admin_pref.geojson").to_crs("EPSG:6671")
admin_diss = admin.dissolve(by="CITY_CD", as_index=False)
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.lon, df.lat),
                        crs="EPSG:4326").to_crs("EPSG:6671")
joined = gpd.sjoin(gdf, admin_diss[["CITY_CD", "geometry"]],
                    how="left", predicate="within")
city_counts = joined.groupby("CITY_CD").size()

図 2: 規制点マップ — 規制種別で色分け

なぜこの図か: 学習者が広島県地図上で規制がどこに集中しているかを直感する。 緯度経度の点を 5 規制種別の固定色で塗り、災害規制 (kisei_type='disaster') を赤リングで強調。 1258 (今後の規制 N=149) をベースにし、後続の図 3 (LineString) と 図 5 (コロプレス) と比較できる。

図 2: 規制点マップ (規制種別)
図 2: 規制点マップ (規制種別)

この図から読み取れること:

図 3: 規制区間 LineString 重畳マップ

なぜこの図か: 図 2 の点マップでは規制区間の長さが見えない。 本図は kukanroot WKT を LineString 化して描画し、区間規制の地理的広がりを示す。 細線 = 1258、太線 = 1257 で重畳すると、本日と今後の時間スコープの違いも 地理的に確認できる。

図 3: 規制区間 LineString 重畳
図 3: 規制区間 LineString 重畳

この図から読み取れること:

図 5: 市町別 規制密度コロプレス

なぜこの図か: 点や線では市町単位の規制集積度合いが見えにくい。 市町ポリゴンを 1258 (今後) の規制件数で着色し、地理的偏在を直接可視化する。 上位 8 市町には本日/今後の件数を併記して、両 dataset の差も同時に読める。

図 5: 市町別 規制密度コロプレス
図 5: 市町別 規制密度コロプレス

この図から読み取れること:

図 6: 規制延長 log10 ヒストグラム + 累積分布

なぜこの図か: encho (規制延長) は最小 10m から最大 92,000m まで 4 桁の幅を持つ。 線形軸では長距離規制の少数に押されて分布形状が読めない。 log10 スケールにすると対数正規 (= 正規分布のような釣り鐘) 形状が見える。 H5 (対数正規分布 + median 数百 m) の検証に最適。

図 6: 規制延長 log10 ヒスト + 累積分布
図 6: 規制延長 log10 ヒスト + 累積分布

この図から読み取れること:

表: 市町別 規制件数 (Top 15)

市町 1257 件数 1258 件数 合計件数
福山市 6 23 29
廿日市市 3 16 19
三原市 5 13 18
(県外/不明) 8 8 16
庄原市 8 7 15
三次市 5 8 13
広島市南区 1 12 13
安芸高田市 5 7 12
大竹市 4 7 11
東広島市 2 8 10
広島市安佐北区 5 5 10
安芸太田町 4 3 7
広島市中区 1 6 7
尾道市 1 5 6
海田町 3 3 6

この表から読み取れること: 上位 5 市町で 1258 全体の 45% を占める。都市部 + 国道通過地に規制が集中。中山間 (庄原・三次) や島嶼部 (江田島) も少数だが規制を持つ。県外/不明判定の点は 8 件のみ。

表: 規制期間・延長 統計

指標 1257 本日 1258 今後
規制期間 中央値 (日) 182.4 0.3
規制期間 平均 (日) 238.7 76.7
規制期間 最長 (日) 1107 1107
規制延長 中央値 (m) 170 180
規制延長 平均 (m) 1848 1833
規制延長 最大 (m) 92000 92000
規制延長 総和 (km) 112.7 111.8

この表から読み取れること: 規制延長は中央値 180m, 最大 92000m, 総和 112km。規制期間は中央値 0 日、最長 1107 日 (約 3 年)。H5 (対数正規 4 桁) を支持。長距離規制 (10km 超) は事前通行規制区間 (積雪等) で、短距離規制 (10-100m) はピンポイント工事。中央値の街区 1 ブロック規模 (300-500m) が最頻帯。

【分析 4】 1257 ⊂ 1258 包含関係 — 2 ビューの構造的相互関係

狙い (分析 4: 2 dataset の包含関係)

1257 (本日) と 1258 (今後) は同じ運用システムから派生する 2 つのビューと 仮説 H6 で予想した。本セクションでは id 集合の差集合を計算し、 3 つの排他的グループに分解する:

3 グループの件数比から、運用システムの時間境界の操作論理が見える。

実装コード

L50_road_restrictions.py 行 1685–1717

 1
 2
 3
 4
 5
 6
 7
 8
 9
1694
1695
1696
1697
1698
# 集合演算による包含関係分解
ids_1 = set(df1["id"])
ids_2 = set(df2["id"])
common  = ids_1 & ids_2
only_1  = ids_1 - ids_2
only_2  = ids_2 - ids_1
print(f"1257 ∩ 1258 = {len(common)}")
print(f"1257 only    = {len(only_1)}")
print(f"1258 only    = {len(only_2)}")
print(f"包含率 = {len(common)/len(ids_1)*100:.1f}%")

# 1257 only の特性: 本日中に終了する短期規制 = end_date は今日
df_only_1 = df1[df1["id"].isin(only_1)].copy()
print(df_only_1[["rosenname", "kiseinaiyo", "end_date"]])

図 9: 1257 / 1258 包含関係 (Venn 風 + bar)

なぜこの図か: 集合演算の結果を視覚化するため Venn 風と bar の 2 表示。 左の Venn 風で「1257 が 1258 にほぼ完全包含される」 という構造的事実を直感的に伝え、 右の bar で 3 グループの絶対件数を厳密に示す。

図 9: 包含関係 (Venn 風 + bar)
図 9: 包含関係 (Venn 風 + bar)

この図から読み取れること:

表: 1257 / 1258 包含関係

集合 件数 意味
1257 ∩ 1258 (両方含む) 66 本日 ∈ 今後 = 95.7%。1258 は 1257 のスーパーセット
1257 only (本日終了予定) 3 本日中に終了する規制 (1258 は明日以降を扱うので除外)
1258 only (将来開始) 83 今後開始する規制 (現在は実施されていない)
1257 計 69 本日実施中の規制
1258 計 149 今後実施予定の規制

この表から読み取れること: 1258 = 1257 ∪ 将来規制 という設計。包含率 95.7% で 1258 が 1257 のスーパーセット。DoBoX は 1 つの規制台帳 + 取得時刻フィルタで 2 ビューを生成。H6 を強支持

仮説検証総合

本記事の 6 仮説と観測結果の照合:

仮説 予想 観測 判定
H1 (one_side 支配) 片側交互通行が最頻 (40-50%), 通行止 15-25% 片側 1257=55.1% / 1258=47.0%, 通行止 1257=31.9% / 1258=14.8% 支持
H2 (国道 vs 県道の管轄分離) 1258 国道シェア > 50%, 1257 国道 < 30% 1257 国道=23.2%, 1258 国道=65.8% 支持
H3 (工事 9 vs 災害 1) 工事 90%+, 災害 10% 弱 1257 災害=7/69 = 10.1%, 1258 災害=7/149 = 4.7% 支持
H4 (2018 西日本豪雨の長期残存) 2018-07-07 起因の規制が複数残存、最長 8 年 2018-07-07 起因=3 件残存、最古 2018-07-07 (7.8 年継続) 支持
H5 (規制延長の対数正規分布) log10 範囲 4 桁、median 数百 m min=10m, max=92000m, log10 範囲 4.0 桁, median=180m 支持
H6 (1257 ⊂ 1258) 1257 → 1258 包含率 > 90% 包含率 95.7% (66/69) 支持

主要発見の総括

2 dataset の構造的相互関係

1257 と 1258 は独立した別データではなく、同じ運用システムから派生する時間スコープの異なる 2 ビュー。1257 = 取得時刻 ∈ [start, end] のフィルタ、1258 = 取得時刻 ≤ end のフィルタ。1258 のスーパーセット構造は、防災・交通計画アプリが「直近の影響」 と「将来の予定」 を 1 リクエストで取得できる設計に直結する。本記事は 2 dataset を統合分析することで、この制度的設計を逆工学的に解読した。

発展課題

結果X → 新仮説Y → 課題Z (4 課題)

発展課題 1 (西日本豪雨の長期残存 由来)

発展課題 2 (規制延長の対数正規分布 由来)

発展課題 3 (1257 ⊂ 1258 包含構造 由来)

発展課題 4 (時系列スナップショット 由来)