一覧に戻る

PythonでGTFSをパースするライブラリgtfs-parser

#Python#pandas#foss4g#GTFS

はじめに

この記事は公共交通に関するデータセット「GTFS」をパースするライブラリgtfs-parserの紹介をします。

:::note GTFSの説明は下記記事に任せ、割愛します。 :::

https://qiita.com/Kanahiro/items/976900c4e5542acfe29d

https://qiita.com/Kanahiro/items/140f50b7f7894f260fde

まず2021年の話ですが、GTFSを位置情報データへ変換するツールとして、GTFS-GOというQGISプラグインを開発しました(QGIS=位置情報データを表示するGISソフトウェア)。多方面から反響をいただき、バージョンアップを重ねてきました。

https://github.com/MIERUNE/GTFS-GO

GTFS-GO開発当初から、GTFSをパースする部分はPythonモジュールとして内部的に切り出していました。とはいえ、リポジトリ内の単なる1フォルダであるため、GTFS-GO以外からは使いにくい状態でした。

今回、GTFSをパースする部分をgtfs-parserとして、①別リポジトリに切り出し②CLIの引数等を整理し③PyPIに公開したため、紹介します。

gtfs-parser

https://github.com/MIERUNE/gtfs-parser

https://pypi.org/project/gtfs-parser/

インストール

# Python v3.7.1 or newer
pip install gtfs-parser

使い方

CLI

gtfs-parser <mode> <src> <dst>
# mode: parse or aggregate
# src: gtfs-zip or gtfs-directory
# dst: output directory, 変換結果がGeoJSON形式のファイルとして書き出されます。
# simple
gtfs-parser parse gtfs.zip output_dir

# with options
gtfs-parser parse gtfs_dir output_dir --parse_ignoreshapes --parse_ignorenoroute
# --parse_ignoreshapes: shapes.txtを無視する
# --parse_ignorenoroute: routeが通らないstopを無視する
# simple
gtfs-parser aggregate gtfs.zip output_dir

# 名寄せを行わないオプション
gtfs-parser aggregate gtfs.zip output_dir --aggregate_nounifystops
# --aggregate_nounifystops: stopの名寄せを行わない

# オプション
gtfs-parser aggregate gtfs.zip output_dir \
  --aggregate_yyyymmdd 20230706
  --aggregate_delimiter -
  --aggregate_begintime 123456
  --aggregate_endtime 234501
# --aggregate_yyyymmdd: 集計対象の日付 20230706 -> 2023-07-06
# --aggregate_delimiter: stopの名寄せ時の、stop_idの区切り文字指定
# --aggregate_begintime: 集計対象の時間範囲(開始時刻) 123456 -> 12:34:56
# --aggregate_endtime: 集計対象の時間範囲(終了時刻) 234501 -> 23:45:01

Python API

from gtfs_parser.gtfs import GTFS
from gtfs_parser.parse import read_routes, read_stops, 
from gtfs_parser.aggregate import Aggregator

#gtfs_dir: path to gtfs-directory
gtfs = GTFS(gtfs_dir)

# parse
stops = read_stops(gtfs) # GeoJSON-Features
routes = read_routes(gtfs) 
# with options
# stops = read_stops(gtfs, ignore_no_route=True)
# routes = read_routes(gtfs, ignore_shapes=True)

# aggregate
aggregator = Aggregator(gtfs) # take costs on init
aggregated_stops = aggregator.read_interpolated_stops() # GeoJSON-Features
aggregated_routes = aggregator.read_route_frequency()
# with options
# aggregator = Aggregator(gtfs, no_unify_stops=True)
# aggregator = Aggregator(
#     gtfs,
#     yyyymmdd="20200101",
#     begin_time="000000",
#     end_time="235959",
#     delimiter=",",
# )

課題

https://github.com/MIERUNE/gtfs-parser/issues/1

スイスの1.62GBのGTFSの処理に218分かかるので、これをベンチマークに速度改善を図りたい(これは極端なケースですが、速度改善はGTFS-GOでも課題になっている)。

終わりに

MITライセンスで公開しているので、ぜひ使ってみてフィードバックをください(きっと動かないGTFSデータもあると思います。また、あらゆるコントリビュートを歓迎します。特にドキュメントやテストが不足している状態です。

次のプラン

gtfs-parserを外部から使いたくなった動機は、GTFSを動的に変換するサーバーを書きたくなり、そこで使いたかったためです。GTFSの在処を渡すとGeoJSONで降ってくるサーバーがあったら面白そうですよね。動的に返すためにはそれなりの速度が求められるため、上記のIssueが重要なわけです(それでも1.62GBのGTFSを動的に変換するのは不可能ですが)。

※開発中の画面(ニューヨークのGTFSを利用、©️OpenStreetMap Contributors.)

こちらもそのうち公開出来たら良いなと思います。