Skip to content

公開GTFS時刻表から速度較正テーブルを自動生成するスクリプトを追加 - #1592

Merged
TinyKitten merged 5 commits into
devfrom
claude/eta-estimation-accuracy-j0kfdt
Jul 5, 2026
Merged

公開GTFS時刻表から速度較正テーブルを自動生成するスクリプトを追加#1592
TinyKitten merged 5 commits into
devfrom
claude/eta-estimation-accuracy-j0kfdt

Conversation

@TinyKitten

@TinyKitten TinyKitten commented Jul 5, 2026

Copy link
Copy Markdown
Member

概要

速度較正テーブル(#1591)のフォローアップ。公共交通オープンデータセンター等の公開GTFS時刻表から路線×種別ごとの実効最高速度を自動較正する scripts/compute_speed_table.py を追加する(compute_average_distance.py と同じ validate/apply パターン)。較正結果として函館市電・横浜市営地下鉄ブルーライン(快速)・京都市営地下鉄東西線ぶんを収録。

変更の種類

  • バグ修正
  • 新機能
  • データの修正・追加
  • リファクタリング
  • ドキュメント
  • CI/CD
  • その他

変更内容

  • scripts/compute_speed_table.py(新規): GTFS の stop_times から平日日中の列車ごとの所要時間を取り、arrival_estimation.rs の運動学モデル(迂回係数較正・通過ペナルティ・運転余裕率込み)を Python で再現して、実ダイヤ所要時間の中央値を再現する実効最高速度を二分探索でフィッティングする
    • 停留所は駅名正規化+座標(名称一致500m / 最近傍救済200m)で自リポジトリの駅データへ名寄せ、路線は停車駅一致率で自動判定
    • 停車パターンを 5!station_station_types の種別グループと照合して kind を判定(全駅停車は Default)
    • 一般則(路線種別×種別倍率)から±10%以上乖離した路線のみ出力。サンプル3本未満・フィット範囲外は見送り
    • GTFS キャッシュは一時ファイルへ書いて ZIP 検証後に os.replace で原子的に確定し、非 ZIP 応答(エラーボディ)を恒久キャッシュしてしまう事故を防ぐ
  • speed_table.rs: 自動生成ブロック(LINE_SPEED_OVERRIDES_GTFS、マーカー間をスクリプトが再生成)を追加。手動テーブルと重複するキーはスクリプト側で除外し、lookup は手動テーブル優先(キー衝突時に手動値が返ることの回帰テストも追加)
  • 較正結果:
    • 函館市電2系統 20km/h・5系統 25km/h(併用軌道の実勢。一般則の路面電車 40km/h では GTFS 実ダイヤ(全区間中央値47〜48分)に対し所要時間を40〜50%過小評価していた)
    • 横浜市営地下鉄ブルーライン 快速 65km/h・京都市営地下鉄東西線 65km/h(いずれも一般則 75km/h。ODPT トークン認証フィードから較正)
  • .gitignorescripts/.gtfs_cache/(GTFSキャッシュ)と __pycache__/ を追加

フィード構成とライセンス:

フィード 認証 ライセンス
函館市電 不要 公共交通オープンデータセンター(認証なし公開)
京都市営地下鉄 ODPT_ACCESS_TOKEN 必要 公共交通オープンデータ基本ライセンス(要出典明示)
横浜市営地下鉄 ODPT_ACCESS_TOKEN 必要 同上

トークンは https://developer.odpt.org/ で無料発行できます。京都・横浜ぶんの較正エントリは本PRに収録済みです(基本ライセンスのフィードを使うため、アプリのクレジット表記への出典追加が必要)。なお東武・京王のGTFSは「オープンデータチャレンジ限定ライセンス」のため対象外にしています。

テスト

  • cargo fmt --all -- --check が通ること
  • cargo clippy -- -D warnings が通ること
  • cargo test(SQLX_OFFLINE=true)が通ること

--apply を2回実行して出力が冪等であること、生成ブロックのエントリが lookup されることの単体テストも確認済み。

関連Issue

スクリーンショット(任意)

🤖 Generated with Claude Code

https://claude.ai/code/session_01TsvFBx2rLj486tvj64M9eP


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • 路線ごとの速度設定に、公開時刻表から自動生成された補正値が反映されるようになりました。
    • 速度テーブルの自動生成・更新を行うコマンドが追加され、結果の確認と反映を選べます。
  • Bug Fixes

    • 既存の手動設定を優先しつつ、自動生成分も順に参照するよう改善しました。
    • キャッシュや一時生成物が管理対象に入りにくくなりました。

claude added 2 commits July 5, 2026 08:26
compute_average_distance.py と同じ validate/apply パターンで、公共交通
オープンデータセンター等の GTFS フィードから路線×種別ごとの実効最高速度を
較正する scripts/compute_speed_table.py を追加する。

- GTFS の stop_times から平日日中の列車ごとの所要時間を取り、駅名正規化+
  座標(500m/最近傍200m)で自リポジトリの駅データへ名寄せする
- 停車パターンを station_station_types の種別グループと照合して kind を判定
- arrival_estimation.rs の運動学モデル(迂回係数較正・通過ペナルティ・
  運転余裕率込み)を Python で再現し、実ダイヤ所要時間の中央値を再現する
  実効最高速度を二分探索でフィッティングする
- 一般則(路線種別×種別倍率)から±10%以上乖離した路線だけを
  speed_table.rs の自動生成ブロック(手動テーブルと重複するキーは除外、
  手動テーブル優先で lookup)へ書き込む

フィード構成: 函館市電(認証不要)、京都市営地下鉄・横浜市営地下鉄
(要 ODPT_ACCESS_TOKEN、https://developer.odpt.org/ で無料発行)。
初回適用として函館市電の較正結果を収録: 市街地併用軌道の実勢に合わせ
2系統 20km/h・5系統 25km/h(一般則の路面電車 40km/h では所要時間を
40〜50% 過小評価していた)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsvFBx2rLj486tvj64M9eP
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsvFBx2rLj486tvj64M9eP
@TinyKitten TinyKitten self-assigned this Jul 5, 2026
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

ODPT公開GTFS時刻表から路線×列車種別ごとの実効最高速度を較正するPythonスクリプトscripts/compute_speed_table.pyを新規追加し、Rust側speed_table.rsに自動生成テーブルLINE_SPEED_OVERRIDES_GTFSを追加、line_speed_override_kmhが手動テーブル優先でGTFSテーブルへchainするよう変更。.gitignoreにキャッシュディレクトリを追記。

Changes

GTFSベースの速度較正パイプライン

Layer / File(s) Summary
キャッシュ除外設定
.gitignore
scripts/.osm_cache/, scripts/.gtfs_cache/, __pycache__/をgitignoreに追記。
運動学モデルと基礎定数
scripts/compute_speed_table.py
Feedデータクラス、基準速度/一般則速度、haversine距離、区間走行・停車込み所要時間モデルを実装。
自リポジトリデータ読込と迂回係数推定
scripts/compute_speed_table.py
路線/駅/種別グループCSVを読み込み、正規化駅情報とkindマッピングを構築し、迂回係数を推定。
GTFS取得と駅・路線対応付け
scripts/compute_speed_table.py
ODPTからGTFS ZIP取得、CSV読込・時間パース・平日service抽出、座標/名称一致で駅対応付け、line_cd探索。
種別分類とv_max二分探索
scripts/compute_speed_table.py
停車集合をkindへ分類し、中央値残差ゼロとなるv_maxを二分探索で推定。
Calibration集計本体
scripts/compute_speed_table.py
各tripからline_cdを特定し単調進行サンプルを抽出、v_fit・v_rule・観測中央値等を集計。
Rust側テーブル書き換えとCLI
scripts/compute_speed_table.py
BEGIN/ENDブロック書き換え処理と--validate/--applyオプション、ODPT_ACCESS_TOKENを用いたCLI制御を実装。
Rust自動生成テーブルとlookup優先順位
stationapi/src/domain/speed_table.rs
LINE_SPEED_OVERRIDES_GTFS定数とBEGIN/END生成ブロックを追加し、line_speed_override_kmhを手動優先でchain参照に変更、対応テストを追加。

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • TrainLCD/StationAPI#1572: line_speed_override_kmhのlookupに使われる速度テーブル・迂回係数ロジックを同様に扱っている点で接点がある。

Suggested labels: feature

Poem

ぴょんと跳ねて時刻表めくる
GTFSの速さ、拾い集めて
二分探索でv_maxさがす
手動テーブル優先、忘れずに
自動生成ブロック、静かに更新
うさぎも一息、キャッシュは.gitignore へ 🐇🚃

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed PRタイトルは主要変更であるGTFS時刻表から速度較正テーブルを自動生成する追加を適切に要約しています。
Description check ✅ Passed 必須の概要・変更種類・変更内容・テストが揃っており、テンプレート要件を概ね満たしています。
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/eta-estimation-accuracy-j0kfdt

Comment @coderabbitai help to get the list of available commands.

@TinyKitten

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/compute_speed_table.py`:
- Around line 269-287: In fetch_feed, the cache file is written directly and the
returned ZipFile is never closed, so a non-ZIP error response can be cached
permanently and keep causing BadZipFile failures. Update fetch_feed to write
into a temporary file, validate it as a ZIP before committing, then atomically
move it into CACHE_DIR with os.replace; also ensure callers such as main use a
with block around the ZipFile returned from fetch_feed so the handle is always
closed.

In `@stationapi/src/domain/speed_table.rs`:
- Around line 123-129: The gtfs_generated_entries_are_looked_up test only checks
presence via line_speed_override_kmh(...).is_some(), so it does not verify that
manual entries win when the same (line_cd, kind) exists in both manual and
GTFS-generated tables. Update this test in speed_table.rs to cover the
precedence rule by choosing or constructing a duplicate-key case and asserting
the manual-path value is returned by line_speed_override_kmh, using the existing
line_speed_override_kmh and gtfs_generated_entries_are_looked_up symbols to
locate the logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5d1e38e1-1b3c-45d6-98f2-79e5cfb489d9

📥 Commits

Reviewing files that changed from the base of the PR and between 54b953c and d54e7ec.

📒 Files selected for processing (3)
  • .gitignore
  • scripts/compute_speed_table.py
  • stationapi/src/domain/speed_table.rs

Comment thread scripts/compute_speed_table.py
Comment thread stationapi/src/domain/speed_table.rs
一時ファイルへ書いてZIP検証後に os.replace で確定し、ZipFile は with で
クローズする。あわせて手動テーブル優先の lookup を回帰検知するテストを追加。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsvFBx2rLj486tvj64M9eP
@TinyKitten
TinyKitten merged commit bc9c116 into dev Jul 5, 2026
11 checks passed
@TinyKitten
TinyKitten deleted the claude/eta-estimation-accuracy-j0kfdt branch July 5, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants