👻

東京都の地下鉄駅データを、隣駅が分かるように加工する

2024/12/15に公開

「画面を見ないでできる」「電車にまつわる」シンプルなゲームを作ることにしました。
その準備として、東京の地下鉄駅のデータを整理してみます。

データ入手

駅データ.jpさんのデータがとても便利でした。
無料版を使わせていただきました。

ゴール

とりあえず、隣り合う駅が分かる形の表データを目指します。

対象は地下鉄路線のみで、接続や乗り入れは考えません。例えば浅草線は、泉岳寺から品川へ行けますが京急なので無視。

あと、つくばエクスプレスも無視します。秋葉原もつくば駅も地下プラットフォームですが、あれって地下鉄の分類じゃないですよね?

処理

まずは路線種別データから地下鉄路線の「line_cd」(路線コード)を抜き出して、そのうえで駅一覧データからその line_cd の駅データを取り出します。

地下鉄路線の絞り込み。「東京メトロ」と「都営地下鉄」しかないので簡単です。

import pandas as pd
line_df = pd.read_csv('line20240426free.csv')
tokyo_subway_lines = [x for x in line_df['line_name'].unique() if '東京メトロ' in x or '都営' in x] # 地下鉄名称一覧. line_cdでもよい
tokyo_subway_line_df = lines[lines['line_name'].isin(tokyo_subway_lines)] # これ

# 辞書型にしてみる
tokyo_subway_line_cd = {x:y for x, y in zip(tokyo_subway_line_df['line_cd'], tokyo_subway_line_df['line_name'])}
tokyo_subway_line_cd

出力 ↓

{
 28001: '東京メトロ銀座線',
 28002: '東京メトロ丸ノ内線',
 28003: '東京メトロ日比谷線',
 28004: '東京メトロ東西線',
 28005: '東京メトロ千代田線',
 28006: '東京メトロ有楽町線',
 28008: '東京メトロ半蔵門線',
 28009: '東京メトロ南北線',
 28010: '東京メトロ副都心線',
 99301: '都営大江戸線',
 99302: '都営浅草線',
 99303: '都営三田線',
 99304: '都営新宿線'
}

これを使って、駅のデータから地下鉄駅を絞り込みます。

stations = pd.read_csv('station20240426free.csv')
subway_stations_df = stations[stations['line_cd'].isin(tokyo_subway_line_cd.keys())]
subway_stations_df.__len__() # 291

乗り換え駅はダブりますが、291駅もありました。

東京メトロ: 180駅、都営線: 106駅

という公式情報があるので、まぁ大体あっていそうです。逆に何が一致しないんでしょう?

ここからが少し趣味要素です。隣駅の「station_cd」(駅コード)が分かるようにします。

駅データ.jpより、隣り合う駅の情報がcsvにまとめられているので、これを上のデータに結合します。

joins = pd.read_csv('join20240426.csv')

# right: station_cdが大きい隣駅 / left: 自駅よりstation_cdが小さい隣駅 とする
stations_neighbor_df = subway_stations_df.merge(joins[['station_cd1', 'station_cd2']], left_on='station_cd', right_on='station_cd1', how='left')
stations_neighbor_df.drop(columns=['station_cd1'], inplace=True)
stations_neighbor_df.rename(columns={'station_cd2': 'right_cd'}, inplace=True)

stations_neighbor_df = stations_neighbor_df.merge(joins[['station_cd1', 'station_cd2']], left_on='station_cd', right_on='station_cd2', how='left')
stations_neighbor_df.drop(columns=['station_cd2'], inplace=True)
stations_neighbor_df.rename(columns={'station_cd1': 'left_cd'}, inplace=True)

ここまできて、致命的な弱点に気づきました。三叉路になっている駅の存在です。今作っているデータでは、隣り合う駅は二つまで、というのが暗黙の了解になっています。しかしながら地下鉄にも、枝分かれ路線がいくつかあります。考慮漏れ。

幸運なことに、これまでの処理でそのような駅は行が二つできているはずです。なので簡単に可視化できます。私が思いつく限りでは都庁前駅(大江戸線)、中野坂上駅(丸の内線)でした。仮説が正しいか確認しましょう。

# groupbyのあとにgroupsを呼ぶと、一覧を辞書形式で出せる
for k,v in stations_neighbor_df.groupby('station_cd').groups.items():
    if len(v)>1:
        display(stations_neighbor_df[stations_neighbor_df['station_cd']==k])

結果がこちら。あたっててなんかうれしい。

station_cd station_g_cd station_name line_cd lon lat address right_cd left_cd
2800220 2800220 中野坂上 28002 139.68291 35.69792 中野区中央2-1-2 2800221.0 2800219.0
2800220 2800220 中野坂上 28002 139.68291 35.69792 中野区中央2-1-2 2800226.0 2800219.0
station_cd station_g_cd station_name line_cd lon lat address right_cd left_cd
9930101 9930101 都庁前 99301 139.69257 35.690551 新宿区西新宿2-8-1 9930102.0 9930128.0
9930101 9930101 都庁前 99301 139.69257 35.690551 新宿区西新宿2-8-1 9930129.0 9930128.0

これらをどうするかはお好み。あたらしくstation_cdをきって別駅にするのも用途によってはありかと思います。たとえば

stations_neighbor_df.loc[39, 'station_cd'] = 2800228+1	
stations_neighbor_df.loc[39, 'station_name'] = '中野坂上 方南町方面'

stations_neighbor_df.loc[186, 'station_cd'] = 9930138+1
stations_neighbor_df.loc[186, 'station_name'] = '都庁前 飯田橋方面'
stations_neighbor_df.loc[186, 'left_cd'] = 9930129

地上路線だとこういうのさらに増えそうなので、考えたくないです。。

ともあれ目標のデータが達成できました。

Discussion