Here's a plan built around the five stage files, with the pedagogical beat each stage is meant to hit.
Run the finished script, show the forecast plot, close it. No typing. "In two hours this is yours."
Goal: nothing is real until you've looked at it.
read_csv("day.csv")— deliberately withoutparse_datesfirst. Rundf.info(), discoverdtedayis anobject. Then re-read withparse_dates=["dteday"]. This is the single most important lesson in the session and it should hurt slightly.head(),shape,describe(),isna().sum()- Rename to human columns:
dteday → date,cnt → rides set_index("date"), then check completeness: comparelen(df)againstpd.date_range(start, end). 731 days, no gaps — but show them the check, because most data does have gaps.- Blanks: the
parse_datesargument, the rename dict.
Goal: raw columns are rarely usable columns.
- Denormalize:
temp * 41,hum * 100,windspeed * 67. Concrete, verifiable, and they see why reading the data dictionary matters. - Decode codes into labels:
season,weathersit,yr → 2011/2012,weekday → day names - Derive:
is_weekend,casual_share = casual / rides - Sanity-check the result — plausible temperature range, no negative counts
- Write
stage2_clean.parquetas the checkpoint everyone can rejoin from
Goal: this is where the insights live. Budget generously.
- Time plot of
rides. Immediately visible: growth from 2011 to 2012, a yearly hump, and enormous day-to-day noise. - Add a 7-day rolling mean. Noise disappears, trend appears. The most useful two lines of code in the whole session.
- Spot the late-October 2012 collapse → Hurricane Sandy. Teaches that outliers usually have causes, and that you look before you model.
- Groupby weekday, plot
casualandregisteredseparately. The payoff moment: registered ridership peaks midweek, casual peaks on weekends. Two populations hiding in one column. - Groupby month → the seasonal shape, cleanly.
- Scatter
ridesvstemp→ clearly non-linear, falls off at both extremes. - Switch to
hour.csv, groupbyhr, split byworkingday→ the commuter double-peak versus the weekend midday hump. Best single visual you'll show; save it for last.
Goal: a forecast is only meaningful next to a baseline.
- Split: train on everything except the final 28 days, test on those 28. Emphasize why the split is chronological, not random.
- Three predictions, each one line:
- training mean
- naive — last observed value
- seasonal naive — the value from 7 days ago
- Compute MAE for all three. Seasonal naive wins, and they can see why from the weekday plot they made in stage 3.
- Plot all three against actuals.
- Stretch prompt: scale seasonal naive by the year-over-year growth ratio. Does MAE improve?
What you deliberately skipped and what it's called — stationarity, ACF, ARIMA, prediction intervals — so they know the vocabulary to search for. Point at the FPP book. Suggested homework: rerun the whole pipeline on hour.csv, or on the Seoul dataset where the columns are different enough to be real practice.
Cut these ruthlessly if you're behind: the temp scatter, the monthly groupby, the growth-ratio stretch. Protect the weekday split, the rolling mean, and the baseline comparison — those three carry the session.
Want me to turn this into the actual stage files now?