Contents/ Part XVI · Regression Case Study/ Chapter 105

Case Study: Forecasting Daily Bike-Share Demand

The third capstone, and the one where the answer is a count: how many bikes will be rented today? Same 12-step method, a messy daily-operations file to clean, and the signature hazard of count models to diagnose and fix, overdispersion.

⏱️ ~26 min read
🐍 Full notebook included
📊 Chapter 105

Ames predicted a number (price), churn predicted a yes/no. This one predicts a count, whole, non-negative, unbounded, which needs its own model. Fit a straight line to daily rentals and it will happily forecast negative demand; the right tool is Poisson regression, and it has one famous failure to watch.

λ
A count-regression case study models a non-negative count with a Poisson (log-link) regression, whose coefficients exponentiate to rate ratios. When the counts vary more than Poisson allows, overdispersion, the fix is a negative binomial model.
🧭
The count-model twist

Everything from steps 1–7 is the familiar pipeline. The new content lands at steps 8–9: choose a Poisson family, then discover the daily counts are wildly overdispersed and switch to a negative binomial.

1

The 12-Step Method

The same repeatable loop, now applied to a count outcome. The companion notebook runs all twelve steps in code; the sections below narrate the story with the key numbers and pictures.

The 12-step method: from a raw file to a decision 1 Define the objective 2 Collect CSV/SQL/API 3 Inspect shape, types, gaps 4 Clean dupes, dates, missing 5 Visualize hist, box, heatmap 6 Transform log, encode, engineer 7 Analyze correlation, outliers 8 Build the regression 9 Validate VIF, residuals, CV 10 Interpret coefficients as dollars 11 Deploy API, monitor, retrain 12 Communicate plain-English write-up
📂 Dataset · bike_share.csv

Two years of daily records: date, season, weather, temp_c, humidity, windspeed, workingday, holiday, and the target rentals (a daily count).

2

Define, Collect, Inspect, Clean (Steps 1–4)

1

Define the objective

Predict the daily rental count and identify its drivers, so operations can pre-position bikes, schedule staff, and time maintenance. Because rentals are counts, ordinary linear regression is wrong (it can predict negative demand); the right family is Poisson.

2

Collect the data

A CSV pull from the bike-system database. As always, other sources (SQL, an API, a spreadsheet) would use the same one-line pandas readers, then land in a DataFrame.

3

Inspect the data

info() and value_counts() reveal the mess: season and weather in mixed case, workingday as 0/1 and Yes/No, three date formats, duplicate days, missing weather readings, and a few rows with no rentals.

4

Clean the data

ProblemDetailFix
Missing target5 rows with no rentalsdrop
Duplicate days14 repeated datesdeduplicate
Messy categoriesseason ×12, weather ×8, workingday 0/1 + Yes/Nonormalize case, map to one scheme
Three date formatsdatepd.to_datetime(format="mixed"), then engineer month & weekend
Missing weatherhumidity 18, windspeed 9impute the median

After cleaning, 726 days remain with no missing modeling values, and we have engineered month and is_weekend from the parsed dates.

3

Visualize, Transform, Analyze (Steps 5–7)

5

Visualize the data

Step 1: explore. Weather and temperature drive demand 1711 Clear 1515 Mist 945 Light Rain 369 Heavy Rain avg rentals by weather rentals vs temperature (°C)

Demand tracks the weather and the temperature. Average rentals fall from about 1,700 on clear days to under 400 in heavy rain, and rise with temperature (the scatter climbs, then flattens in the heat). The count distribution is right-skewed, and its spread grows with its level, the first hint of trouble.

6

Transform features

We engineer calendar features (month, weekend) from the date, enter weather and season as dummy variables, and add a squared temperature term to capture the rise-then-flatten shape. The outcome is a count, so the model family is Poisson with a log link.

7

Analyze patterns

Quantifying the hint: the daily rentals have a variance-to-mean ratio in the hundreds, when a Poisson model assumes it is about 1. That is overdispersion, and step 9 must deal with it.

4

Build and Validate (Steps 8–9)

8

Build the model

A Poisson GLM of rentals on temperature (and its square), humidity, windspeed, weather, season, working day, and holiday. It fits well, but its Pearson chi-square / df is about 255 (it should be near 1), the overdispersion alarm.

9

Validate the model

Bin the data and the variance sits far above the mean, Poisson's core assumption is badly violated:

Overdispersion: variance dwarfs the mean Poisson assumes variance = mean (gray line); the counts vary far more, so we switch to negative binomial Poisson: variance = mean mean rentals in the bin → variance in the bin →

The remedy is the negative binomial, which adds a dispersion parameter so variance can exceed the mean. It is a spectacular improvement here, the AIC drops from about 183,000 to 11,000. VIFs are ~1 (no multicollinearity), and the negative-binomial forecast tracks actual demand closely (pseudo-R² ≈ 0.66):

The model in action: predicted vs actual daily rentals Pseudo-R² = 0.66; closer to the dashed line is a better forecast perfect forecast actual rentals → predicted rentals →

Same rate ratios as the Poisson fit, but now with honest standard errors. This is the count analog of the log transform in the house-price study: diagnose the violation, switch to the right model, re-check.

5

Interpret and Deploy (Steps 10–11)

10

Interpret the results

Overdispersion diagnostic and the count model demand forecast
From the notebook · Step 10
The variance-versus-mean overdispersion check (why negative binomial beats plain Poisson here) alongside the fitted demand forecast.

Exponentiating each coefficient gives a rate ratio, the multiplier on expected demand:

What moves demand: rate ratios (log scale) RR < 1 means fewer rentals, RR > 1 more; the line at 1 is no effect RR = 1 0.25 0.5 1 1.5 Heavy rain 0.25 Light rain 0.54 Holiday 0.57 Mist 0.90 +10% humidity 0.94 Working day 1.10 +5°C warmer 1.33

Weather rules demand. A heavy-rain day sees only ~25% of clear-day rentals, light rain about half. Warmth helps (+33% for every 5°C), working days run ~10% busier than weekends, and holidays ~40% quieter. A concrete forecast: a warm, clear working day predicts about 3,000 rentals.

Actionable: scale bikes and staff down on forecast rain and cold, up on warm clear working days, and treat holidays like weekends. The forecast feeds straight into the next day's rebalancing plan.

11

Deploy the model

Persist the model and cleaning as one pipeline; score daily by feeding tomorrow's weather forecast plus the calendar to get a predicted count with a range; feed it into bike rebalancing, staffing, and maintenance planning; monitor forecast error and retrain as ridership grows. Guardrail: report the interval and do not extrapolate to weather far outside the training range.

6

Communicate: the Plain-English Write-Up (Step 12)

For the operations manager

What we did. We took two years of daily rental records, cleaned them (removed duplicate days and a few unusable rows, fixed inconsistent labels, filled a handful of missing weather readings, standardized the dates), and built a formula that predicts how many bikes will be rented on a given day.

How good is it? It explains about two-thirds of the day-to-day swing in demand and tracks actual rentals closely, reporting a sensible range rather than a single number.

What drives demand:

  • Weather above all, a rainy day can cut rentals by up to 75%.
  • Temperature, warmer days are busier (about +33% per 5°C).
  • The calendar, working days beat weekends; holidays are quiet.

A note on method. Daily counts bounce around far more than a simple model expects, so we used one built for that (a "negative binomial"), which makes the forecast's confidence honest.

In practice: let tomorrow's weather forecast set tomorrow's bike plan.

🐍

Run the entire forecast project in Python

The companion notebook is the full 12-step pipeline: it loads and cleans the messy daily export (dates, categories, missing weather), visualizes demand and its seasonal rhythm, engineers calendar features, fits Poisson then negative-binomial regression, diagnoses overdispersion (variance-vs-mean, Pearson chi-square), reads rate ratios, and forecasts a day, with every table and chart explained.

📓 View Notebook (code & outputs) ▶ Open in Colab ⬇ View / Download on GitHub

View opens the rendered notebook instantly. Open in Colab runs it live. To run locally, install numpy, pandas, matplotlib, seaborn, statsmodels, and scikit-learn.

🎓 Key Takeaways

  • Counts need a count model: Poisson regression (log link) predicts a non-negative rate; ordinary regression can predict negative demand.
  • Coefficients exponentiate to rate ratios: heavy rain ×0.25, +5°C ×1.33, working day ×1.10.
  • Overdispersion is the count-model pitfall: the variance-to-mean ratio and Pearson chi-square / df flagged it (in the hundreds).
  • The negative binomial is the fix: it let variance exceed the mean and cut the AIC from ~183,000 to ~11,000, honest error bars, same rate ratios.
  • Same 12-step method as the other case studies, only the model family (and its diagnostic) changed for a count outcome.
7

Take It Further

Five ways to extend the forecast in the notebook:

1

Poisson vs negative binomial, quantified

Compare the two models' standard errors on the weather coefficients to see how much Poisson understated them.

Hint: line up .bse from each fit.
2

Does temperature really curve?

Refit without the squared temperature term and compare AIC; is the curvature worth keeping?

Hint: lower AIC wins; check the fitted temp-response shape.
3

Cross-validate the forecast

Use 5-fold CV to estimate out-of-sample accuracy and confirm the model is not overfit.

Hint: PoissonRegressor with cross_val_score.
4

Weekend vs weekday profiles

Test whether weather hurts weekend demand more than weekday demand (an interaction).

Hint: C(weather) * is_weekend.
5

Forecast a week ahead

Build a 7-row DataFrame from a weather forecast and predict each day's demand with a range.

Hint: get_prediction(...).summary_frame().
📓

All five, worked in a companion notebook

A second notebook, Take It Further, recaps this chapter's model and then works every one of these five extensions with visuals and explanations, the Poisson-vs-NB standard errors, the temperature curve, cross-validation, a weekend-weather interaction, and a week-ahead forecast, closing with a plain-English summary.

📓 View Notebook (code & outputs) ▶ Open in Colab ⬇ View / Download on GitHub
8

Quiz: Test Yourself

Eight questions on the count-regression case study. Answer them, hit Check Answers, and keep refining until you score 100%. Your progress is saved, so you can hop back to the chapter and return anytime.

🏁
Onward

You have now modeled a number, a yes/no, and a count, end to end. Predicting Medical Charges tackles the last frontier of this Part: a regression with many predictors, where regularization picks the signal from the noise.