はじめに
あまりtwitterでは公言していませんでしたが、鉄道のダイヤについて調べるのが結構好きです。特に縁あって小田急のダイヤを研究対象としていました。
ダイヤを分析して思ったことを本来は大学のサークル誌などに載せて文化祭を通じて発表したかったところなのですが、昨今の情勢でその機会が無くなってしまったので、このブログを通じて発信しようと思います。
概要
一文で言うと、列車の時刻データ(今回は小田急の列車)を扱いやすいjsonデータ形式に変換し、ダイヤの性質について考察することを行いました。
昔は時刻表をちまちまと読みながら性質を書きだしていたのですが、莫大な時間と手間がかかり、間違いも多いので何かプログラミングで自動化できないかなあと考えました。
他にも列車のjsonデータでの表し方はネットに転がっていますが、あくまで個人的に扱いやすいデータを作ります。
形式
まずは列車データ。
train =
{
"num": "2221",
"type": "急行",
"day": "土曜・休日のみ運転 ",
"dep": "北綾瀬",
"ter": "向ヶ丘遊園",
"timedata": [
[
"北綾瀬",
"",
"1610"
],
…
[
"向ヶ丘遊園",
"1713",
""
]
]
}
train["timedata"]は停車駅の時刻データが入ったリストのリストです。通過駅は入れません。
次に駅データ。
[
{
"id": 0,
"name": "新宿",
"up": -1,
"down": 1
},
{
"id": 1,
"name": "南新宿",
"up": 0,
"down": 2
},
…
駅にidを振り、上り(下り)方向に進んだときの次駅を記します。
乗り換え駅の場合は次のようになります。
shinyurigaoka=
{
"id": 22,
"name": "新百合ヶ丘",
"up": 21,
"down": [23,67]
},
新百合ヶ丘の場合は,下り方向が2駅になります.このときshinyurigaoka["down"]はリストになります。
新宿駅のようにある方向の次駅がない場合は-1を入れます。
データ収集
データ量が膨大なのでの手打ちは非常に面倒です。そこでOuDiaの手法のようにトレたびからスクレイピングする方法をとります。
詳しい方法は割愛します。サーバーに負荷をかけないよう注意してください。
で、問題なのは、データそのままを引っ張ってきても扱いにくいことです。
生のデータでは扱いにくい点を列挙します。
千代田線直通列車の場合、列車番号が千代田線のものが描かれています。小田急の列番は備考に書かれています。列番が他社のであると小田急の列番特有の法則が使えないので不便です。
これは悩みましたが、手打ちの修正で乗り切りました。ツカレタヨ……。
列車が平日/土休の区切りではない場合ある
トレたびの列車データは、時刻表のように平日/土休で列車情報が分かれていなく、運転日のタグづけがされているだけです(「平日のみ」「土曜・休日のみ」「運転日:~日」など)。パターンダイヤでも、たいていの列車は平日/土休で時刻か列番が異なるので列車が分けられるのですが、まれに平日/土休で時刻も列番も全く同じ列車が存在します。この場合「毎日運転する」一つのデータしかWeb上にはありません。
平日/土休それぞれの列車データを作るには、このような列車のデータを修正してやる必要があります。
化ける列車の種別の扱い
客扱いを継続したまま列車種別を変更する列車、いわゆる「化け列車」です。種別がA→Bと化ける場合、トレたびの種別欄にはAまたはB1のどちらか一つの種別のみが書かれます。このままでは化けの有無の見分けがつかず、データとして扱いづらいです。
そこで次のルールを定めます。A→Bと種別が化ける場合、
- 化け列車の列車データのtypeキーの値はA,Bのうち上位の種別とする。
- noteキーを追加し、停車駅についての注釈を書く。
書いた注釈の一覧は次のようになります。
"note": "開成停車"
"note": "新百合ヶ丘以西各駅停車"
"note": "相模大野以西各駅停車"
"note": "多摩線内各駅停車"
"note": "開成停車"
"note": "江ノ島線内急行"
"note": "新百合ヶ丘以西各駅停車"
"note": "開成~小田原停車"
"note": "多摩線内各駅停車"
"note":"多摩線内列番切替"
化け種別に加え、途中で列番が変わる通勤急行も加えました。
注釈は手打ちでもいいのですが、せっかくなので自動化します。
例えば、
for train in trains:
num = int(train["num"])
if num >= 1000 and num < 4000:
stas = [td[0] for td in train["timedata"]]
if "南林間" in stas and not("向ヶ丘遊園" in stas):
train["note"] = "江ノ島線内急行"
print("note added", train["type"], train["num"], train["day"])
といった具合で書きます。
if num >= 1000 and num < 4000:
の部分で、種別を急行・快速急行・通勤急行に絞り、
if "南林間" in stas and not("向ヶ丘遊園" in stas):
の部分で化け列車(南林間に停まり向ヶ丘遊園に停まる列車種別は存在しない)、かつ江ノ島線では急行、小田原線では快速急行or通勤急行となる列車に絞ります。ただし、通勤急行は化けないので江ノ島線内急行、小田原線内快速急行の列車データのみを抽出できます。
特急ロマンスカーのスクレイピングしたままのデータを見ます。
{
"num": "0021",
"type": "特急 はこね 21号",
"day": "土曜・休日と9月24・29日・10月6・13・16・20・28日運休 ",
"dep": "新宿",
"ter": "箱根湯本",
"timedata": [
[
"新宿",
"",
"1320"
],
…
……とまあ、非常に扱いづらいです。
運転日は滅茶苦茶だし、種別には相性と号数が入り組んでるし……もう発狂したくなりますw
今のところは特急列車はあまり興味がないので、データの整形はは一旦保留とします。
また気が向いたら書こうと思います。
おわりに
列車の時刻データをプログラミングで扱いやすくするために、jsonでの表現法を考えました。また、生のデータから扱いやすいデータにするための方法・感想を記しました。
今回書いた作業を行うだけでも、「化け列車が平日と土休日に何本あるか?」といったような事が、時刻表とにらめっこせずとも簡単に調査できるようになりました。
もちろんこの記事で終わりではなく、「そもそもこんな形式を考えて何をしたいんだ?」という疑問に答える必要があります。また、「集めたデータに間違いがなく、信頼できるか?」という疑問も残ります。が、今回はいったん記事を区切り、改めて書いていこうと思います。