東京公共交通オープンデータを触ってみた

# 東京公共交通オープンデータチャレンジ
「東京公共交通オープンデータチャレンジ」というオープンデータコンテストがはじまりました。
https://tokyochallenge.odpt.org/
首都圏の公共交通機関のデータが公開されているのでさっそく触ってみました。
中身は2014年の「東京メトロオープンデータ活用コンテスト」で使われたデータを拡張した感じでした。
https://developer.tokyometroapp.jp/
現在準備中の項目も多いので、データが揃うのが楽しみです（早く揃ってくれないとアプリが作りづらい）

# 取得できるデータ
詳細はAPI仕様を読んでください。

| 種別 | 名称 | 詳細 |
|:-:|:-:|:-:|
| 鉄道 | PassengerSurvey | 駅の乗降客数 |
| 鉄道 | Railway | 路線情報 |
| 鉄道 | RailwayFare | 運賃情報 |
| 鉄道 | Station | 駅情報 |
| 鉄道 | StationTimetable | 駅単位の時刻表 |
| 鉄道 | Train | 電車の位置情報 |
| 鉄道 | TrainInformation | 路線の運行情報 |
| 鉄道 | TrainTimetable | 電車単位の時刻表 |
| バス | Bus | バスの位置情報 |
| バス | BusTimetable | バス単位の時刻表 |
| バス | BusroutePattern | 路線情報 |
| バス | BusroutePatternFare | 運賃情報 |
| バス | BusstopPole | バス停情報 |
| バス | BusstopPoleTimetable | バス停単位の時刻表 |
| 航空 | FlightInformationArrive | 当日到着する航空機の情報 |
| 航空 | FlightInformationDeparture | 当日出発する航空機の情報 |
| 航空 | FlightSchedule | 空港を発着する航空機の予定時刻表 |

# 情報提供している会社
全ての会社が上記全てのデータを提供しているわけではありません。

| 種別 | 名称 | 静的データ | 動的データ |
|:-:|:-:|:-:|:-:|
| 鉄道 | 東京地下鉄 | ◯ | ◯ |
| 鉄道 | 東京都交通局 | ◯ | ◯ |
| 鉄道 | JR東日本 | ◯ | ◯ |
| 鉄道 | 小田急電鉄 | ◯ | ◯ |
| 鉄道 | 京王電鉄 | ◯ | ◯ |
| 鉄道 | 京成電鉄 | ◯ | - |
| 鉄道 | 京浜急行電鉄 | ◯ | ◯ |
| 鉄道 | 西武鉄道 | ◯ | - |
| 鉄道 | 東京急行電鉄 | ◯ | ◯ |
| 鉄道 | 東京臨海高速鉄道 | ◯ | ◯ |
| 鉄道 | 東武鉄道 | ◯ | - |
| 鉄道 | ゆりかもめ | ◯ | - |
| バス | 東京都交通局 | ◯ | ◯ |
| バス | 小田急バス | ◯ | - |
| バス | 関東バス | ◯ | - |
| バス | 京王電鉄バス | ◯ | - |
| バス | 国際興業 | ◯ | - |
| バス | JRバス関東 | ◯ | - |
| バス | 西武バス | ◯ | - |
| バス | 東急バス | ◯ | - |
| バス | 東武バス | ◯ | - |
| バス | 西東京バス | ◯ | - |
| 航空 | 全日本空輸 | ◯ | - |
| 航空 | 東京国際空港ターミナル | ◯ | ◯ |
| 航空 | 成田国際空港 | ◯ | ◯ |


# 環境
* Xcode 9.1
* Swift 4

# コード

iOSアプリを作りたいので、とりあえずAPIKitで叩いてSwiftyJSONで内容を見られるように全APIのRequestを用意しました。

https://gist.github.com/ninten320/718a2465f52234fe3c93675567ef603d

このAPIを叩くにはアクセストークンが必要なので、まずコンテストにエントリーしてアクセストークンを取得しましょう。
ACL_CONSUMERKEYを各自で取得したアクセストークンに置き換えてください。

```swift
import APIKit
import SwiftyJSON

protocol TokyoChallengeAPIRequest: Request {
    var params: [String: Any] { get set }
}

extension TokyoChallengeAPIRequest {
    var baseURL: URL {
        return URL(string: "https://api-tokyochallenge.odpt.org/api/v4/")!
    }
    var parameters: Any? {
        var params = self.params
        // ACL_CONSUMERKEYを取得したアクセストークンで置き換える
        params["acl:consumerKey"] = ACL_CONSUMERKEY
        return params
    }
    var method: HTTPMethod {
        return .get
    }
    func response(from object: Any, urlResponse: HTTPURLResponse) throws -> JSON {
        return JSON(object)
    }
}

enum TokyoChallengeAPI {
    // ここにいろいろ
}
```
こんな感じで使えます。

```swift
import APIKit

let request = TokyoChallengeAPI.TrainInformation(operatorID: "odpt.Operator:TokyoMetro")
Session.send(request) { print($0) }
```

叩くときの引数の値の例を示しておきます。

| 種別 | 引数 | 値 |
|:-:|:-:|:-:|
| 鉄道 | operatorID | odpt.Operator:TokyoMetro |
| 鉄道 | railwayID | odpt.Railway:TokyoMetro.Marunouchi |
| 鉄道 | stationID | odpt.Station:TokyoMetro.Marunouchi.Tokyo |
| バス | operatorID | odpt.Operator:Toei |
| 航空 | airportID | odpt.Airport:HND |

# 気になった点
すべてのデータを見れてはいませんが、少し触ってみて気になった点を書いていきます。
準備中データが公開されたら追記するかもしれません。

鉄道のデータについては、東京メトロのオープンデータを触っていたので同じように使えそうです。
バスと航空については馴染みがないので何とも言えません。
おそらく鉄道と同じように使えると思いますが、バスデータは複雑そうだなという印象です。

以下、比較のために東京公共交通オープンデータを新データ、東京メトロオープンデータを旧データと呼びます。
東京メトロのデータの例では、「東京メトロ(新)」の場合は新データ、「東京メトロ(旧)」は旧データで取得した情報です。

## APIドキュメントが旧データに比べて親切でない
旧データは各APIのリクエスト・レスポンスに具体例がありましたが、新データは型情報しか書かれていないAPIがいくつもあります。
バス関連のデータのDescriptionなどは日本語がなくて分かりにくいです。
各社がロゴなどのファイルを提供しているという文章はあるのですがアクセス方法が分かりません。

## 日本語表記が追加されている場合がある

旧データではIDと日本語表記の辞書が別ファイルで渡されていたのが、新データではデータに日本語表記が含まれている場合があります。
結果をそのまま表示できるので簡単になりました。
東京メトロ(新)には含まれていませんでしたが・・・

```json:東京メトロ(旧)
{
  "odpt:station": "odpt.Station:TokyoMetro.Ginza.Shibuya",
  "odpt:index": 0
}
```
```json:JR東日本
{
  "odpt:index": 1,
  "odpt:station": "odpt.Station:JR-East.JoetsuShinkansen.Tokyo",
  "odpt:stationTitle": "東京"
}
```

## stationOrderのindexが異なる
駅順を表すstationOrderのindexが、旧データでは0から割り当てられているのに対し、新データでは1からはじまっています。

```json:東京メトロ(旧)
{
  "odpt:station": "odpt.Station:TokyoMetro.Ginza.Shibuya",
  "odpt:index": 0
}
```

```json:東京メトロ(新)
{
  "odpt:index": 1,
  "odpt:station": "odpt.Station:TokyoMetro.Ginza.Shibuya",
}
```

## 同じキーに会社によって違う情報が入っている／そもそも入ってない
会社によって違うデータが返ってきたりそもそも存在しない可能性があります。
例えば、路線情報APIで取得できる所要時間は東京メトロ(旧)と都営地下鉄で単位が違います。
他のデータもこのような違いがある可能性があります。

```json:東京メトロ(旧)
{
  "odpt:fromStation": "odpt.Station:TokyoMetro.Chiyoda.YoyogiUehara",
  "odpt:toStation": "odpt.Station:TokyoMetro.Chiyoda.YoyogiKoen",
  "odpt:necessaryTime": 2,
  "odpt:trainType": "odpt.TrainType:Local"
}
```

```json:東京メトロ(新)
null
```

```json:都営地下鉄
{
  "odpt:toStation": "odpt.Station:Toei.Shinjuku.ShinjukuSanchome",
  "odpt:trainType": "odpt.TrainType:Local",
  "odpt:fromStation": "odpt.Station:Toei.Shinjuku.Shinjuku",
  "odpt:necessaryTime": 75
}
```
(追記)
新データの仕様書には所要時間は分であると書かれていました。
また、キーが"odpt:time"であると書かれていましたが旧データ仕様のままです。
そもそもAPI仕様のRailwayの定義に所要時間が含まれていないのに都営だけ取得できていることが不思議です。


### 会社によるデータの違い

| API | 違い |
|:-:|:-:|
| Railway | 所要時間の単位が東京メトロは分、都営地下鉄は秒 |
| TrainInformation  | 東京メトロは現在の情報のみ、JRは過去のデータも含む |

## 駅時刻表に列車IDが含まれていない
個人的に旧データでの最大の不満点でしたがにも東京メトロについては新データにも含まれていませんでした。
API仕様を読むと列車IDの欄があるので、路線によっては含まれているかもしれません。

## 情報が古いまま

丸ノ内線の支線の駅ナンバリングが「ｍ」から「Ｍｂ」に変わってしばらく経つのですが、変更されていません。

## オープンデータ？
このデータはコンテスト以外に使ってはいけないことになっています。
オープンデータの定義はなんだっけ・・・

## 結果が1000件までしか取得できない
取得件数に制限があるため、一度にあんなことやこんなことをしにくくなりました。
JR東日本の駅情報すら一度に取得できません。

> APIによって出力される結果が1000件を超える場合、1000件以下にフィルターされた結果が返る
> クエリパラメータで絞込を行った上で再度必要な情報を取得する必要がある

（絞り込めば必要な情報が全部取得できるとは言っていない）
取りたい情報が1000件以内に収まっていることを祈りましょう。

## データの更新が通知されていない？
データカタログに(予定)がついててもデータによっては既に取得できるようです

## 年末年始ダイヤの対応
12/30〜1/3までリアルタイム情報のデータ提供を停止するそうです。
（年末年始対応を諦めるならコンテストは年明けから始めればよかったのでは...）

# おわりに
API仕様を見ると、東京メトロのオープンデータにはないような情報も含まれていて期待が高まりました。
しかし実際には提供されていない情報の多さや前回の不満点が改善されていないなど、正直に言えば肩透かしを食らった気分です。
それでも、多くの公共交通機関のデータに触れる貴重な機会です。
東京メトロのオープンデータコンテストは、想定を上回る応募によってオープンデータの提供継続が決まったそうです。
今回のコンテストも、たくさんの人が応募して盛り上がったらいいなと思います。
公共交通機関のオープンデータ化の流れがオリンピックに向けた一時的なものではなく継続・拡大していくことを期待しています。