Week 5 · Sunday — consolidate and defend
Forecasting studio 5: repair an invalid backtest and explain horizon and segment errors
Project thread forecasting · linked lessons day 21, day 22, day 23, day 24, day 25
Milestone W5-b: a repaired backtest with every flaw documented, an evidence-based explanation of horizon and segment error differences, and pre-registered Week 6 freeze criteria. Together with Saturday, this is the Week 5 main evidence in Appendix C: backtest configuration and results, and demonstrated cutoff correctness.
- 90 minsession length
- 4timed blocks
- 5tasks
- —status
Session plan90 min
Before you start
Prepare before the session (2 minutes). Save the following as forecasting-project/review/flawed_w05.py. It is
scaffolding with deliberate flaws, so do not reuse it.
# flawed_w05.py - a rolling-origin backtest for the D-14 forecast (contains deliberate flaws; do not reuse)
import sqlite3
import pandas as pd
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.metrics import mean_absolute_error
con = sqlite3.connect("python/artifacts/airline_sample.sqlite")
df = pd.read_sql("""
SELECT f.date, f.flight_no, f.route, f.weekday, f.holiday, f.capacity, f.competitor_price,
f.bookings_final, b.cumulative_bookings AS bk_d14
FROM flight_day f
JOIN booking_curve b ON b.date = f.date AND b.flight_no = f.flight_no AND b.days_to_departure = 14
""", con, parse_dates=["date"]).sort_values(["flight_no", "date"])
g = df.groupby("flight_no")["bookings_final"]
df["lag_7"] = g.shift(7)
df["roll_28"] = g.transform(lambda s: s.rolling(28, min_periods=7).mean())
df["snaive_364"] = g.shift(364)
feats = ["weekday", "holiday", "capacity", "competitor_price", "bk_d14", "lag_7", "roll_28"]
rows = []
for origin in pd.date_range("2023-07-01", "2024-06-01", freq="MS"):
train = df[df["date"] < origin]
test = df[(df["date"] >= origin) & (df["date"] < origin + pd.DateOffset(months=1))]
m = HistGradientBoostingRegressor(random_state=0).fit(train[feats], train["bookings_final"])
rows.append({"origin": origin.date(),
"mae_model": mean_absolute_error(test["bookings_final"], m.predict(test[feats])),
"mae_snaive": mean_absolute_error(test["bookings_final"], test["snaive_364"])})
res = pd.DataFrame(rows)
print(res.round(1).to_string(index=False))
print("mean MAE model", round(res["mae_model"].mean(), 1), "| seasonal naive", round(res["mae_snaive"].mean(), 1))
Run it from the repository root with uv run --project python python forecasting-project/review/flawed_w05.py. It
takes well under a minute on a laptop. You also need your Saturday files: configs/backtest_w05.yaml,
outputs/backtest_w05.csv, the availability-check code and the contract. The colleague and the RM lead are
simulated.
Blocks4
Block 1: Spaced recall
20 minAnswer the prompts in task
recall-week5closed-book (12 minutes). Then check them against lessons 21-25 and your recall log (8 minutes), and log misses with corrections. Include at least one item that you missed in Weeks 2-4.Block 2: Improve - inspect and repair an invalid backtest
40 minA simulated colleague's backtest,
review/flawed_w05.py(see setup), reports excellent skill against seasonal naive.- Minutes 0-5 - commit. Run it, note the printout, and write one sentence on whether you trust it, before you read the code closely.
- Minutes 5-20 - find the flaws (task
review-backtest). - Minutes 20-32 - repair (task
repair-backtest). Repair using your Saturday cutoff checks, then re-run. - Minutes 32-40 - explain (task
explain-errors). Explain the horizon and segment differences in your own backtest.
If Saturday's candidate was carried forward, run it in the first 15 minutes and repair only the two most severe flaws.
Block 3: Teach-back - why the repaired numbers differ
20 minExplain to a simulated RM lead, in at most 200 words written or 3 minutes spoken (task
teach-back):- why the colleague's backtest looked better;
- what the repaired and your own backtests show by horizon and market;
- which forecast you would trust for which segment.
Then answer the lead's simulated follow-up question.
Block 4: Weekly review and planning
10 minWeek 5 review in
decision-log.md:- lessons 21-25 status;
- studio status;
- recall misses.
Write the Week 6 freeze criteria now, before any test data is seen. These are the rules that will pick the final design from backtest evidence, for example "the lowest mean decision cost across origins, with skill below 1 on at least 9 of 12 origins; otherwise the pickup baseline".
Tasks5
Task 1
recallAnswer closed-book:
- Name three ways a structural break differs from seasonality in a plot.
- What does an ACF spike at lag 7 in daily departures suggest? What does it not prove?
- Why can over-differencing hurt?
- Why is AIC not out-of-sample accuracy?
- What is the minimum safe lag of
bookings_finalfor a D-14 forecast, and why? - Expanding vs sliding window: when does each help?
- Why report error per horizon instead of pooled?
- Give one item missed in Weeks 2-4.
Task 2
reviewList every flaw in
flawed_w05.pywith its line, the mechanism, and whether it inflates the model's score, the baseline's score, or only the reporting. Rank them by severity.Task 3
codeWrite
review/repaired_w05.py: the smallest version that removes every flaw you listed inreview-backtest. It must follow your Saturday conventions (contract, horizon-specific gaps, baselines) and report per origin and per market next to the baselines of your own backtest.Run your Saturday availability check against its features. Compare its results with the flawed printout and with your own
backtest_w05.csv.Task 4
analysisUsing
backtest_w05.csv, explain:- (a) the D-30 against D-14 difference for the pickup baseline;
- (b) why the seasonal naive's error does or does not depend on horizon, given what it uses;
- (c) the market differences;
- (d) whether the three 2024-03-01 break routes behave differently in origins after March 2024.
Cite numbers for each.
Task 5
defenseWrite or record the explanation for the simulated RM lead (at most 200 words). Then answer the follow-up question, "So should we stop using the seasonal naive?", in at most 60 words.
Rubric4 criteria
| Criterion | Meets | Exceeds |
|---|---|---|
| Backtest flaw detection | At least four of the six flaws are identified, including the ones that directly break the D-14 cutoff. | All six are identified and ranked, with an ablation showing which flaw causes most of the inflation. |
| Repair and verification | The repaired backtest runs, passes the availability check, and is compared with the learner's own backtest. | The repair reuses the project's backtest function and configuration rather than duplicating logic. Remaining differences are fully reconciled. |
| Horizon and segment explanation | Horizon and market differences are explained with numbers and plausible mechanisms. | Separates evidence from hypothesis, notes how few post-break origins exist, and says what further evidence would settle the question. |
| Pre-registration | Week 6 freeze criteria are written before any test data are seen. | The criteria include a fallback rule and a decision-cost criterion, not only MAE. |
Required output
Saved in forecasting-project/:
review/backtest-review-w05.md, with the committed sentence, the ranked flaws and the comparison table;review/repaired_w05.py, runnable, with its availability-check output;- the four error explanations and the teach-back text;
- the pre-registered Week 6 freeze criteria in
decision-log.md; - updated
notes/recall-log.md.
This completes the Week 5 main evidence: backtest configuration and results, and demonstrated cutoff correctness.
Studios are tracked separately from the 60 core lessons; completing one never completes a lesson.