How many people are on that train?

Every train on the map carries a number: how many riders are aboard. Nobody counted them. Here is how they were inferred from fare and turnstile counts, a timetable, and some network tomography.

At 8:45 a.m. on Wednesday, February 5, 2020, a month before the pandemic emptied the system, about 213,000 people were riding New York's subway trains — according to the model this page describes. The MTA doesn't publish a picture like the one above. Its fare system knows how many people enter each station, hour by hour, and its turnstiles know, roughly, how many leave. Nothing records which train anyone rode. What follows is how to get from those counts to a number for every train: a little data cleaning, a little graph search, and an idea borrowed from medical imaging.

What the counters know

Two MTA datasets do the counting. The fare system's hourly ridership counts entries at each of the system's 424 station complexes, every hour. Those are the model's inputs, and it matches them exactly. Everything it knows about exits comes from the older turnstile files, published through 2022: a reading of every turnstile's registers, taken every four hours.

The register works like a car's odometer: two counters, entries and exits, that should only go up. Subtract consecutive readings and you get riders per interval. “Should” is doing some work here: across the week, 81 counters ran backwards and two dozen jumped by millions when they were reset. Flipping the first kind and patching the second from the same turnstile's usual count was enough; fewer than one interval in 5,000 needed a patch.

The harder problem is where each turnstile is. The files name stations in 15 truncated characters (JKSN HT-ROOSVLT) with a run-on list of lines (EFMR7), so matching them to station complexes takes fuzzy name matching plus line overlap. That mostly works. Its best mistake was a unit labeled “59 ST” with lines “NRW,” which the matcher placed at 5 Av/59 St in Manhattan. It is really 59 St in Sunset Park, Brooklyn. The hourly entries caught it: when turnstiles are assigned to the wrong station, the two datasets disagree. After that one hand fix, every complex's turnstile entries match the fare system's within 8%, and 406 of 424 within 5%.

Exits are messier. Riders leave through emergency gates and exit-only stairways that have no counters, so recorded exits add up to only 79% of entries systemwide. Station by station, the ratio runs from almost nothing to nearly double.

Some of that spread is real, because not everyone goes home from the station they came in at; that's how 82 stations can record more exits than entries. Most of it is counting. So exit counts can't say how many people went to a station. They can say when people left it: the shape over the day survives even when the level doesn't.

The timetable is a graph

The second ingredient is the schedule. The MTA's current timetable is easy to download; the February 2020 one is not, but the Internet Archive saved a copy of the feed from that spring, and its weekday schedule covers our day exactly: 8,376 trips, making about 225,000 station-to-station hops.

A route planner called the Connection Scan Algorithm reads those hops once, in order of departure time, and finds the earliest way from a station, at any minute, to every other station. Earliest isn't how people choose, though. Asked to get from Times Square to Coney Island, it takes the 7 one stop, changes to the B, and changes again to the Q, all to arrive six minutes before the one-seat N. So the planner keeps the best journey for each number of trains used, and riders pick whichever minimizes arrival time plus five minutes for every transfer. That puts them on the N.

Network tomography

Now the puzzle: we know how many people entered each station each hour, and roughly when people left each station. We want to know who went where.

This is network tomography, a name Yehuda Vardi gave in 1996 to estimating the traffic between every pair of computers on a network from counts on its links. The name comes from medical imaging. A CT scanner never sees inside you; it measures sums along X-ray paths, from many angles, and solves for the interior that explains them all. One angle isn't enough.

Lay the unknowns out as a table of origins by destinations and the hourly entries are its row sums; the exit counts are its column sums, up to each station's unknown recording rate, which is why the rule that people go home matters. That is two angles. The timetable supplies more. A rider who enters Flushing at 8 a.m. bound for Grand Central leaves around 8:35; one bound for Coney Island, around 9:30. So each four-hour exit count is a sum over a particular set of origins and starting hours, picked out by the routes through the timetable. The routes are the rays.

Even so, the scan is badly underdetermined. The unknowns are riders from each station to each other station for each hour of the modeled window: 5.4 million numbers, against 2,587 exit counts and 424 daily totals. The model needs a shape, and ours is one of the oldest in transportation planning, the gravity model. Riders entering a station spread over destinations in proportion to each destination's pull at that hour times a weight that falls with travel time, and are shared out so each station's riders add up to its measured entries. The weight is e−minutes/17.2: every 12 extra minutes of travel halves a destination's appeal (more on where that number came from below).

That leaves 12,720 pulls to fit, one per station per hour, tuned so that the riders, routed through the timetable, leave each station when its exit counters say they did. Three assumptions make that possible. Each group of exit counters gets its own recording rate, which absorbs both missing gates and model error. Each station's exits over the day roughly equal its entries, because people go home. And a station's pull changes smoothly from hour to hour. Those assumptions, as much as the data, decide the details.

Two ways it went wrong

The first attempt skipped the gravity model and let all 5.4 million flows float free, nudging them until they matched the exits. It matched beautifully, by inventing nonsense: to reconcile two exit counters at the same Bronx station, it put 2,600 people on a single 5:55 a.m. 6 train. With enough free numbers, a model will always find a way to fit the noise.

The second attempt had the gravity model and failed more spectacularly. It decided that 14 St–Union Square was the destination of 2.15 million trips a day, more than a third of the whole system, at a station where about 104,000 people enter.

The culprit was the exit counters again. Systemwide, the share of riders whose exit gets recorded is lowest at the morning peak, when crowds push through emergency gates. A model in which each counter's rate is fixed all day can't express that, so it found a loophole: a station with a single group of exit counters, whose recording rate could drop to 7% while its “arrivals” absorbed the mismatch. The fix was to let recording vary smoothly by time of day, the same for the whole system (right). Union Square went back to being a busy station rather than a black hole.

Putting people on trains

With flows between stations in hand, the last step is mechanical. Each hour's riders from each station are spread over departure times two minutes apart, each group is routed through the timetable, and its riders are added to every hop of every train it rides. That is about 380,000 route searches, a minute and a half on a laptop. The result is a rider count for every hop of every trip, which is what the map animates.

On the 7 line between 7:45 and 8:45, Manhattan-bound trains fill up through Queens until they are carrying about 20,000 riders an hour past Queensboro Plaza, and stay near that level under the East River before emptying at Grand Central and Times Square. Expresses run fuller than locals; the fullest train of the hour is a 7 express with about 1,000 riders between Woodside and Queensboro Plaza. Trains heading back to Flushing carry under a third as many.

How good is it?

Parts of it can be checked; the part on the map can't, yet. The MTA publishes its own origin–destination estimates, inferred from MetroCard and OMNY swipe histories, but only from 2021 on. February 2023 Wednesdays are the nearest comparison: lower volume and less commuting than 2020, but the same city. So the check compares where each station's riders go, as shares, scoring the overlap from 0 (entirely different destinations) to 1 (identical).

Knowing nothing but each station's size already scores 0.60. Adding travel time brings it to 0.68, and fitting to the exit counts to 0.74. In the morning peak the same steps go 0.51, 0.66, 0.69.

That check isn't fully independent, because one number came from the same MTA data. The turnstile counts barely constrain how far people travel, so the travel-time weight was calibrated to reproduce the MTA's distribution of trip lengths. Before calibration the model's median trip was 34 minutes, against the MTA's 28, and the whole-day overlap was 0.69, against 0.74 now.

Nothing here checks per-train loads directly. Entries are measured; destinations, timing within the hour, and route choice are modeled. Everyone traveling between the same two stations at the same minute takes the same train, and trains never fill up, so fast routes probably carry too many riders and parallel ones too few. The biggest dots on the map, on the A and the B, are on exactly those fast routes, and the Lexington Avenue express looks lighter than its reputation. The timetable is also the plan, not what actually ran that day. A direct test would compare loads with cordon counts of subway riders entering Manhattan, line by line.

Ingredients

Turnstile usage (2020), hourly subway ridership, the subway stations table, and origin–destination estimates (2023), all from the MTA via data.ny.gov. The February 2020 GTFS schedule, via the Internet Archive. Basemap © OpenStreetMap contributors and CARTO. The code is a small Python pipeline (polars, numba, scipy) and a MapLibre + deck.gl page; the README explains how to rebuild everything.

← Back to the map