← BACK TO LOG
Research2024

Divvy Bikes: A Year in 4.3 Million Trips

Behavioral and operational analysis of the full 2023 Divvy bike-share dataset, separating member from casual riders and recommending where the operational levers are.

TableauPythonPandasMatplotlibStatistical ModelingSpatial Analysis

In 2023, Divvy recorded 4,331,707 bike-share trips across Chicago. This case study breaks that dataset apart along the dimensions an operator would actually act on: member versus casual usage, weekday versus weekend, seasonal pattern, and station-level concentration. The deliverable is a Tableau workbook plus a written set of recommendations. The point of the exercise was to take a year of mobility data and produce something an operations director could use on Monday morning, not a notebook full of charts that prove the analyst can use seaborn.

I picked the Divvy dataset specifically because the obvious chart (total trips by month) is the chart that hides the most. The interesting structure is in the disaggregation: who is riding, when, and why.

The system

Divvy is operated by Lyft for the City of Chicago. As of 2023, the system covered all 50 wards with more than 800 stations and over 15,000 bikes and e-bikes. Among North American bike-share systems it is the largest by service area. The dataset is publicly released by the City and contains, for every trip, the start and end station, the start and end timestamps, and a rider type (member or casual).

Operationally a successful bike-share system runs on three things: a viable membership base that anchors revenue and demand predictability, enough bike availability at the right stations at the right time of day, and pricing and product design that attracts new riders fast enough to grow. The 2023 data contains signal on all three.

The headline numbers

Members took 60 percent of trips. Casual riders took the other 40 percent. The asymmetry matters because the two groups behave entirely differently and require different operational responses.

Trip duration is where that asymmetry first becomes visible. Members average roughly 12 to 13 minutes per trip. Casual riders average 25 minutes or more, roughly double. Quoting a single system-wide average would flatten a difference that is the whole point: members are using bikes for transportation, casual riders are using bikes for recreation. Same fleet, two products, and any aggregate that blends them describes neither.

Seasonal volatility is extreme. Peak summer days run roughly four times the volume of mid-winter days. The seasonal curve starts climbing in April, peaks in July and August, and drops sharply through November as Chicago weather turns. Operations that don't acknowledge that volatility (in fleet sizing, in maintenance scheduling, in marketing spend) leak money.

Two riders, one fleet

Every dimension in the dataset separates the two groups cleanly, and they separate in the same direction: members look like a transit system, casual riders look like a park.

MembersCasual riders
Trip duration12 to 13 minutes25 minutes or more
Temporal peakWeekday rush hour, twice daily (about 8 AM and 6 PM), flat weekendsWeekend-heavy, clustered midday and afternoon, no rush-hour spikes
GeographyResidential-to-downtown corridors (Lincoln Park, Logan Square, West Town into the CBD)Tourist and lakefront destinations (Millennium Park, Navy Pier, Grant Park, the lakefront trail)
SeasonalityYear-round at reduced winter volumeFunctionally absent in January, returning in May
Operational implicationPredictable: forecast it, rebalance to it, size docks to the morning surge, stage maintenance in the midday lullVolatile: dynamic pricing, weather-responsive repositioning and marketing, tourism partnerships

The member pattern is close to a second transit map. Plot the origin-destination pairs and it looks like the CTA Blue and Red lines drawn in trip arrows, which is what makes it schedulable: a demand curve that repeats every weekday can be planned against a week in advance. The casual pattern has no such repeat. Its swing creates a summer-side problem (not enough bikes at the lakefront on a 28-degree Saturday) and a winter-side problem (a lot of capacity sitting idle), and neither is solved by a better forecast. They are solved by capacity that can move. The distinction matters more than any single number in the table: predictability and volatility call for different tools, and treating the 4.3 million trips as one population hands you the average of two answers to a question nobody asked.

Weather and seasonal mechanics

Temperature is the dominant exogenous variable. Trip volume starts climbing meaningfully above 50°F (10°C), peaks in the 70 to 80°F range (21 to 27°C), and curiously declines slightly above about 90°F (32°C) when extreme heat begins discouraging outdoor activity.

Precipitation has a sharp same-day effect. Rainy days show 60 to 80 percent volume reductions versus comparable dry days. The reduction is steeper for casual riders than for members, which is consistent with the underlying use cases: a commuter still has to get to work in the rain, a tourist does not have to bike along the lakefront.

These patterns are unsurprising and quantifiable, which is what makes them useful for operational planning. Predictive models that incorporate weather forecasts can size the active fleet a day or two ahead with usable accuracy.

Station-level concentration

The station distribution follows a Pareto-like shape: roughly 20 percent of stations carry about 60 percent of system volume. The top stations are concentrated downtown and along the lakefront. The bottom of the distribution contains stations that record fewer than five trips per day on average.

Two operational responses follow.

Strategic capacity additions at the high-volume stations. Adding docks at a station that already runs at saturation captures real incremental demand. Adding docks at a station running at 20 percent of capacity captures nothing.

Selective repositioning of low-volume stations. Some low-traffic stations exist for equity reasons (network coverage of underserved neighbourhoods) and should stay regardless of volume. Others are simply badly located and should be moved. Distinguishing those two cases is a policy question, but the data identifies the candidate list.

Recommendations

The case-study writeup ended with five recommendations, paraphrased here:

  1. Convert casual riders systematically. The data identified casual riders who took three or more trips in a single month as a high-likelihood conversion segment. A targeted offer (free trial, summer discount, partner promotion) aimed at that segment converts at rates that justify the marketing spend.

  2. Build a predictive rebalancing model. Member trip patterns are predictable enough to forecast directional flows by time of day. Pre-staging bikes at expected destinations reduces stockouts at the morning end and full-station refusals at the evening end. The expected operational gain is in the 20 to 30 percent range based on comparable systems' published results.

  3. Implement dynamic pricing for casual rides. Same fleet, different price by time and weather. Smooths peak-hour congestion at high-demand stations and improves revenue recovery on weekend afternoons in summer.

  4. Expand strategically into latent-demand neighbourhoods. Origin-destination analysis identified neighbourhoods that show high inbound trip volume but limited station coverage. These are the candidate expansion locations.

  5. Integrate with CTA for first-and-last-mile use cases. Member trip patterns show clear handoffs between bike trips and transit. A bundled or integrated payment product would capture commuters who currently use both systems but pay separately.

Methodology

The data work was done in Python with Pandas for cleaning and feature engineering. Cleaning was the bulk of it: a duration clip at both ends of the distribution, and a de-duplication pass on station identifiers so that a station counted once rather than twice. Both of those steps exist because of the mistakes described in the next section. Time-series decomposition isolated weekly cycles from seasonal trends. Spatial analysis used station-level geocoding to produce origin-destination flow maps. The visualizations were built in Tableau Public for the final deliverable.

The interactive workbook is embedded below, with the season and station-level cuts filterable inside it.

Divvy: a year in review (2023). Interactive Tableau Public dashboard.

This analysis was completed during the Big Data Analytics program at Georgian College and was framed as a hypothetical consulting engagement rather than a published business analysis. The dataset, as a public release, is identical to the one used by Divvy's operating team. The recommendations are mine.

What I got wrong on the first pass

Neither of the two cleaning steps above was in the first version of the pipeline. Both were added after the numbers they were protecting had already gone wrong.

The first mistake was a duration outlier I did not catch until the second cleaning pass. Divvy's 2023 release included trips with ended_at - started_at measured in days, not minutes. Some of those are real (a bike stolen and recovered), most are docking-sensor failures. Computing the average trip duration with those rows in shifted the estimate by minutes. The fix was to clip durations to a sensible range: drop trips under one minute (mostly docking-sensor glitches) and trips over twenty-four hours (mostly equipment lost or stolen). Plotting the duration histogram before and after was the diagnostic. The clipped distribution had a clean right tail; the unclipped one had a thin scatter of multi-day outliers that pulled every aggregate.

The second was an early version of the station-concentration chart that conflated unique stations with start-station counts. Each station appears as both an origin and a destination across the year, so the naive count double-counts by a factor of two. The Pareto shape is real but my first numbers overstated it. The corrected version is the one in the workbook above.

Neither error showed up in tutorials I had used to learn pandas. They came from spending an extra evening on the data after I thought I was done.

What carried forward

The pattern I keep using from this project is the member-versus-casual disaggregation. It is a generic move (split a population by behavioural type before computing any aggregate) and once you have the habit it shows up everywhere. The dashboards I build at metricHEALTH for clinical operations are the same shape: total volume is rarely the metric a manager actually wants. Volume by population, by time of day, by hand-off pattern is. The Divvy workbook was where I built the muscle for that kind of cut, before the data started being about people instead of bikes.

GitHub: https://github.com/TirtheshJani/Case_Study_Divvy_Bikes-

© 2026 TIRTHESHJANI.COMOPEN TO AI/ML ROLESAD ASTRA PER ASPERA