SPB Git

spb/wp9_uqo Public

UQO Working Paper No. 9 — A grand hedonic model of the Canadian housing market: decomposing structure and location value.

TeX 60.1% Python 39.8%
9.8 KB · 147 lines markdown
Rendered Raw Blame History
1# AUDIT — UQO Working Paper 9 (`immo-wp9-spb-20260529`)23**Audit date:** 2026-08-054**Original location:** `~/Desktop/UQO/UQO_WP/immo-wp9-spb-20260529` (left untouched)5**New clean repository:** `~/Desktop/wp9_uqo`67## 1. What the project is89UQO Working Paper No. 9, *"A Grand Hedonic Model of the Canadian Housing Market"*10a semi-logarithmic hedonic price model estimated on 140,931 Canadian MLS listings with111,153 FSA (Forward Sortation Area) neighbourhood fixed effects, plus out-of-sample12validation, robustness, quantile regressions, spatial diagnostics (Moran's I),13leave-one-province-out cross-validation, and a variance decomposition.1415## 2. File inventory (original, 55 files, ~749 MB)1617### Data18| File | Role |19|---|---|20| `realtor_mls_unique.duckdb` (747 MB) | **Raw data.** Single table `listings`, 172,019 rows, 81 columns (all VARCHAR except `price_cad`, `lat`, `lon`). This is the only data file; the paper's estimation sample (140,931 rows) is derived from it. |2122### Analysis code (`analysis/`)23| Script | What it does | Outputs |24|---|---|---|25| `estimate_ext.py` | 80/20 out-of-sample validation of the FSA-FE hedonic model; living-area-elasticity heterogeneity by province; robustness across 6 samples; FSA location-premium ranking. | `oos.json`, `heterogeneity.csv`, `robustness.csv`, `fsa_premia.csv` |26| `estimate_ext2.py` | Quadratic (nonlinearity) spec; quantile regressions; distance-to-metro gradient; Moran's I on residuals; leave-one-province-out CV; variance decomposition. | `ext2.json`, `lopo.csv`, `tables/quantile.tex`, figures `fig_nonlinear/quantile/gradient/moran/decomp.png` |27| `make_assets.py` | Copies 9 upstream figures; builds `fig_heterogeneity/premia/oos.png`; writes `tables/summary_stats/regression/robustness/oos.tex`. | figures + tables |28| `ml_benchmark.py` | XGBoost / LightGBM / PyTorch-MLP benchmarks vs. the hedonic model. | `ml_compare.csv/json`, `tables/ml.tex`, `fig_ml_compare/importance.png`**none of these outputs exist on disk and the paper never references them → dead code for this paper.** |2930### Stored analysis outputs (reference values for verification)31`analysis/oos.json`, `ext2.json`, `robustness.csv`, `lopo.csv`, `heterogeneity.csv`,32`fsa_premia.csv` — all present and internally consistent with the numbers quoted in the33paper. These are the ground truth I verify the rebuilt pipeline against.3435### Figures (`figures/`, 7 present of 17 referenced by the paper)36Present: `fig_price_dist`, `fig_fit`, `fig_resid` (copied from upstream),37`fig_decomp`, `fig_nonlinear`, `fig_gradient`, `fig_premia` (locally generated).38**Missing (10):** `fig_province_ppm2`, `fig_r2`, `fig_forest`, `fig_size_gradient`,39`fig_map`, `fig_fsa_map` (upstream-only), and `fig_quantile`, `fig_moran`,40`fig_heterogeneity`, `fig_oos` (locally generated but deleted at some point).4142### Tables (`tables/`, 6 files)43`summary_stats.tex`, `regression.tex`, `robustness.tex`, `quantile.tex`, `oos.tex`,44`lopo.tex`. All referenced by the paper. Note: `lopo.tex` is **hand-written** — no script45produces it (`estimate_ext2.py` only writes `lopo.csv`).4647### LaTeX48| File | Role |49|---|---|50| `main.tex` | Real paper: preamble + metadata + `\input{sections/*}`. Already reasonably modular. |51| `main_web.tex` | Duplicate of `main.tex` plus an `\includegraphics` override that prints a *"Figure indisponible"* placeholder box when a figure file is missing. |52| `sections/*.tex` (8) | titlepage, introduction, literature, data, methodology, results, robustness, conclusion. |53| `references.bib` | 32 entries, `aer` style with natbib. |54| `uq_logo.jpg` | UQO logo for the title page. |55| `Makefile`, `.latexmkrc` | latexmk build config. |5657### Dead / generated / junk files58- Build artifacts: `main*.aux/log/out/fls/fdb_latexmk`, `main_web.bbl/blg/synctex.gz` — regenerate on compile.59- `main_web.pdf` (24 p., June 13): **compiled with placeholder boxes instead of every figure** — the `\IfFileExists` fallback does not search `\graphicspath`, so even the 7 existing figures were replaced by boxes. There is no valid compiled PDF of the actual paper.60- `main.pdf`: does not exist (never successfully compiled, or deleted).61- `ml_benchmark.py`: dead for this paper (outputs unused, see above).62- `.DS_Store` files.6364## 3. Critical findings65661. **The upstream pipeline is gone.** All three live scripts read67   `~/Desktop/RE_DB_QC/hedonic/data/analysis.parquet` and68   `~/Desktop/RE_DB_QC/hedonic/output/fit.json` / `coef_M*.csv`. That directory no longer69   exists anywhere on disk. The cleaning code (duckdb → `analysis.parquet`) and the70   M1–M5 estimation code were never inside this project.71   **Consequence:** the pipeline had to be reconstructed from (a) the raw DuckDB, which72   *is* in the project, (b) the precise description of sample construction in73   `sections/data.tex`, and (c) the stored outputs/tables used as exact numerical targets.742. **No usable compiled PDF existed** (see above).753. **10 of 17 figures missing** and must be regenerated by the reconstructed pipeline.764. Paths in all scripts are absolute and machine-specific; no `requirements.txt`,77   no README, no reproducibility instructions.785. Hard-coded constants in scripts: the dashed reference line `0.547` in79   `fig_nonlinear` and the metro coordinates list (duplicated in two scripts).806. `\WPemail` in the paper is `simon-pierre.boucher@uqo.ca` (kept as-is in the rewrite;81   code headers use `contact@spboucher.ai` per instruction).8283## 4. Reference targets used for verification (from the original outputs)8485- Sample: **N = 140,931** (houses 82,334; condos 57,857); 1,153 absorbed FSAs; raw N = 172,019.86- Grand model M5: R² = 0.767; ln-living 0.547 (0.009); bath 0.109 (0.004); ln-lot 0.030 (0.004).87- Ladder R²: M1 0.464, M2 0.469, M3 0.567 (houses); M5 0.767.88- OOS: R² 0.764, RMSE(log) 0.282, median APE 15.8%, within ±10% 33.8%, ±20% 59.5% (train 112,732 / test 28,187).89- Moran's I: 0.459 → 0.082; gradient −0.0854; nonlinearity b1 = 1.065, b2 = −0.0526; LOPO mean 0.362.90- Full details in `analysis/*.{json,csv}` and `tables/*.tex` of the original.9192## 5. Reproduction verification — rebuilt pipeline vs. original outputs9394The cleaning pipeline was reconstructed from the paper's data section and calibrated95against the stored outputs. Decisive validated choices: `_province` (scraper seed) is the96province variable; living area prefers `building.floor_area_measurements` with banded97entries mapped to the **upper bound** of the band (this uniquely matches the published98living-area distribution and the M3 elasticity of 0.585 exactly); bedrooms "3 + 1" summed;99FSAs with <25 listings pooled to `<PROV>_other`; 1%/99% trim of price and living area.100101**Everything below refers to `results/reproduced/` (script output). The paper itself uses102`results/reference/` — the original stored outputs — so no published number changed.**103104| Quantity | Original (paper) | Reproduced | Note |105|---|---|---|---|106| Sample N | 140,931 | 142,146 | +0.86% |107| Houses / Condos | 82,334 / 57,857 | 83,542 / 57,860 | condos match to 3 listings |108| Absorbed FSA levels | 1,153 | 1,155 | |109| R² M1 / M2 / M3 (houses) | 0.464 / 0.469 / 0.567 | 0.467 / 0.470 / 0.569 | |110| R² M4 / M5 | 0.762 / 0.767 | 0.766 / 0.770 | |111| M5 ln living | 0.547 (0.009) | 0.530 (0.010) | ~2 SE apart |112| M5 full bathrooms | 0.109 (0.004) | 0.111 (0.003) | ✓ |113| M5 half baths / bedrooms | −0.036 / −0.002 | −0.032 / −0.003 | ✓ |114| M5 ln lot / has lot | 0.030 / −0.196 | 0.061 / −0.417 | see (a) below |115| OOS R² / RMSE / med. APE | 0.764 / 0.282 / 15.8% | 0.770 / 0.280 / 15.6% | ✓ |116| OOS within ±10 / ±20% | 33.8% / 59.5% | 34.2% / 60.0% | ✓ |117| Moran's I struct → grand | 0.459 → 0.082 | 0.494 → 0.072 | same conclusion (−85%) |118| Gradient (β log-dist) | −0.0854 | −0.0821 | ✓ |119| Nonlinearity b1 / b2 | 1.065 / −0.0526 | 1.145 / −0.0624 | same shape |120| LOPO mean R² | 0.362 | 0.315 | same ranking (ON best, AB negative) |121| Elasticity by province | 0.44 (NL) – 0.66 (MB) | 0.42 (NL) – 0.72 (SK) | same coastal-vs-Prairies pattern |122| Quantile elasticity τ=.1→.9 | 0.557 → 0.598 | 0.591 → 0.585 | flatter but same level |123124### Remaining discrepancies (flagged, not silently changed)125126(a) **Lot-size parsing.** The free-text `land.size_total` parser could not be recovered127    exactly. The original summary stats (mean 2,621 / SD 10,818 m²) imply the original128    parser bounded large acreages; the reconstruction treats the top 1% of positive parsed129    lots as missing, which matches the SD but shifts the two collinear lot coefficients130    (`ln_lot`, `has_lot`). All other structural coefficients are essentially unaffected.131(b) **Sample off by +1,215 listings (+0.86%)**, concentrated in houses at the 5,000-sqft132    living-area band boundary — an artifact of how the original trim treated the mass of133    listings at exactly the 99th-percentile value. Counts by province and condo counts134    match almost exactly.135(c) **fig_size_gradient / condominium claim.** The original figure was lost. Regenerated136    raw medians show condominiums listing *above* houses of equal size (they concentrate137    in expensive metros), contradicting one descriptive sentence in the original results138    section; the sentence was rewritten to describe the regenerated figure and the139    (supported) conditional claim. See CHANGES.md — requires author review.140(d) `analysis/ml_benchmark.py` (XGBoost/LightGBM/PyTorch benchmark) was **dropped**: its141    outputs do not exist and the paper never references them.142(e) Original `main_web.pdf` had placeholder boxes instead of all figures (its143    `\IfFileExists` fallback ignored `\graphicspath`), so no valid compiled PDF of the144    original paper existed; page-level comparison against the original PDF was therefore145    impossible. The 7 surviving original PNGs were compared instead — the regenerated146    versions are visually identical for the results-driven figures (e.g. `fig_premia`).147