SPB Git

spb/qwhpi Public

QHPI — Quebec Housing Price Index: quality-adjusted, hierarchically pooled housing price indexes.

Python 63.9% TypeScript 25.4% CSS 5.5% TeX 3.5% SQL 0.8% Makefile 0.5% Dockerfile 0.5%
4.0 KB

# Hierarchical weekly model — design record

# Architecture chosen (two-stage)

  1. Stage 1 — pooled residualization (pyfixest, n=625,882, R²=0.605, ~3s): log(P) ~ log(floorArea) + fa_missing + age bins + building type | FSA FE + (week × type) FE. The absorbed week×type effects are the province-level weekly paths per property type; residuals are quality- and location-adjusted deviations.
  2. Stage 2 — heteroskedastic local-level Kalman per cell: weekly mean residual observed with variance σ²/n_t; latent deviation is a random walk with innovation τ² estimated by MLE per cell. Region cells deviate from the province path; municipality cells deviate from the smoothed region path. Weeks with zero transactions are pure predictions — the grid is never dropped.

Published variants: index (raw weekly), index_smoothed (one-sided filter, real-time), index_research (two-sided smoother). All three share one rebasing constant (2021 avg = 100), so they are directly comparable.

# Shrinkage behaviour (outputs/tables/hierarchical_summary.csv)

  • Trois-Rivières condo (median 1 tx/week): raw weekly SD 30.4% → smoothed 4.2%.
  • Drummondville condo (median 0 tx/week): still produces a continuous path, ~98% parent-driven (shrinkage weight).
  • Liquid cells (province types, ~300–1,500 tx/week) are data-dominated.

# Benchmark: two-stage vs unified city-specific time-dummy (Step 4 baseline)

Liquid province cells agree almost exactly (corr 0.9996, Québec unifamilial). Montréal condo exposed a genuine specification fork: by July 2026 the two-stage index reads 126.9 vs 118.6 for the city-β baseline.

Arbitration by pseudo repeat-sales (BMN, yearly dummies; condo pairs matched on street + floorArea + yearBuilt because condo addresses carry no unit numbers — 6,079 Montréal condo pairs, ≥90 days between sales):

Measure (2026 level, 2021=100) Montréal condo Province condo Relative
Pseudo repeat-sales (composition-free) 120.4 132.0 −8.8%
Two-stage hierarchical (pooled β) 126.9 138.2 −8.2%
City-specific time-dummy baseline 118.6 ~139 −14%

The two-stage model reproduces the composition-free relative path almost exactly; the city-β baseline overstates Montréal's divergence. Hedonic levels sit a few percent above repeat-sales, the standard direction (depreciation / renovation bias in repeat pairs). Decision: the two-stage hierarchical model is the headline architecture. The unified per-cell time-dummy remains as a robustness spec.

# Compute cost

Full stage 1 + 112 cells of stage 2 run in under one minute on a laptop — weekly refresh is trivially cheap. A Bayesian multilevel variant (PyMC) was rejected for the headline: equivalent shrinkage behaviour at orders of magnitude more compute, and harder vintage reproducibility.

# Known caveats (tracked)

  • se_log combines the province-path delta-method variance and the Kalman posterior variance; block-bootstrap validation of CI coverage is part of Step 6.
  • The Kalman gain-based shrinkage_weight measures how much of a week's movement comes from the parent path; reliability grades therefore weigh n / effective N / SE primarily (Step 7).
  • Montréal plex R² is low (0.20) in any spec — unobserved revenue characteristics; reliability grading must reflect this.

Author: Simon-Pierre Boucher — contact@spboucher.ai