Methodology & Data
TransitShield is built to be auditable: every station score traces back to public MTA and FEMA data through a reproducible, keyless pipeline. This page documents the sources, the index, its central assumption, and its limits.
Data sources
All sources are public-domain U.S. open data requiring no API key or authentication.
| Source | Role | License |
|---|---|---|
| MTA Subway Hourly Ridership (Beginning 2025)data.ny.gov (Socrata) · 5wq4-mkjj | Per-station annual ridership (2025 calendar year, subway mode), coordinates, borough. Drives the consequence term. | public domain (NY Open Data) |
| MTA Subway Hourly Ridership (2020-2024)data.ny.gov (Socrata) · wujg-7c2s | Alternate/historical ridership source (same schema). 2025 dataset used as the current-year basis; full-dataset group queries on this larger table time out, so 5wq4-mkjj was used. | public domain (NY Open Data) |
| MTA Subway Major Incidents (Beginning 2015)data.ny.gov (Socrata) · ereg-mcvp | Major-incident counts by division and line (2020-present used). Drives the station reliability index via line->station allocation. | public domain (NY Open Data) |
| MTA Mean Distance Between Failures (Beginning 2015)data.ny.gov (Socrata) · e2qc-xgxs | Division-level fleet MDBF (2025). Scales reliability index (lower MDBF => worse reliability). | public domain (NY Open Data) |
| FEMA National Risk Index — CountiesFEMA (hosted ArcGIS FeatureServer) · National_Risk_Index_Counties (ArcGIS FeatureServer) | County (borough) climate exposure: coastal flood + hurricane + composite risk scores, Expected Annual Loss ($), and Social Vulnerability. Drives the exposure term. | public domain (U.S. Federal) |
Composite index construction
The TransitShield risk score fuses three signals — consequence, fragility, and hazard — then ranks stations 0–100:
- Reliability index (fragility). mean 2020-present major-incident count of lines serving a station (parsed from station name), scaled by division MDBF fleet factor. Higher = worse.
- Climate exposure (hazard). FEMA NRI county (borough) national-percentile scores: 0.40*coastal_flood + 0.35*hurricane + 0.25*composite, /100. Borough-uniform; per-station hazard is PROPOSED. Weights: coastal_flood 0.4, hurricane 0.35, composite 0.25.
- Ridership (consequence). Per-station 2025 annual subway ridership — the count of riders a failure would strand.
These combine as risk_raw = zscore(reliability) * borough_exposure * ln(annual_ridership+1); ranked 0-100 by percentile.
The line-level incident allocation assumption
Incidents are line-level; assumed to distribute uniformly across a line's stations. Per-station incident geolocation is PROPOSED.
MTA publishes major incidents by line and division, not by individual station. TransitShield therefore distributes a line's incident count uniformly across the stations that line serves (parsed from the station-complex name), scaled by the division's mean-distance-between-failures fleet factor. This is a transparent, documented approximation — not a claim of per-station incident geolocation.
Limitations (read before acting)
- Line-level incidents. Reliability is allocated from line/division incident counts, assumed uniform across a line's stations; true per-station incident geolocation is proposed.
- Borough-uniform exposure. FEMA climate exposure is at county (borough) resolution, so all stations in a borough share one exposure value; per-station hazard modeling is proposed.
- Ridership scope. Ridership is 2025 subway-mode only; Staten Island Railway and non-subway modes are out of scope, so those stations are not scored.
- Weighting is a choice. The exposure weights are a documented v1 baseline; a sensitivity analysis is on the roadmap.
- Proposed enhancements, not shown as results: origin-destination network outage propagation; per-station (not borough) hazard modeling; storm scenario simulator (e.g. Sandy-class surge).
Reproducibility
The pipeline is one command — npm run data (python3 scripts/build_index.py) — pulling MTA ridership, incidents, and MDBF plus the FEMA National Risk Index, computing the composite, and writing validated GeoJSON/JSON. A separate validator (npm run validate) enforces coordinate bounds, score ranges, and cross-file consistency. No manual steps, no hand-edited numbers.