#!/usr/bin/env python3 # Author: Simon-Pierre Boucher — contact@spboucher.ai """Step 02 — The horse race. Fits the twenty registry models under (i) a random 80/20 holdout and (ii) a forward-in-time holdout (train < 2025, test 2025–2026), plus the Box–Cox profile likelihood and summary statistics. Writes: horserace_random.csv, horserace_temporal.csv, boxcox.csv, summary_stats.csv, sample_counts.csv Usage: python scripts/02_horserace.py """ import sys from pathlib import Path import pandas as pd sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) from wp11 import config, models, sample # noqa: E402 def main() -> None: config.ensure_dirs() df = sample.load() out = config.REPRODUCED # ------------------------------------------------------------ Table 1 desc = {"price": "Sale price ($)", "area": "Floor area (m2)", "lot": "Lot area (m2)", "age": "Building age (years)", "floors": "Storeys", "units": "Dwelling units"} rows = [] for var, label in desc.items(): s = df[var] rows.append({"variable": label, "n": len(s), "mean": s.mean(), "sd": s.std(), "p10": s.quantile(.10), "p50": s.median(), "p90": s.quantile(.90)}) pd.DataFrame(rows).to_csv(out / "summary_stats.csv", index=False) counts = {"n_sales": len(df), "n_munis": df["muni"].nunique(), "n_grid": df["grid"].nunique(), "n_grid5": df["grid5"].nunique()} for k, v in df.groupby("prop_class").size().items(): counts[f"n_{k}"] = int(v) pd.Series(counts).to_csv(out / "sample_counts.csv") # ------------------------------------------------------------ Box–Cox profile d = models.add_derived(df) d["sale_year_c"] = d["sale_year"].astype(str) train, _ = models.split(d, "random") lam, prof = models.fit_boxcox(train, models.NUM_LEVELS, models.CATS + ["muni", "quarter"]) prof["chosen"] = prof["lambda"] == lam prof.to_csv(out / "boxcox.csv", index=False) print(f"Box–Cox lambda* = {lam}") # ------------------------------------------------------------ the race for scheme in ("random", "temporal"): res = models.run_horserace(df, scheme) res.to_csv(out / f"horserace_{scheme}.csv", index=False) if __name__ == "__main__": main()