# collection_log.md — city_data.csv の出所

対象: 135市区（2020年国勢調査で人口20万人以上の市 109 ＋ 東京都特別区 23 ＋
そのどちらにも入らない県庁所在地 3〔甲府市・鳥取市・山口市〕）
取得日: すべて **2026-08-25**
再現手順: `uv run python scripts/build_base.py` → 各 `fetch_*.py` → `build_city_data.py`

---

## 対象都市の決め方

仕様の抽出ルール「2020年国勢調査人口20万人以上の市＋全都道府県庁所在地（東京は新宿区）」を
そのまま適用すると **113市区** にしかならず、仕様が見込む「約130市区」と17件ずれた。
依頼者の判断で **東京都特別区23区をすべて対象に含め、135市区** とした。
新宿区は「東京都の県庁所在地」としても特別区としても該当するので二重には数えない。

政令指定都市は行政区ではなく市単位で1行。人口20万人以上の判定も市単位で行っている。

---

## 列ごとの出所

| 列 | 値の中身 | ソース | 集計方法 |
|---|---|---|---|
| `city_code` | JIS 5桁（文字列） | 総務省 全国地方公共団体コード | 6桁コードの先頭5桁 |
| `pref` / `city` | 都道府県名 / 市区名 | 同上 | そのまま |
| `population` | 2020年国勢調査 総人口 | 社会・人口統計体系 A表 項目 `A1101` | 市区町村行を直接参照 |
| `area_km2` | 2023年 総面積（北方地域・竹島を除く） | 同 B表 項目 `B1101` | 同上 |
| `habitable_km2` | 2023年 可住地面積 | 同 B表 項目 `B1103` | 同上。**人口密度の分母はこちら** |
| `daytime_population` | 2020年国勢調査 昼間人口 | 同 A表 項目 `A6107` | 同上 |
| `retail_sales_million` | 2020年の小売業計 年間商品販売額（百万円） | 令和3年経済センサス-活動調査 卸売業，小売業 産業編（市区町村表）第1表 | 産業小分類 `I2_小売業計` の「年間商品販売額」列 |
| `workers` | 2021年 従業者数（民営） | 社会・人口統計体系 C表 項目 `C2208` | 市区町村行を直接参照 |
| `screens` | 映画館のスクリーン数（成人映画館・閉館済みを除く） | コミュニティシネマセンター「映画上映活動年鑑2025」全国映画館リスト | 市区町村名を市区町村コードへ解決して合計 |
| `dept_stores` | 会員百貨店の店舗数 | 日本百貨店協会「百貨店 店舗所在地」 | 住所を市区町村コードへ解決して集計 |
| `large_stores` | 2021年 大型小売店数 | 同 H表（居住）項目 `H6132` | 市区町村行を直接参照 |
| `cafe_chains` | スターバックス店舗数 | スターバックス公式店舗検索 | 都道府県ごとの facet を市区町村名で集計 |
| `fastfood_big3` | すき家・吉野家・松屋の店舗数（合計） | 各社公式の店舗検索 | 下記「牛丼3社の数え方」参照 |
| `burger_king` | バーガーキングの店舗数 | バーガーキング公式サイトの店舗検索API | 住所を市区町村コードへ解決して集計 |
| `muji_loft_hands` | 無印良品・ロフト・ハンズの店舗数（合計） | 各社公式の店舗一覧 | 住所を市区町村コードへ解決して集計。採否の線引きは下記 |
| `big_electronics` | 都市型の大型家電量販店の店舗数 | ヨドバシカメラ／ビックカメラ／ヤマダデンキ 各社公式の店舗一覧 | 住所を市区町村コードへ解決して集計。採否の線引きは下記 |
| `performance_venues` | 2021年 興行場（別掲を除く），興行団 事業所数 | 令和3年経済センサス-活動調査 産業横断的集計 第9-1A表 | 産業小分類 `802` の事業所数 |
| `bars_snacks` | 2021年 バー，キャバレー，ナイトクラブ 事業所数 | 令和3年経済センサス-活動調査 産業横断的集計 第9-1A表 | 産業小分類 `766` の事業所数 |
| `cinema_complex` | シネマコンプレックスの館数 | 同 全国映画館リスト | 種別が「シネマコンプレックス」の館を数える |
| `mini_theater` | ミニシアター・名画座の館数 | 同 全国映画館リスト | 種別に「ミニシアター」か「名画座」を含む館を数える |
| `film_festivals` | 2025年度に開催された映画祭の数 | 同「Ⅱ1 全国映画祭リスト2025」 | 開催月の記載がある行だけを数える |
| `premium_screens` | IMAX / Dolby Cinema / 4DX / ScreenX 等の特別スクリーン数 | TOHOシネマズ・109シネマズ・ユナイテッド・シネマ・イオンシネマ 各社公式 | 「劇場 × フォーマット」の組を数える |
| `income_per_taxpayer_man` | 納税義務者1人あたり課税対象所得（万円） | 社会・人口統計体系 C表 `C120110` ÷ `C120120` | 百万円を万円に直して割る |
| `doctors_per_100k` | 人口10万人あたり医師数 | 同 I表 `I6100` ÷ A表 `A1101` | |
| `clinics_per_100k` | 人口10万人あたり一般診療所数 | 同 I表 `I5102` ÷ A表 `A1101` | |
| `nurseries_per_1k_children` | 15歳未満1000人あたり保育所等数 | 同 J表 `J250302` ÷ A表 `A1301` | |
| `housing_area_m2` | 1住宅あたり延べ面積（m²） | 同 H表 `H2130` | そのまま |
| `libraries` | 2021年 図書館数 | 社会・人口統計体系 G表（文化・スポーツ）項目 `G1401` | 市区町村行を直接参照 |
| `museums` | 登録博物館＋指定施設の館数 | 文化庁 博物館総合サイト「全国の博物館リスト」 | 市区町村名を解決して集計 |
| `art_museums` | うち館種が「美術」の館数 | 同上 | 同上 |
| `rail_stations` | 鉄道駅数（モノレール・路面電車・地下鉄を含む） | 国土数値情報 N02（令和6年度 鉄道データ）× N03（行政区域 2025-01-01） | 空間結合。下記参照 |
| `passengers_per_day` | 駅の1日あたり乗降客数（2022年度） | 国土数値情報 S12（駅別乗降客数 S12-23）× N03（行政区域 2025-01-01） | 空間結合。下記参照 |

---

## ソースURL

### 基礎統計

- 総務省 全国地方公共団体コード
  `https://www.soumu.go.jp/main_content/000925835.xlsx`
  シート「R6.1.1現在の団体」（都道府県・市・特別区・町村。政令市の区は別シート）
- 社会・人口統計体系「統計でみる市区町村のすがた2025」基礎データ（公開 2025-06-20）
  一覧: `https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00200502&tstat=000001229545&cycle=0&tclass1=000001229546&tclass2val=0&metadata=1&data=1`
  - A 人口・世帯 `https://www.e-stat.go.jp/stat-search/file-download?statInfId=000040283810&fileKind=0`
  - B 自然環境 `…statInfId=000040283811&fileKind=0`
  - C 経済基盤 `…statInfId=000040283812&fileKind=0`
- 令和3年経済センサス-活動調査 卸売業，小売業 産業編（市区町村表）第1表
  `https://www.e-stat.go.jp/stat-search/file-download?statInfId=000040032863&fileKind=0`
- 令和3年経済センサス-活動調査 産業横断的集計 第9-1A表（産業小分類別 全事業所数）
  `https://www.e-stat.go.jp/stat-search/file-download?statInfId=000040067884&fileKind=0`

### 施設系

- 国土数値情報 N02 鉄道データ（令和6年度）
  `https://nlftp.mlit.go.jp/ksj/gml/data/N02/N02-24/N02-24_GML.zip`
- 国土数値情報 N03 行政区域（2025年1月1日）
  `https://nlftp.mlit.go.jp/ksj/gml/data/N03/N03-2025/N03-20250101_GML.zip`
- 国土数値情報 S12 駅別乗降客数（S12-23）
  `https://nlftp.mlit.go.jp/ksj/gml/data/S12/S12-23/S12-23_GML.zip`（5.9MB）
- スターバックス公式店舗検索が使うエンドポイント
  `https://hn8madehag.execute-api.ap-northeast-1.amazonaws.com/prd-2019-08-21/storesearch/facet`
  （`store.starbucks.co.jp` からの Referer が必要。都道府県コードで絞って
  `facets.address_2` を読む。47回のGETのみ）
- 日本百貨店協会「百貨店 店舗所在地」
  `https://www.depart.or.jp/depart_address/`
- 無印良品 公式 店舗一覧（都道府県別）
  `https://www.muji.com/jp/ja/shop/preflist/01` 〜 `/47`（コードは2桁ゼロ埋め。`/1` は404）
  一覧が市区町村の見出しで区切られており、各店に住所が付く。
  素の urllib のヘッダでは応答が返ってこない（Akamai）。`Sec-Fetch-*` / `sec-ch-ua` を含む
  ブラウザ相当のヘッダ一式を送ると 200 が返る
- ロフト 公式 店舗一覧
  `https://www.loft.co.jp/shop_list/`（全190件が1ページ）
- ハンズ 公式 店舗一覧
  `https://info.hands.net/list/`（全104件が1ページ。業態がアイコンの class で区別されている）
- ヨドバシカメラ 店舗一覧
  `https://www.yodobashi.com/ec/print/store/`（印刷用。24店の名前と住所が1ページに揃う）
  検算用に `https://www.yodobashi.com/ec/store/list/`（店舗案内。石井スポーツ等も載る）
- ビックカメラ 店舗一覧
  `https://www.biccamera.com/bc/i/shop/shoplist/index.jsp`（全67件が1ページ）
  **このページだけ Windows-31J**。utf-8 決め打ちで読むと全部化ける
- ヤマダデンキ 店舗一覧（都道府県別）
  `https://www.yamada-denki.jp/store/contents/?p=1` 〜 `?p=47`（全国1,109件）
- すき家 店舗検索 API
  `POST https://maps.sukiya.jp/api/search`（`address=県名+市区名` で件数が返る。
  XHR ヘッダと Referer が必要）
- 吉野家 店舗検索（NAVITIME 製）
  `https://stores.yoshinoya.com/yoshinoya/spot/list?search=address&address=01` 〜 `47`
  （都道府県ページに市区町村別の件数とコードが載る）
- バーガーキング 店舗検索
  `POST https://www.burgerking.co.jp/burgerking/BKJ0302.json`
  （SPA の非公開 API。詳細は下記「バーガーキングの取り方」）
- 松屋フーズ 店舗検索（NAVITIME 製）
  `https://pkg.navitime.co.jp/matsuyafoods/spot/list?search=address&address=01` 〜 `47`
  （同上。`&category=0101`（松屋）`0102`（松屋PREMIUM）でブランドを絞る）

---

## 集計方法の注記

### 秘匿値と「該当なし」の区別

経済センサスの表では `x` が秘匿、`-` が該当事業所なしを意味する。
`-` は 0、`x` は欠損として読み込んでいる。対象135市区では `x` は出なかった。

### 政令指定都市の集約

- 経済センサスと社会・人口統計体系は市の合計行（例 `01100_札幌市`）を持つので、
  それを直接使っている。区の行を足し上げてはいない。
- 国土数値情報 N03 の行政区域コードは政令市を **区単位** で持つため、
  区コード → 市コードへ寄せてから集計した。
  市コードは末尾 `00` とは限らない（川崎 14130 / 相模原 14150 / 浜松 22130 /
  堺 27140 / 福岡 40130）ので、コードの形ではなく名称で市の行を判定している。
- チェーン店の住所は「札幌市中央区…」の形なので、市区町村名の最長一致で
  自動的に市へ寄る（`scripts/geocode.py`）。

### 鉄道駅数の数え方

N02 の駅は「事業者・路線ごとの線分」なので、同じ駅が乗り入れ数だけ重複する。
駅名グループコード `N02_005g` で名寄せしてから、線分の代表点が入る市区町村に数えた。
全国10,235レコード → 名寄せ後 9,071駅。

検算: 那覇市 16駅。沖縄都市モノレール（ゆいレール）全19駅のうち、
経塚・浦添前田・てだこ浦西の3駅は浦添市内なので 19−3=16 と一致する。

### 無印/ロフト/ハンズの数え方

3ブランドとも公式の全国店舗一覧を使い、**物販の実店舗だけ**を数えた。
除外したものも理由つきで `data/raw/muji_loft_hands_stores.csv` に残してある
（全1,068件のうち採用1,002件）。

| ブランド | 採用 | 除外したもの |
|---|---|---|
| 無印良品 | 735 | 飲食（Cafe&Meal MUJI / CafeMUJI / MUJI Diner / MUJI Coffee&Bakery）、宿泊（MUJI BASE / MUJI room）、別ブランドのイデーショップ、名前に `【閉】` が付く閉店済みの店 |
| ロフト | 186 | MoMA Design Store 4件（ロフトの運営だが別ブランド） |
| ハンズ | 81 | 海外12件、プラグスマーケット9件、カフェ1件、店名欄に閉店告知が残っている1件 |

`MUJIcom`・`MUJI to GO`・`無印良品500`・`ハンズ ビー` は小型店だが物販なので採用した。

対象135市区の合計は 645 店。八戸市・甲府市・寝屋川市の3市は 0 だが、これは一覧に
当該市の店が1件も無いことを確かめた上での 0 で、未調査ではない
（例: 山梨県の6店はすべて昭和町・富士吉田市・甲斐市にあり、甲府市内には無い）。

### 住所→市区町村コードの表記ゆれ対応

`scripts/geocode.py` の `resolve()` に、**厳密一致が外れたときだけ**動くフォールバックを足した。
すでに解決できている住所の結果は変わらない（追加後に city_data.csv を作り直して
既存列に差分が無いことを確認済み）。

- 郡名を落とす。コード表の町村名は「大口町」なので、住所の「丹羽郡大口町…」と前方一致しない
- 異体字を入れ替える。「茅ケ崎市」/「茅ヶ崎市」、「塩竃市」/「塩竈市」

これで無印/ロフト/ハンズの未解決52件が0件になった。うち135市区に関わるのは茅ヶ崎市の2店。

### 大型家電量販店の数え方

「都市型大型店」の線引きは利用者の指定による。除外分も理由つきで
`data/raw/big_electronics_stores.csv` に残してある（全1,200件のうち採用84件）。

| ブランド | 採用 | 線引き |
|---|---|---|
| ヨドバシカメラ | 24 | 「ヨドバシカメラ」を冠する全店。グループの石井スポーツ・アートスポーツ、ヨドバシアウトレット京急川崎は対象外 |
| ビックカメラ | 43 | 家電の大型店のみ。ビック酒販／お酒屋／ビックカメラリカー（酒販）、ビックフォトスタジオ、ビックトイズ、アウトレット×ソフマップ、Air BicCamera（空港等の免税小型店）、Select・Bic Style（小型店）は対象外。浦和西口店は取得日時点で未開業なので除外 |
| ヤマダデンキ | 17 | 都市型フォーマットの LABI / LABI LIFE SELECT のみ。郊外型のテックランド、Tecc LIFE SELECT、ツクモ、IDC OTSUKA、ベスト電器などは対象外 |

ヨドバシは店舗案内ページ側の「ヨドバシカメラ」冠の店舗数と一致するかを毎回検算している。

注意: **名古屋・仙台・福岡には現在 LABI が無い**。かつての都市型旗艦店は
テックランド／Tecc LIFE SELECT に転換されており、この線引きでは入らない。
その3市の値はヨドバシとビックカメラだけで立っている（名古屋3・福岡3・仙台0）。

対象135市区の合計は 80 店。全国84店のうち残り4店は立川市・武蔵野市にあり、
どちらも人口20万人未満で対象に入らない。

### 牛丼3社の数え方

- **すき家** は API に「県名+市区名」を渡して135市区を1件ずつ問い合わせ、件数を読んだ。
  前方一致検索なので、返ってきた住所が本当にその市区のものかを毎回検証している（食い違いは0件）。
  ページング（morelist）はセッション状態を持ち、状態が壊れると全国2,005件を返し続けるので使わない。
- **吉野家・松屋** は NAVITIME 製の店舗検索で、都道府県ページに市区町村別の件数と
  JIS コードが載っているのでそれを読んだ。住所解決は不要。
- **松屋** は一覧に松屋フーズ全ブランド（松のや・マイカリー食堂・すし松等）が混ざるため、
  カテゴリ 0101（松屋）+ 0102（松屋PREMIUM）だけを合計した。
  東京都で全14カテゴリの合計が絞りなしの総数と一致（530=530）することを確認済み。
  1件も無い都道府県でカテゴリを絞るとページが「近隣の地域」表示に差し替わって
  全国件数が出る罠があり、市区町村一覧のクラスが在るときだけ読む。
  検算として都道府県ごとに「松屋ブランド ≤ 全ブランド」を確認している。
- 吉野家の「そば処吉野家」「吉野家×はなまるうどん」は既定の一覧（カテゴリ 0101 相当）に
  含まれない別カテゴリなので入っていない。

この列だけ**出力を対象135市区に限定**している。すき家が「135市区を名指しで問い合わせる」
取り方なので、全国ぶんを揃えても3社で網羅範囲がそろわないため。
ブランド別の内訳は `data/raw/fastfood_big3_counts.csv`。
135市区の合計は 2,781 店（すき家 1,088 / 吉野家 849 / 松屋 844）。
すき家は135市区すべてに、吉野家は鳥取市以外に在り、松屋の0は7市
（いずれも実データ由来の0で、鳥取県・島根県などには松屋が無い）。

### 「店舗ゼロ」と「未調査」

`dept_stores` / `cafe_chains` / `rail_stations` / `bars_snacks` /
`muji_loft_hands` / `big_electronics` / `fastfood_big3` は
全国を網羅するソースから作っているので、ソースに現れない市区町村は **0** で埋めた。
一度も収集していない列は **空欄** のまま置いてある。

---

## 未収集の列とその理由

| 列 | なぜ埋まっていないか | 代案 |
|---|---|---|
| `screens` | ~~無償の一次情報として存在しない~~ → **この判断は誤りだった（2026-08-25 訂正、下記）**。未収集なのは着手していないだけ | 経済センサス第9-1A表の産業小分類 `801_映画館` の**事業所数**なら取得済み（`data/raw/industries.csv` の `cinemas` 列）。スクリーン数ではなく館数なので `screens` には入れていない |
| `large_sc` | 日本SC協会のSC名鑑は有償。店舗面積3万m²以上という条件で機械的に絞れる無償データが無い | — |
| `live_capacity2000` | 会場DBに公的な一次情報が無く、キャパ2,000人以上の判定が会場ごとの公称値頼りになる | — |

この3列が空欄のため、全135市区の `coverage` は **0.82**（有効重み 11.5 / 全重み 14.0）。
`toshido_scoring.py` の警告しきい値 0.7 は上回っている。

---

## 参考として持っているが city_data.csv に入れていない値

`data/raw/industries.csv`（令和3年経済センサス 第9-1A表 由来、市区町村別事業所数）

| 列 | 産業小分類 |
|---|---|
| `bars_snacks` | 766 バー，キャバレー，ナイトクラブ（本採用） |
| `sakaba` | 765 酒場，ビヤホール |
| `cinemas` | 801 映画館 |
| `dept_gms` | 561 百貨店，総合スーパー |

---

## 訂正: スクリーン数の一次情報は存在する（2026-08-25）

上表で「無償の一次情報として存在しない」としたのは**誤り**。以下が使える。

**コミュニティシネマセンター「映画上映活動年鑑2025」Ⅰ5 全国映画館リスト2025**
`http://jc3.jp/wp/wp-content/uploads/2026/05/映画上映活動年鑑2025_Ⅰ5全国映画館リスト2025.pdf`
（一覧ページ: `http://jc3.jp/wp/research-reports/`）

6ページのPDFに全国およそ607館が載っており、列は
**都道府県 / 市区町村 / 映画館名 / スクリーン数 / 種別**。
種別は シネマコンプレックス（約367）／ ミニシアター・名画座（約157）／
既存興行館（約58）／ 成人映画館（約25）に分かれている。
館名に `＊2026年3月閉館` `＊2025年10月開館` の注記が付く行がある（7件確認）。

### 罠

- **サイトは https だと証明書が一致しない**（`*.xserver.jp` の証明書が返る）。`http://` で取る
- **pypdf では市区町村と都道府県の列が文字化けする**（CID フォントに ToUnicode が無く、
  CID をそのまま符号位置として拾ってしまう）。館名だけは読める、という中途半端な壊れ方をする。
  **pymupdf を使えば全列が綺麗に取れる**
- 1ページが2つの表ブロックに分かれており、`no.` はブロックごとに振り直される。
  行番号を通し番号として使わないこと
- 館名が2行に折り返される行がある（例: フォーラム盛岡）

同じ年鑑に「Ⅱ1 全国映画祭リスト2025」「Ⅱ2 公共の映画専門施設（シネマテーク）及び映画資料館」
「Ⅳ 都道府県別上映施設一覧」もあり、いずれも同じ取り方ができる。

---

## 映画・文化系の列（2026-08-25 追加）

利用者の指定で、映画鑑賞という主観を軸にした指標を足した。
「都会度」というより「映画充実度」を測る列が混ざっているのは意図的。

### 映画館（`screens` / `cinema_complex` / `mini_theater`）

`scripts/fetch_cinemas.py`。
コミュニティシネマセンター「映画上映活動年鑑2025」Ⅰ5 全国映画館リスト2025 の PDF から、
**都道府県 / 市区町村 / 映画館名 / スクリーン数 / 種別** を読む。
全国 597 館を取得し、利用者の指定で以下を除外した。

| 除外 | 件数 | 理由 |
|---|---|---|
| 成人映画館 | 25 | 対象外との指定 |
| 閉館 | 15 | 館名に `＊2026年3月閉館` のような注記があるもの。`＊開館` は新規開館なので残す |

採用 557 館・総スクリーン 3,639。日本映画製作者連盟が公表する全国スクリーン数
（およそ3,600）とおおむね合う。除外分も理由つきで `data/raw/cinemas.csv` に残してある。

種別は シネマコンプレックス / ミニシアター・名画座 / 既存興行館 の3つ（併記あり）。
`cinema_complex` と `mini_theater` は種別に該当語を含む館を数えたもので、
「既存興行館｜ミニシアター/名画座」のように併記された館は両方に数える。
どちらにも該当しない既存興行館だけの館は、スクリーン数には入るが館数の内訳には出ない。

**PDF の罠**（fetch_film_festivals.py も同じ）

- サイトは https だと証明書が一致しない（`*.xserver.jp` の証明書が返る）。`http://` で取る
- **pypdf では都道府県・市区町村が文字化けする**。CID フォントに ToUnicode が無く、
  CID をそのまま符号位置として拾ってしまう。館名だけは読めるので気づきにくい。
  **pymupdf なら全列が綺麗に取れる**
- 1ページに表ブロックが2つあり、そのたびにヘッダ行が挟まる。
  ただし no. は文書全体の通し番号なので、これを軸にすれば切り出せる
- **番号・都道府県・市区町村の入り方が3通りある**。ここが一番はまる。
  2桁までは `99` `埼玉県` `川越市` と3行に割れるが、
  3桁になると `100 埼玉県` `熊谷市` と番号が都道府県とくっつき、
  さらに詰まると `229 神奈川県横浜市` と市区町村まで1行に入る（区切り文字なし）
- 館名が2行に折り返される行がある（フォーラム盛岡、ユナイテッド・シネマ アシコタウンあしかが等）

検算: 通し番号 1〜597 に欠番なし、47都道府県すべてが出現、末尾が沖縄県。
市区町村コードに解決できなかった館は0件。
ミニシアター・名画座の最多は渋谷区9館、次いで大阪市7・新宿区6・千代田区5。

### 映画祭（`film_festivals`）

`scripts/fetch_film_festivals.py`。同じ年鑑の「Ⅱ1 全国映画祭リスト2025」。
216件を取得し、**開催月の記載がある151件**だけを数えた。
原資料は「2020年以降の実施が確認できなかったが終了も確認できないもの」も
一部載せているので、開催月が空の行は現に開催されているとみなさない。
最多は千代田区9件（うち国際映画祭4）、横浜市8、京都市5。

### 図書館（`libraries`）

社会・人口統計体系 G表（文化・スポーツ）の項目 `G1401` 図書館数。2021年。
A/B/C表と同じ e-Stat のファイル群で、statInfId は `000040283816`。

**蔵書冊数は入れられなかった。** 市区町村別の蔵書冊数を持つ無償の一次情報が無い。

- 文科省「社会教育調査」の図書館調査は都道府県別までで、市区町村別の蔵書数表が無い
- 日本図書館協会『日本の図書館 統計と名簿』には市区町村別の蔵書冊数があるが**有償**。
  無償公開されている電子媒体版は 1996〜2020年ぶんで、Box の共有フォルダ配布。
  Box が JavaScript で描画するページなので機械的に落とすのが面倒なうえ、最新でも2020年

規模を測るなら有償の名簿を買うしかない、というのが調査の結論。

### 博物館・美術館（`museums` / `art_museums`）

`scripts/fetch_museums.py`。文化庁 博物館総合サイト「全国の博物館リスト」の CSV
`https://museum.bunka.go.jp/wp-content/uploads/2026/08/MuseumList_20260820.csv`
（リンク元は `https://museum.bunka.go.jp/guide/`。日付つきのファイル名なので更新時は貼り替える）

列は 名称 / 都道府県 / 市区町村 / 登録状況 / 設置者 / 館種。1,475館。
博物館法上の**登録博物館（1,084）と指定施設（390）だけ**で、
数のうえで多数を占める「博物館類似施設」は入っていない。
網羅性より質のそろい方を優先した一覧なので、
「その市区町村にきちんとした館がいくつあるか」を測る用途には向いている。

`art_museums` は館種が「美術」の館（全国520）。
館種は他に 歴史523・総合191・科学126・水族館45・動物園40 など。

**規模の列は無い**（延床面積・収蔵品数・入館者数のいずれも）。図書館と同じく、
市区町村別の規模データは無償の一次情報が見つかっていない。

解決できなかったのは2件だけで、どちらも原資料側の表記不備
（`北海道 枝幸郡`＝町村名が無い、`岩手県 陸前高市`＝陸前高田市の誤り）。
どちらも対象135市区には関係しない。

---

## 住みやすさ系（2026-08-25 追加）

`scripts/build_city_data.py` の `load_livability()`。
社会・人口統計体系の A / C / H / I / J 表から作る。
A/B/C 表と同じ e-Stat のファイル群で、statInfId は D=…813 E=…814 F=…815
G=…816 H=…817 I=…818 J=…819（`data/raw/sugata2025_*.xls`）。

**生の件数ではなく比率として持っている。** 医師数や保育所数をそのまま入れると
人口の大きい市が自動的に上位に来てしまい、「都会度」の指標と見分けがつかなくなるため。

| 列 | 作り方 | 分布 |
|---|---|---|
| `income_per_taxpayer_man` | 課税対象所得(百万円)×100 ÷ 納税義務者数 | 中央 362万円 / 港区 1,397万円。歪みが大きいので log 変換 |
| `doctors_per_100k` | 医師数 ÷ 総人口 ×10万 | 中央 280人。大学病院のある区が突出するので log 変換 |
| `clinics_per_100k` | 一般診療所数 ÷ 総人口 ×10万 | 中央 84施設。log 変換 |
| `nurseries_per_1k_children` | 保育所等数 ÷ 15歳未満人口 ×1000 | 中央 1.8所。歪みが小さいので変換なし |
| `housing_area_m2` | 1住宅当たり延べ面積 | 中央 85.7m²。福井市126.4 / 新宿区51.9。変換なし |

135市区すべてで欠損0。

`housing_area_m2` は現行スコアとの順位相関が **−0.51** で、都会度の対抗軸として効く。
グループ「住みやすさ系」の倍率は **既定 0**。都会度とは別の軸なので、
既定の総合スコアには効かせず、見たいときにスライダーで上げる作りにしてある。

---

## 特別スクリーン `premium_screens`（2026-08-25 追加）

`scripts/fetch_premium_screens.py`。
利用者の指定でフォーマット別には分けず1列にまとめた。
数えるのは「劇場 × フォーマット」の組で、1館が IMAX と 4DX の両方を持てば 2。

### フォーマット元の公式は全部使えない

- `imax.com` … 403
- `4dx.com` … **SSL証明書が期限切れ**。`4dx.jp` は中身が無い
- `screenx.com` … 実質空。`screenx.jp` は名前解決できない
- `dolby.com` … 日本語の劇場名が出ない

そこで無印/ロフト/ハンズや家電量販店と同じく、チェーン各社の公式から集めている。

### チェーンごとに劇場名の在り方が違う

| チェーン | 劇場名がどこにあるか |
|---|---|
| TOHOシネマズ | `alt="TOHOシネマズ 新宿"` の**属性値**。本文には出ない。ページは Shift_JIS |
| 109シネマズ | IMAXページは本文、4DXページは `alt="109シネマズ富谷画像4DX"` |
| ユナイテッド・シネマ | **本文にも属性にも名前が無い**。`/kanazawa/` のようなリンクのスラグだけ。スラグごとに劇場ページを1回引いて `<title>` から名前を取る |
| イオンシネマ | トップページの劇場ブロックに `data-chip="IMAXレーザー"` が並ぶ |

そのため markup は解析せず、**生HTMLを正規化した文字列に劇場名が出てくるか**で判定している。
**タグを剥がすと TOHO の alt が消える**ので剥がさない。ここは一度間違えた。
ナビにチェーン全劇場が並んでいると全部当たってしまうので、
1ページでそのチェーンの半分以上に当たったら警告を出すようにしてある。

### 収集できた範囲（のべ120件 / 86館 / 73市区町村）

| チェーン | フォーマット | 館数 |
|---|---|---|
| TOHOシネマズ | IMAX / TCX / 轟音 | 13 / 9 / 8 |
| 109シネマズ | IMAX / 4DX・ScreenX | 9 / 15 |
| ユナイテッド・シネマ | IMAX / 4DX / ScreenX | 計25館・のべ37 |
| イオンシネマ | IMAX / 4DX / MX4D / ULTIRA / THX | 計22館・のべ29 |

イオンの `Dolby Atmos` は音響だけで導入館が多いため、特別スクリーンとしては数えていない。
109シネマズの `/4dx/` は 4DX と ScreenX の合同ページなので、フォーマット名も
`4DX/ScreenX` としてある（15/19館と当たりすぎに見えるが、ページの性格どおり）。

### 数えられていないもの（既知の取りこぼし）

- **TOHOシネマズの Dolby Cinema / MX4D / ScreenX**。劇場一覧が JavaScript で描かれており、
  HTML には劇場名が出てこない。`theater/find.html` も同様
- **松竹（MOVIX）と T・ジョイ の全フォーマット**。フォーマット別の一覧ページが見つからない
- ユナイテッド4館（枚方・岸和田・熊本・お台場）。2025年の映画館リストに同じ名前が無い
- イオン2館（江釣子・新潟亀田インター）。同じくリストに無く、劇場名から市区町村も引けない
  （八王子滝山は「八王子」が市名の前方一致で拾えたので解決できた）

そのぶん実際より少なめに出る。**上位都市の相対比較には使えるが、絶対数としては不完全。**

---

## 人口密度の分母を可住地面積に変えた（2026-08-25）

`toshido_scoring.py` の `add_derived()` で、`density` と `daytime_density` の分母を
**総面積（`area_km2`）から可住地面積（`habitable_km2`）に変えた**。

総面積で割ると、市域の大半が山林の市が実態よりずっと低く出ていた。

| 市 | 総面積 km² | 可住地 km² | 可住地率 | 旧密度 | 新密度 | 倍率 |
|---|---|---|---|---|---|---|
| 函館市 | 677.9 | 122.8 | 18.1% | 370 | 2,045 | 5.5 |
| 松本市 | 978.5 | 233.3 | 23.8% | 247 | 1,034 | 4.2 |
| 静岡市 | 1,411.9 | 342.7 | 24.3% | 491 | 2,023 | 4.1 |
| **京都市** | 827.8 | 218.4 | **26.4%** | 1,768 | 6,703 | **3.8** |
| 大津市 | 464.5 | 123.7 | 26.6% | 743 | 2,789 | 3.8 |

東京23区や草加市などは可住地率100%なので値が変わらない。
可住地面積は135市区すべてで取得でき、0の市区も無い。
念のため、可住地面積が無い/0の場合だけ総面積で代用するようにしてある。

この変更で 京都市 7→5位、金沢市 54→29位、静岡市 49→31位、長崎市 67→51位。
「京都も那覇もほどほど都会の印象」という利用者の感覚に近づいた。

**注意**: 可住地面積は「総面積 − 林野面積 − 主要湖沼面積」であって、
市街化区域ではない。JPC が使う「市街化区域（用途地域面積）」で割るともっと厳しくなる。

---

## `large_sc` → `large_stores`、`live_capacity2000` → `performance_venues`（2026-08-25）

利用者の指定で、**列名と実態がずれないように列名ごと差し替えた**。
どちらも旧列は最後まで空欄のままだったので、失われたデータは無い。

| 旧列 | 新列 | 中身 | なぜ変えたか |
|---|---|---|---|
| `large_sc`（大型SC数） | `large_stores`（大型小売店数） | 社会・人口統計体系 H表 `H6132`。2021年 | SC名鑑が有償で、店舗面積3万m²以上で機械的に絞れる無償データが無かった。大型小売店数なら公的統計にあり欠損0 |
| `live_capacity2000`（キャパ2000人以上のホール/アリーナ数） | `performance_venues`（興行場・興行団） | 経済センサス 第9-1A表 産業小分類 `802`。2021年 | 公的な会場DB（全国公立文化施設協会）は在るが弁別力ゼロだった（東京都4件・鳥取県2件）。産業小分類802なら欠損0で、現スコアとの順位相関0.84・最大/中央55.2 と候補中いちばん弁別力が高い |

`large_stores` は 大阪市521 / 横浜市514 / 名古屋市383 ↔ 西東京市21 / 徳島市22。
`performance_venues` は全国15,641事業所。

**意味は変わっている。** `performance_venues` は「劇場・ライブハウス・演芸場・興行団」の
事業所数であって、収容人数の閾値で数えた会場数ではない。興行団（劇団など）も入る。
`large_stores` も「店舗面積の大きい小売店」であって大型ショッピングセンターではない。

これで city_data.csv の全28指標が埋まり、**coverage は全市区 1.0** になった。

---

## 番外の参考行「東京都区部」（2026-08-25 追加）

`toshido_scoring.py` の `REFERENCE_ROWS` / `build_reference_rows()`、
アプリ側は `buildReference()` / `scoreReference()`。

### なぜ入れたか

行政区画の切り方が都市によって違う。**東京だけ「市」が無く23区に割れている**ため、
表のうえでは東京の総力が23分割されて見えなくなっていた。
一方で大阪市・横浜市などの政令市は24区・18区をまとめて1行で出ている。
同じ「区」なのに扱いが違う、という非対称がある。

実測すると、23区を1行にまとめたときのスコアは **100.41**。
135市区の1位である大阪市の 74.74 を **25点以上**引き離す。
「大阪市が1行にまとまっていてズルい」というより、
**東京が23分割されていて不当に低く見えている**ほうが実態に近い。

### 仕様

- `city_code` は `13100`、表示名は「東京都区部（23区の合計）」
- **順位にも偏差値の母集団にも入れない。** 偏差値は135市区の分布（平均・SD）のうえに
  載せて計算する。参考行を母集団に含めると135市区の偏差値が動いてしまうため
- `ranking.csv` には **rank 0** の行として先頭に出力する
- 件数の列は23区の**合計**
- 比率の列（`income_per_taxpayer_man` / `doctors_per_100k` / `clinics_per_100k` /
  `nurseries_per_1k_children` / `housing_area_m2`）は**人口で加重平均**する。
  医師数・診療所数は人口あたりなので人口加重で厳密に一致するが、
  課税所得（納税義務者あたり）・保育所（15歳未満あたり）・住宅面積（1住宅あたり）は
  **本来の分母を city_data.csv に持っていないので近似**になる。
  住みやすさ系はグループ倍率が既定0なので既定スコアには効かないが、
  倍率を上げたときはこの近似が乗る
- 派生指標（密度・昼夜間比率）は合計値から引き直す。足し合わせても意味を成さないため

`scripts/verify_app.js` はこの参考行も py と js で突き合わせる（rank 0 を別枠で比較）。

### ファイルで足す参考行（`data/reference_rows.csv`）

東京都区部は135市区のデータから合成できるが、**135市区に入っていない地域**は
外から与える必要がある。`scripts/build_reference_rows.py` が
`data/reference_rows.csv`（city_data.csv と同じ列）を作り、
`toshido_scoring.py` と アプリの両方がそれを番外行として読む。
`scripts/make_embedded.js` は埋め込み版にこの CSV も同梱する。

**`TARGETS` は既定で空**にしてある。特定の区を載せると作成者の生活圏が分かるため、
公開物には個別の区を入れない方針。手元で見たいときだけ一時的に足し、
**`data/reference_rows.csv` を消してからデプロイする**
（`scripts/deploy.py` は `public/` を作り直すので、消し忘れるとそのまま公開される）。

| 取り方 | 列 |
|---|---|
| 区の行がそのまま在る | 人口・昼間人口・面積・可住地面積・従業者数・小売販売額・図書館数・大型小売店数・住宅面積・医師数・診療所数・保育所数・バー/スナック・興行場 |
| 区単位で集計し直せる | 鉄道駅数（stations.csv は元から区コード）・乗降客数（S12×N03 を市に寄せる前）・スタバ（`address_2` が「○○市○○区」の形）・無印/ロフト/ハンズ・大型家電・バーガーキング・百貨店（住所から解決） |
| **取れない（空欄）** | 牛丼3社・映画系5指標・博物館2指標・一人あたり課税所得 |

**取れない列は空欄のまま**にしてある。欠損は「使える指標だけで重みを再正規化」して
吸収されるので比較はでき、そのぶん coverage が下がって信頼度が表に出る。

親市の値を人口シェアで按分して埋める案も試したが、**やめた**。
按分値がちょうど135市区の中央値あたりに来るため偏差値50前後になり、
再正規化した場合とほとんど変わらない（試した区では 49.38 → 48.99 と**むしろ下がった**）。
推計値を入れて coverage を 1.0 に見せかける利点が無い。

百貨店だけは明細を残していないので `build_reference_rows.py` が
日本百貨店協会のページを取り直す（1リクエスト）。

### 分割しないことにした理由

逆に政令市を区に割る案も検討したが、見送った。
28指標のうち21は区単位で取れる（社会・人口統計体系も経済センサスも区の行を持っていて
欠損ゼロ。鉄道駅にいたっては元が区単位で、いま市に集約している）。
**しかし映画系5指標と博物館2指標が取れない。**
映画上映活動年鑑も文化庁の博物館リストも市区町村欄が「大阪市」止まりで区の表記が無い。
分割すると大阪市の81スクリーン・ミニシアター7がまるごと欠損になり、
このランキングの主軸である映画の軸が政令市20市で全滅する。

---

## 駅の乗降客数 `passengers_per_day`（2026-08-25 追加）

`scripts/fetch_passengers.py`。国土数値情報 S12（駅別乗降客数 S12-23）を
N03（行政区域）に空間結合し、市区町村別に合計する。
政令市の区は市に寄せる（`rail_stations` と同じ扱い）。

### なぜ駅数と別に要るのか

**`rail_stations` との順位相関は 0.31 しかない。**
駅がいくつあるかと、その鉄道が実際に使われているかは別の話で、
路面電車の停留所が多い市は駅数だけが膨らむ。

| 市区 | 駅数 | 乗降客数（人/日） | 駅あたり | 自家用車のみ率 |
|---|---|---|---|---|
| 高知市 | 67 | 38,910 | 581 | 54% |
| 福井市 | 44 | 31,042 | 706 | 74% |
| 旭川市 | 16 | 6,890 | 431 | 66% |
| **渋谷区** | 19 | 3,127,179 | **164,588** | 5% |

弁別力は 最大/中央 = 42倍（`rail_stations` は12倍）。
大阪市 8,989,358 ↔ 旭川市 6,890 で **1,300倍**の開きがある。
既存指標で一番かぶるのは `daytime_density`（0.86）と `car_only_pct`（−0.85）。

### 重複コードの扱い（唯一の落とし穴）

S12 は「路線ごとの線分」なので1つの駅が事業者・路線の数だけ行を持つ。
そのうえで **重複コード（2022年度は `S12_050`）が 1 の行だけが採用すべきレコード**で、
2・3 は他の行と同じ数字が載っている重複行。仕様書の言い方では
「複数路線の駅において、一番中心に近い駅にのみデータを付加」。

これを無視して全行を足すと、新宿駅の山手線 585,262 を4回数えることになる。
採用は 7,769 / 全 10,500 レコード、全国合計 108,943,902 人/日。

なお重複コード 2 のまま残る事業者（新宿駅の都営新宿線・大江戸線など）は集計から落ちる。
そのぶん実際よりやや少なめに出るが、全国で同じ扱いなので順位の比較には使える。

### その他の罠

- 乗降客数の列は `S12_009`（2011年）から**4つおき**。最新は `S12_053`（2022年）。
  年度が増えると列番号がずれるので、列の存在を確かめてから使う
- zip 内に `UTF-8/` と `Shift-JIS/` の2組が入っているが、
  **UTF-8 側でも `.cpg` が実態と合っておらず**、geopandas が latin-1 で読んでしまう。
  `encoding="utf-8"` を明示する
- 最近傍で補完するときは投影座標系（EPSG:3857）に移してから。
  地理座標のままだと `sjoin_nearest` の距離が狂う
- **N03（603MB）が必要**。以前「再実行するときだけ再取得」として消していたが、
  この列のために取り直した。`data/raw/geo/` に展開してある

### 採用しなかったもの

- **電車の運行本数**: 「全国鉄道運行本数データ」（西澤明／地域・交通データ研究所、
  CC-BY 4.0、`https://gtfs-gis.jp/railway_honsu/`）に駅別発着本数がある。
  2026年版・9,416駅・欠損0で集計もできたが、**乗降客数との相関が 0.82** で冗長。
  広島市が本数65,193（全国5位）なのに乗降客660,309と、路面電車が本数を押し上げる癖もある。
  個人作成のベータ版データという点でも S12 のほうが固い
- **自動車保有台数**: 市区町村別は有償（自検協の統計書が印刷6,930円/電子52,360円）。
  代替として国勢調査の「自家用車のみ」通勤率を `scripts/fetch_car_usage.py` で
  取得してあるが（`data/raw/car_usage.csv`、欠損0）、
  **人口密度と −0.94、`housing_area_m2` と 0.91** で既存指標のほぼ複製のため列にしていない
- **学校数**: 社会・人口統計体系 E表にあり欠損0だが、生の件数は人口と0.68、
  可住地あたり密度にすると人口密度と0.94。どう正規化しても既存とかぶる
- **公演数**: 市区町村別のデータが流通していない。ぴあ総研の白書はデータ編が
  11万円（標準版）/50万円（詳細版）で、しかも公演ごとの動員数は非公表・
  市区町村別の内訳も明記されていない。全国公立文化施設協会の調査は集計済みで施設別が無い。
  `performance_venues`（経済センサス小分類802）が実質の代替

---

## バーガーキングの取り方 `burger_king`（2026-08-25 追加）

`scripts/fetch_burgerking.py`。全国373店舗（37都道府県）。
住所から市区町村コードへの解決は**全件成功**（未解決0）。
対象135市区の合計は257店で、**31市区が0店**。

### 公式サイトは SPA で HTML からは取れない

`burgerking.co.jp` は Vue の SPA（bizMOB Xross 製）。
`/store` も `sitemap.xml` も `robots.txt` も**同じ3KBのシェルを返す**。
吉野家・松屋で使った NAVITIME 製の店舗検索も無い。

店舗一覧は次の1本で取れる。

    POST https://www.burgerking.co.jp/burgerking/BKJ0302.json
    Content-Type: application/x-www-form-urlencoded
    message=<JSON文字列>

JSON は `{"header": {...,"trcode":"BKJ0302"}, "body": {...}}` の形。
レスポンスは `body.data`（配列）と `body.dataCount`（総件数）。
店舗の住所は `storAddr`、店名は `storNm`、店舗コードは `storCd`。

### body の必須項目（ここを外すと分かりにくいエラーになる）

| キー | 値 | 外すとどうなるか |
|---|---|---|
| `tpSearchStore` | `"03"` | 03 = すべての店舗。01 は現在地の近くだけ |
| `searchKeyword` | `""` | 空で全件 |
| `storeServiceCode` | `[""]` | 空文字1つの配列 |
| `sort` | `"02"` | |
| `page` / `dataCount` | 1始まり / 1ページの件数 | 「リクエストされた照会区分は、page, dataCountが必須項目です」 |
| `xCoordinates` / `yCoordinates` | 経度 / 緯度 | **「CRM API連動中エラーが発生しました」**。全件検索なのに座標が要る（距離計算のためだけ） |

座標が無いときのエラーメッセージがまったく無関係な文言なので、ここが一番はまる。

`dataCount` は文字列で返ってくるので、ページングの判定で `int()` に通す必要がある。

### エンドポイントの突き止め方

`js/JP_INT.js` に trcode（`BKJ0302`）と body の形は書いてある。
しかし**エンドポイントの URL は静的解析では当たらなかった**。
`bizMOB-webExtend.js` の `requestTr` は `{_sContext}/{trcode}.json` を組み立てており、
`bizMOB-core.js` の config は `_sContext: "/proxy.server"` なのだが、
実際に叩かれるのは `/burgerking/BKJ0302.json` で `proxy.server` が入らない
（config が実行時に差し替えられている）。

**Playwright で `/store` を開いて実際のリクエストを1回観察して確定した。**

    uv run --with playwright python -m playwright install chromium

観察するときの注意:
- 位置情報の許可モーダル（`.modalWrap`）がクリックを遮る。
  `browser.new_context(permissions=['geolocation'], geolocation={...})` を渡して回避する
- 「すべての店舗」タブは Playwright の `click()` だと要素が重なって届かないことがある。
  `page.evaluate()` で DOM を直接クリックすると通る
- 初期表示は `tpSearchStore=01`（現在地の近く）で、
  「すべての店舗」を押して初めて `tpSearchStore=03` が飛ぶ

### 指標としての性格

一番かぶるのは `passengers_per_day`（0.74）、次が `fastfood_big3`（0.64）。
駅前立地のチェーンという性格がそのまま出ている。
一方で `bars_snacks` とは 0.08、`mini_theater` とは 0.14 とほぼ無関係。

上位は 大阪市20 / 横浜市19 / 神戸市9 / 名古屋市9 / さいたま市7 で、
**東京23区は最大でも新宿区6**。関西・関東の駅前に偏っていて、
全国2,781店の牛丼3社（すべての市区に在る）とは分布がかなり違う。
