See it live: fleet.harrischew.com
What I Built
A live data pipeline and map that studies how Lyft keeps its Bay Wheels bikeshare fleet stocked across San Francisco, the East Bay and San Jose, using only Lyft's public data.
A poller reads Lyft's live station feed every 2 minutes and has mapped 2.28M observations across 638 stations. An analysis pipeline turns that into demand estimates, a stockout forecast and a dispatch backtest, and a live map shows where the fleet is failing riders.
I built it solo, end to end.
Why I Built It
Rebalancing bikes is the same problem as repositioning robotaxis or delivery fleets: predict where demand will be, move idle supply there first, and pay the cost of the empty trip.
Unlike robotaxi data, bikeshare data is public, live and free. That let me work on a real fleet problem with real numbers instead of a simulation.
What I Found
1. Most of the problem is invisible to simple stock counts. 82.5% of trips are on ebikes, but ebikes are only about half the parked fleet. Stations sat with zero ebikes 20.2% of the time, against 5.9% with no bikes at all. A dashboard that only counts bikes misses most of the failures.
2. About a third of demand never shows up in trip data. An empty station records no rentals, so it looks unwanted. I measured rental rates only while bikes were in stock and applied them to the sold-out periods, recovering 32% of ebike demand that trip records never capture. That changes which stations look worth restocking.
3. The longest outage is not the most costly one. The station empty longest (208 hours) lost only 27 rides, while another lost 350 in less time. I built and backtested a model that ranks stations by the rides their empty periods cost, so vans go where they matter most.
How It Works
Collection
A Python FastAPI function on Vercel Cron polls Lyft's live GBFS feed every 2 minutes. It writes only the stations whose inventory changed to Supabase Postgres, and logs every poll so a missing row always means "no change", never "missed data".
Analysis
A pipeline syncs the data into DuckDB, rebuilds a 5-minute grid for every station, estimates true demand, forecasts which stations will run out of ebikes in the next hour, and backtests a dispatch plan. The whole run takes about 3.5 minutes.
Live Map
A Next.js app with deck.gl draws the latest 7 days across four views: all bikes, ebikes, stock versus demand, and stations at risk. The browser reads one static file, so the map never touches the database.
Technical Stack
| Layer | Technology |
|---|---|
| Data sources | Lyft Bay Wheels live GBFS feed, Lyft public trip archive (1.68M trips) |
| Collection | Python, FastAPI, Vercel Cron |
| Storage | Supabase Postgres, DuckDB |
| Modeling | scikit-learn |
| Map | Next.js, deck.gl, MapLibre |