電車の遅延は「地震」で予測できるのか? ── 個人開発で見つけた”震度3の壁”

個人開発で電車遅延予測アプリを作っている、病院SEの開発記録です。今週、データがひとつの小さな事実を語り始めました。


Contents

まず結論

今週、自作の電車遅延予測アプリの開発で、ふたつの手応えがありました。

  • 「どの駅間で遅延が発生したか」を、同じ電車を追いかけることで特定できると分かった
  • 「東京で震度3を超えると、電車は遅れやすくなる」という最初のパターンを、データから掴んだ

どちらも、賢いアルゴリズムをひらめいたわけではありません。地味にデータを貯めて、地味に差分を見ただけです。そして、その「地味さ」こそが個人開発の武器なのだと、今週あらためて思いました。順番に書いていきます。


なぜ電車の遅延を「予測」したいのか

私が作っているのは、ただの遅延案内アプリではありません。名前は「電車遅延アドバイザー」。目指しているのは、「今、目の前に来た電車に乗るべきか、1本待つべきか」を助言してくれる相棒です。

「◯◯線は遅延しています」と表示するだけなら、それは”状態表示アプリ”です。私が欲しいのは、混雑や遅れの**型(パターン)**を知っていて、「この時間のこの駅なら、1本待った方が空いてますよ」と言ってくれる”アドバイザー”の方でした。

そのためのデータは、都営地下鉄が公開している運行情報API(ODPT)から取っています。都営地下鉄は、列車ごとに「どの列車が」「どの駅とどの駅の間にいて」「何秒遅れているか」まで取れるのが強みです。これを90秒ごとに収集し、ファイルに記録し続けています。


最初にぶつかった壁 ──「今の遅延」しか分からない

データを眺めていて、ひとつ困ったことに気づきました。

APIが返す「遅延」の数字は、その電車が”今”何秒遅れているか、という累積値なのです。たとえば、ある駅で2分遅れた電車は、その先のどの駅でも「2分遅れ」と表示され続けます。つまりスナップショット1枚を見ても、最初に遅れが生まれた場所(原因の場所)は分からない

これは初学者向けに言い換えると、こうです。

データは「今の症状(何秒遅れ)」は教えてくれるが、「いつ、どこで熱が出始めたか(発生源)」は教えてくれない。

ここで一度、「やっぱり1枚のデータじゃ無理か」と諦めかけました。


同じ電車を「追いかける」と、景色が変わった

転機は、こう考え直したことでした。1枚の写真では分からないなら、同じ電車を時系列で並べてみればいい。

列車には固有の番号が振られているので、同じ番号を時間順に並べると、こうなります。

09:00:00  列車A  三田→大門     遅延=0秒
09:01:30  列車A  大門→新橋     遅延=0秒
09:03:00  列車A  新橋→東銀座   遅延=180秒  ← ここで初めて遅れた

遅延が 0 → 180 に変わった瞬間の駅間。そこが「遅延が生まれた区間」です。やっていることは、累積の数字を差分(diff)で見るだけ。たったそれだけで、「原因の場所は分からない」が「発生した区間は特定できる」に変わりました。

もちろん限界もあります。90秒ごとの収集なので「秒単位の到着タイミング」までは絞れず、特定できるのは「この駅とこの駅の間」までです。また、他社線への直通運転で列車番号が切り替わる境界駅をまたぐと、追跡が途切れます。でも、何が分かって何が分からないかをはっきりさせること自体が、設計では大きな前進でした。


もうひとつの切り口 ──「地震」

電車を遅らせる原因は、混雑や人身事故だけではありません。地震もそのひとつです。

そこで今週、運行情報に加えて地震情報も収集するスクリプトを足しました。そして「地震の前後で、電車の遅れはどう変わったか」を突き合わせる小さなプログラムを、試行錯誤しながら3回作り直しました。

その結果、データがひとつの線を引いてくれました。

東京で震度3を超えると、遅れが出やすくなる。

震度1や2では、目立った影響は見えにくい。けれど震度3を境に、遅延の出方が変わる気配がある。もちろんまだ”発見の入り口”で、これからデータを貯めて検証していく段階です。それでも、「なんとなく地震で遅れる気がする」という体感が、自分の手元のデータで初めて数字になった瞬間は、素直に嬉しいものでした。


戦国武将に、設計思想を教わった話

少し脱線します。今週、戦国時代の軍師・竹中半兵衛について調べる機会がありました。彼が16〜18人で主君の居城を一夜で乗っ取ったという逸話(後世の創作も多いとされますが)で、鍵になったのは事前の情報でした。

伝承によれば、半兵衛は城の夜警の当番スケジュールを事前に把握し、「この6日間はこの人が当番」という”時間の型”を読んで、最も隙が大きい最終日を選んだといいます。

ここで膝を打ちました。半兵衛が勝てたのは「今、誰が警備しているか」という一瞬の情報ではなく、「6日間の当番ローテーション」という型を読んだからです。これは、私のアプリにそのまま当てはまります。

  • スナップショット1枚(今の遅延)では、アドバイザーになれない
  • 時間をかけて貯めたパターン(型)を持って、初めて「待つべき」と助言できる

「アドバイザー(軍師)」を名乗るなら、一瞬の位置より、貯めた型で勝負しなければならない。歴史の話が、こんなに自分の設計とつながるとは思いませんでした。

そしてもうひとつ。半兵衛の戦法には「敵の進路を読んで兵を伏せる」ものもありましたが、史料には「兵を伏せた場所を敵が通らない可能性もある」と書かれています。読みは外れるのです。だから私のアプリも、予測は外れる前提で設計し、確信が持てないときは断定せず「保留(HOLD)」を返すようにしています。


今週、自分に課しているルール

ここまでの開発を通して、いくつかの方針が自分の中で固まってきました。個人開発の初学者として、迷ったとき立ち返る軸です。

  1. 判断を先に、精度を後に。 まず「待て/乗れ」が論理として正しく動くことを優先し、人数や時間の正確さは後から積み上げる。
  2. 実データに従う(推測で作らない)。 終点の折り返しも、駅間の所要時間も、「こうだろう」と仮定せず、収集済みのデータを覗いてから設計する。推測で作るとバグる。
  3. 動いた、で終わらせない。 各ステップで一度だけ「なぜ動いたのか」を自分に問う。
  4. 記録する一行を、最初から入れておく。 「取得して表示」で終わらせず、タイムスタンプ付きで保存する一行を最初から仕込む。後から「記録しておけば…」と思っても、過去のデータは二度と取り返せない。

特に4番は、今週の地震の発見を支えてくれた習慣でした。


おわりに ── 来週やること

今週でアプリのコードはひと通り出揃いました。なので来週やるべきことは、新しいコードを書くことではありません

毎朝の通勤時に収集を起動し、データを貯めて、検証すること。震度3の壁も、混雑の型も、データ量が増えて初めて精度が上がります。半兵衛が6日間の当番を読んだように、私はこれからしばらく、データが型を見せてくれるのを待つ番です。

派手な機能追加より、地味な記録と検証。それが、個人開発で”アドバイザー”を育てる正しい順番なのだと思います。


この記事は、個人開発の週次記録としてまとめたものです。アプリのコードはGitHubで公開しながら、少しずつ育てています。