Mapping stations' DB-HAFAS-IDs to DELFI-GTFS-IDs

October 23, 2023 · View on GitHub

This project aims to match DB-HAFAS-IDs to DELFI-GTFS-IDs for all train and bus/tram/etc. stations in Germany. Jump to the results.

Terminology

DB-HAFAS-IDs are the stop/station ids used by the HAFAS system run by Deutsche Bahn. Other HAFAS instances most likely use different IDs. Depending on the context DB-HAFAS-IDs might also be called:

  • EVA number. Usually only for DB/German train stations. See e.g. here
  • IBNR. Usually only for DB/German train stations.
  • UIC number. Might be the same as IBNR for train stations (including the country prefix 80), but often enough, it seems to differ, at least according to Wikidata (see e.g. Frankfurt(Main) Hbf). In OSM, there is a tag uic_ref which appears to sometimes contain the UIC number and sometimes the IBNR. There is also the very rare tag ref:IBNR. Also compare this OSM discussion.

However, DB-HAFAS also covers all German bus/tram stations, using IDs without the 80 prefix.

DELFI-GTFS-IDs are the stop/station ids used by the DELFI GTFS dataset. They might also be called:

  • DHID, issued/managed by ZHV.
  • IFOPT-ID, the standard according to which the DHIDs are built.

But, there is a difference between the IDs used in the GTFS dataset and the ZHV ones, see this issue and below.

Data sources

Some insights

  • IFOPT-IDs have a hierarchical structure country:admin_area:stop_place:level:quay, the stop_place corresponding most closely to the notion of a station that might have multiple levels/areas/sections and quays.
  • DB-HAFAS-IDs are just a number. They are assigned to stations/stops, there is no distinction for areas/quays.
  • In the ZHV, a train station and its corresponding bus/tram station are usually identified by a common stop_place identifier, having different level identifiers.
  • In DB-HAFAS, a train station and its corresponding bus/tram station will have two different IDs (though a common parent station, usually the train station).
  • The DELFI GTFS and ZHV IDs diverge quite a lot. In particular (as of 2023), many train movements are not tied to the correct quays, but to a top-level stop_place postfixed with _G instead. E.g. all trains in Frankfurt(Main) Hbf depart from de:06412:10_G. Other stations have IDs that are not at all in IFOPT format. Also see this issue. So if you need a mapping from DB-HAFAS-IDs to ZHV-IDs instead of DELFI-GTFS-IDs, you should adjust the procedure below.
  • I.e. it is not sufficient to map stop_place identifiers to DB-HAFAS-IDs, even though DB-HAFAS-IDs are not as fine-grained as to identify areas/quays.
  • Train stations with an additional underground station ("tief") will usually be identified as two different stations by both DB-HAFAS and the ZHV. The corresponding bus/tram station will be assigned to one of the train stations in the ZHV.
  • But there are also cases where two train stations with different DB-HAFAS-IDs correspond to a single station (and even quay, due to the _G quirk and others) in DELFI-GTFS, e.g. Berlin Ostkreuz [8011162, de:11000:900120003] and Berlin Ostkreuz (S-Bahn) [8089028, de:11000:900120003] or Berlin Hbf (oben) and Berlin Hbf (S-Bahn) (Berlin Hbf (tief) has separate IDs in both).
  • There is an alternative GTFS dataset that might be easier to match, but does AFAIK not use IFOPT-IDs.

Procedure

  • Enrich db-hafas-stations with additional stations and calling lines from public-transport-statistics and the known, manually assigned station-level IFOPT-IDs from the official DB Haltestellendaten. (Download result below)
  • Use an adapted version of nvbw-osm-stop-comparison to match DELFI-GTFS-IDS (and optionally ZHV stations) with the DB-HAFAS-stations (instead of OSM stations):
    • If only trains are calling at a given DELFI-GTFS-station/quay, and there exists a DB-HAFAS-station with a manually assigned IFOPT-ID being a prefix of the DELFI-GTFS-ID, then it is very likely a match
    • If things other than trains are calling at the station, it is most likely a bus/tram station that has a completely different DB-HAFAS-ID, i.e. it should not be matched even if the IFOPT-ID-prefixes match!
    • Then we can only rely on fuzzy location, name, mode and line name comparison (and, with enough HAFAS data, in the future possibly entire line routes)
  • One fine-grained (quay-level) DELFI-GTFS-ID is usually mapped to one DB-HAFAS-ID (but may be mapped to multiple, see above). One DB-HAFAS-ID is typically mapped to many fine-grained DELFI-GTFS-IDS.
  • We favor completeness over accuracy. We try to match every DB-HAFAS-ID to at least one DELFI-GTFS-ID and vice versa, if we have any candidate. However, DB-HAFAS-stations outside of Germany are obviously discarded and in both datasets, stations are missing!

If you want to match against ZHV-IDs instead of DELFI-GTFS-IDs, adjust the -p flag of the nvbw-osm-stop-comparison script from GTFS to DELFI and indicate the ZHV CSV source file using -s (see README). Beware that this will have an impact on the quality of the mapping.

Results

In order to obtain top-level IFOPT-IDs from quay-level ones (including removing quirks like _G), you might use a regex like that: s/^([^:_]+:[^:_]+:[^:_]+)(_[^:]+)?(:.+)?$/\1/. Beware, as stated above, that this will result in a fuzzy mapping, even more so than before.