個人開発で電車遅延予測アプリを作っている。前回の記事で「来週やることは、新しいコードを書くことではなく、データを貯めて検証すること」と書きました。今回はその検証週の報告です。

ただし最初にお断りを。7月1日から、公共交通のオープンデータを使ったコンテストが開幕し、私も参加を決めました。そのため今回から、アプリの手の内にあたる部分──どの路線で・どんな数値の・どんなパターンを見つけたか──は、応募が終わるまで伏せて書きます。その代わり、初学者として検証で何にハマり、何を学んだかは、これまでどおり正直に書きます。

Contents

まず結論

検証を始めて最初に壊れたのは、アプリの予測ではなく「自分の思い込み」のほうでした。この1週間で、初学者がデータ検証でハマる罠を、見事に3つ踏みました。

  • あり得ない異常値を、そのまま信じかけた
  • 「記録が無い」を「少なかった」と読み違えかけた
  • 2日一致しただけで「毎回同じだ」と言いかけた

そして週の終わりには、手元で集計した実測データが公開URLのアプリで動くところまで到達しました。順番に書きます。

罠①:あり得ない数字は、まず「保留」にする

数日分の遅延データを並べて眺めていたら、ある日の午前に、現実の遅れとしてはあり得ない規模の数字が並んでいました。

ここで初学者がやりがちなのは、「大きい数字=大事件があった」と物語を作ってしまうことです。でも可能性は2つあります。本当に大規模な運転見合わせがあったのか、それとも収集プログラム側のバグでデータ自体が壊れているのか。この時点ではどちらか分かりません。

だから結論は「保留」。その日の朝のデータは、白黒つくまで集計から外しました。判別できないものを判別できないと言うのも、検証のうちなのだと思います。

罠②:「欠測」を「ゼロ」と読み違える

これが今週いちばん反省した話です。ある日の夕方だけ、遅延がほとんど記録されていない日がありました。「この日の夕方は平和だったんだな」と読みかけて、ハッとしました。

その日の夕方は、収集していたMacがスリープして、記録そのものが止まっていた時間帯だったのです。

つまり「遅延が少なかった」のではなく「そもそも観測していなかった」。データが無いことには、「本当に無かった」と「見ていなかった」の2種類があります。この2つを区別せずに集計すると、静かに間違った結論が出ます。この日のデータは「欠測」として、比較対象から明示的に外すことにしました。

罠③:2日一致しただけで「型を掴んだ」と思い込む

時間帯ごとの遅れ方に、あるパターンがありそうだと感じていました。実際、2日連続で同じ動きをしたので、「これは毎回同じだ」と言いかけていました。

ところが日数を増やして見直すと、明確な反例の日が見つかりました。4日中、仮説どおりだったのは2日だけ。「2日一致は幸先が良い」と喜んでいたのは、早計だったわけです。

少数のデータを法則だと思い込む──言葉では知っていた罠に、自分もしっかりハマりました。パターンは「見つけた」あとに「疑って壊しにいく」工程までがセットなのだと、身体で覚えた形です。

「物差し」を先に作る、という考え方

検証と並行して、精度を測る仕組みも作り始めました。ここで教わって腑に落ちたのが「ベースライン」という考え方です。

いきなり自分の予測の精度を測るのではなく、まず「何も工夫しない、いちばん素朴な予測」の誤差を測っておく。自分のモデルは、その素朴な予測に勝って初めて「改善した」と言えます。物差しなしの改善は「動いた」で終わってしまう──今の自分に一番刺さる言葉でした。

そして、公開までこぎ着けた

週の終わり、手元のターミナルの中にしかなかった実測の集計結果を、公開URLのアプリに組み込みました。夜、スマホで開いた画面に、朝まで手元にしかなかった数字が表示されたときは、静かに感動しました。

「実測データで分析した」と「公開アプリが実測データで動いている」は、一文字違いのようで大きな差です。コンテストの過去の入賞作を調べると、共通するのはデータ量と、精度を数字で証明したこと、そして公開されていることでした。細部は書けませんが、その土俵に足をかけた1週間だったと思います。

おわりに ── 検証とは、思い込みを壊す作業だった

検証フェーズに入る前は、「予測が当たるかを確かめる作業」だと思っていました。実際にやってみると、最初に検証されたのは予測ではなく、自分の読み方のほうでした。

異常値を保留にする。欠測とゼロを区別する。少数の一致を法則と呼ばない。どれも地味ですが、この地味さの先にしか「アドバイザー」は育たないのだと思います。

応募までの間、収集は止めずに続けます。手の内が明かせるようになったら、伏せた部分もまとめて書くつもりです。


Python / データ検証 / 個人開発

このブログでは、ローカルLLM・Aider・個人開発の試行錯誤をそのまま記録しています。