Repository Public Research preview
1# Changelog — révision scientifique complète (editorial board, 2026-10-17)23Papier : **WP 11 — Half a Million Prices, Twenty Models** (v1.0, August 2026 → **v1.1, October 2026**).4État de référence : tag git `pre-revision-20261017`, PDF `docs/main_pre-revision-20261017.pdf` (23 pages).5Rapport scientifique associé : `docs/REVIEW-REPORT.md`.67## 1. Corrections majeures (où / avant / après / pourquoi / preuve)89### 1.1 Règle de retransformation asymétrique → scoreboard uniforme (correction centrale)10- **Où** : `src/wp11/models.py` (`fit_predict`, `run_horserace`), §4.3 Methodology, §5, §7.1, abstract, intro, conclusion.11- **Avant** : les modèles linéaires en log (A2, A3, A5, A6, B*, C*, D1, D2) étaient multipliés par le facteur de12 smearing de Duan (ŝ ≈ 1.06–1.08) ; les ensembles d'arbres (D3, D4, D5) et le k-NN (D6) ne l'étaient pas13 (`np.exp(pred)` nu). Les métriques log (RMSE_ln, R²_ln) étaient calculées sur la prédiction smearée pour une14 famille et non pour l'autre.15- **Après** : règle « médiane » (inversion directe de la prédiction transformée, éq. 10) appliquée **à tous** les16 modèles pour le tableau principal ; règle « moyenne » (Duan, éq. 11, généralisée au Box–Cox par moyenne sur17 1 000 résidus) calculée pour tous et rapportée en robustesse (Table 12).18- **Pourquoi** : la comparaison v1.0 opposait un A6 smearé (19.1 %) à un D4 non smearé (21.2 %) dans le split19 temporel — le « renversement » annoncé en titre de la v1.0 était un artefact : (i) résidus log asymétriques20 à gauche (skewness −1.4 à −1.8, médiane +0.06) donc le smearing abaisse par coïncidence la MdAPE de tout modèle21 log ; (ii) marché haussier en 2025-26 : tout facteur > 1 compense une partie de la staleness. Appliquée22 uniformément, aucune des deux règles ne renverse le classement (médiane : A6 21.7 vs D4 21.2 ; moyenne :23 19.1 vs 18.4).24- **Preuve** : `results/reproduced/horserace_{random,temporal}.csv` (colonnes `mdape` vs `mdape_mean`, `smear`),25 `results/tables/retransformation.tex`, médianes de résidus vérifiées sur `data/processed/predictions_*.parquet`.26- **Chiffres modifiés (ancien → nouveau, MdAPE %)** — random : A1 18.2→18.2, A2 18.2→19.0, A3 17.0→18.0, A4 18.6→18.6,27 A5 18.1→19.2, A6 16.5→17.6, B1 21.1→22.0, B2 18.1→19.1, B4 18.3→19.3, C1 27.9→28.8, C3 17.5→18.7, C4 19.4→21.0,28 D2 16.7→17.7 ; D3/D4/D5/D6 inchangés (14.6/14.4/23.2/21.2). Forward : A1 20.4→20.4, A2 20.6→23.2, A3 19.2→21.8,29 A4 21.0→21.0, A5 20.5→23.3, A6 19.1→21.7, B1 25.4→29.3, B2 21.0→23.7, B4 20.3→22.9, C1 26.5→29.0, C3 21.3→24.3,30 C4 22.1→25.3, D2 19.5→22.3 ; D3/D4/D5/D6 inchangés (21.3/21.2/26.2/25.6). R²_ln des modèles log : +0.01 à +0.0431 (random), −0.03 à −0.04 (forward).32- **Conséquence narrative** : « the ranking reverses » (v1.0) → « the gap shrinks from 3.2 to 0.5 points and loses33 significance ; relative skill transfers intact, the level does not » (v1.1). Abstract, §1, §5.5, §8, §9 réécrits.3435### 1.2 Inférence statistique ajoutée (absente en v1.0)36- **Avant** : aucun intervalle, aucun test ; le README affirmait « design clustered by municipality » sans aucune37 implémentation.38- **Après** : `src/wp11/inference.py` — bootstrap par grappes (municipalités, B = 500) pour la MdAPE de chaque39 modèle et pour les différences ; test de type Diebold–Mariano / Giacomini–White à erreurs-types groupées sur les40 pertes APE et log² (éq. 13). Tables 4 (tous les modèles vs A6) et 5 (13 paires ciblées).41- **Résultats clés** : D4 vs A6 random −3.2 [−4.7, −1.9] (t = −3.6) ; forward −0.5 [−1.7, +0.6] (t = −1.6, p = 0.11) ;42 C3 vs C2 random −0.45 [−1.07, +0.37] (n.s.) ; C4 vs C2 +1.8 [+1.2, +2.3] ; B4 vs B3 +0.19 [+0.01, +0.37] ;43 D2 vs A6 +0.06 [−0.02, +0.16] (n.s.).44- **Conséquence** : la phrase « the 5.5 km grid beats municipality effects » est ramenée à « nominally better,45 within bootstrap noise » ; « month effects indistinguishable from quarter » précisé (légèrement pires, significatif).4647### 1.3 Décomposition du « generalization gap » (nouveau)48- Comparaison à période fixe (modèles random évalués sur les 31 465 ventes 2025-26 de leur test) : D4 13.7 → 21.249 (coût de staleness 7.5), A6 17.0 → 21.7 (4.7), A1 17.1 → 20.4 (3.3). Biais de niveau médian forward : D4 +0.183,50 A6 +0.161, A1 +0.102. MdAPE re-nivelée forward : D4 13.9 vs A6 16.8 (écart 2.9 ≈ écart random 3.5).51 Par trimestre : avance D4 sur A6 de 1.5 pt (2025Q1) → 0 (2026Q3).52- Fichiers : `same_period.csv`, `relevel.csv`, `by_quarter.csv` ; Tables 8–9, Figure 6 (nouvelle).5354### 1.4 Fuite d'information dans le split aléatoire (nouveau)55- Faits : 20.6 % des ventes sont des reventes d'une même parcelle ; 30.3 % partagent des coordonnées exactes avec56 une autre vente (91.6 % des condos). Colonnes `parcel`, `coord` ajoutées à `sample.py` (reconstruction du57 parquet d'analyse, 514 212 ventes identiques).58- Splits groupés (`split("group_parcel")`, `split("group_coord")`) : course complète. Parcelle : D4 14.5 / A6 17.659 (≈ inchangé). Bâtiment : D4 14.6 / A6 17.8 (écart 3.2 identique) ; seul D6 se dégrade (21.2 → 22.3).60 Décomposition vu/non vu : D4 12.0 vs 15.3 (coord.), A6 17.8 vs 17.6 ; condos D4 8.9 vs 10.2.61- Tables 13–14 ; §4.4, §7.2.6263### 1.5 Effets spatiaux fins : « seventeen K sales » et repli arbitraire64- **Avant** (§5.3) : « its cells average seventeen K sales each » — faux : 514 212 / 30 548 = 16.8 ventes par cellule65 (médiane 3). Corrigé. Cellules non vues (2.5 % des ventes test) tarifées au niveau de la cellule de référence :66 désormais explicité.67- **Nouveau** : C3′ (muni + grille 5.5 km) et C4′ (muni + grille 1.1 km) — solution de norme minimale (ridge α→0)68 ≈ pooling partiel vers la municipalité. Random : C4′ 17.3 % (meilleure spécification linéaire du papier),69 C3′ 17.7 % ; forward : 21.6 / 21.5 vs C2 23.3. Conclusion de l'axe C reformulée : « hierarchy, not coarseness ».70 Table 15 ; `nested_fe.csv`.7172### 1.6 Box–Cox : grille fine73- Grille 0.05 sur [−0.25, 0.75] : λ̂ = 0.35 (profil plat 0.25–0.55 à la tolérance du solveur itératif) ;74 MdAPE random 18.4 % (vs 18.6 % à 0.25). `boxcox_fine.csv`. Texte §5.1 et §7.4.7576### 1.7 Hyper-paramètres du boosting77- Quatre configurations alternatives (shallow, deep, régularisée, early stopping sur les 10 % derniers mois78 d'entraînement) sous les deux splits. `hgb_sensitivity.csv`, Table 16, §7.5. Random 14.3–14.7 % (baseline 14.4), forward 21.2–21.6 % (baseline 21.2) ; early stopping : 700 / 1 000 itérations, reproduit le baseline à 0.1 pt.7980### 1.8 Statistiques descriptives incohérentes81- **Avant** (§3.2, README) : « Prices average $462,000 (median $399,000) ». **Table 1** : 440 207 / 397 375.82 **Après** : texte aligné sur la table ; ajout des 86 logements de classe indéterminée (la somme des classes v1.083 faisait 514 126 ≠ 514 212) ; répartition par année ; nettoyage des lots > P99.5 explicité (était silencieux84 dans `sample.py`) ; bornes âge/étages/logements explicitées.8586### 1.9 Indices et profils : affirmations adoucies87- **Avant** : « all five [indices] agree to within a few index points » ; « curves sit within a tenth of a log88 point ». **Après** : les quatre formes linéaires s'accordent à ≤ 2.5 points ; l'indice boosting finit 9 points89 plus bas (160.5 vs 168.6–171.0 ; écart max 10.9) ; profil d'âge du boosting uniformément plus plat de 0.10–0.1390 log-point à partir de 20 ans (−0.20 vs −0.31 à 40 ans), surface : ≤ 0.05. Chiffres vérifiés dans91 `index.csv`, `profiles.csv`.92- Learning curves recalculées (règle médiane) : OLS 19.1 → 19.2 (v1.0 : 18.4 → 18.1) ; GB 17.6 → 14.5 ; écart93 1.6 → 4.7 pts (v1.0 : < 1 → 3.6). Segments : condo 18.2 vs 9.1 (v1.0 OLS 20.4), grandes villes 17.7 vs 11.9,94 petites municipalités 24.8 vs 18.7 (v1.0 23.3), chalets 34.3 vs 32.1 (v1.0 33.9).9596### 1.10 Méthodologie formalisée97- §4 réécrit : équations (1)–(13) — fonction hédonique générale, six formes A1–A6, profil de vraisemblance Box–Cox98 (avec jacobien), ridge, règle k-NN, règles médiane/Duan, métriques, test DM groupé. Documentation du traitement99 des catégories non vues, du carry-forward et de son analogue pour les arbres (correction de la phrase « clamped100 month counter » : rien n'est écrêté dans le code ; les arbres sont constants par morceaux).101102### 1.11 Autres corrections éditoriales103- « 13 % improvement » → « 18 % » (14.4 vs 17.6) ; « 13–21 % » → « 18–25 % » ; intro « 27.9 % versus 17.5 % »104 vs README « vs 18.1 % » harmonisé (28.8 vs 19.2, référence = backbone C2).105- Hiérarchie de la discussion : liste à puces → prose (règle de style du protocole).106- Mots-clés harmonisés au vocabulaire commun (« hedonic price function », « forward-in-time holdout »,107 « automated valuation model »).108- `\WPversion` 1.0 → 1.1 ; `\WPdate` August 2026 → October 2026 ; page titre canonique intacte ; macro109 `\companionpaper` conservée (main.tex / main_anon.tex).110111## 2. Références112113### Vérifiées (Crossref `api.crossref.org/works?query.bibliographic=…`, 2026-10-17) et corrigées114Toutes les entrées conservées de la v1.0 (31) ont été retrouvées sur Crossref et dotées de leur DOI. Corrections :115- `box1964analysis` : pages 211–252 → **211–243** (244–252 = discussion).116- `bogin2020house` : number 1 → **1–2** ; DOI 10.1007/s11146-019-09712-0.117- `silver2018house` : l'article EURONA 2018 n'est pas indexé ; remplacé par la version vérifiée **IMF Working Paper118 16/213 (2016)**, DOI 10.5089/9781475552249.001, même titre (ordre des mots corrigé).119- `ke2017lightgbm` : @article → **@inproceedings** (NIPS 2017, non indexé Crossref ; actes Curran Associates).120- `malpezzi2003hedonic` : DOI 10.1002/9780470690680.ch5 ; `anselin1988spatial` : DOI 10.1007/978-94-015-7799-1.121122### Retirées (non citées dans le texte et bibliographiquement défectueuses)123- `knight2003listing` (volume/pages vides ; en réalité chapitre Springer 2008, pp. 39–54).124- `diewert2004hedonic` (« Mimeo » en champ journal ; non indexé).125126### Ajoutées (27, toutes vérifiées sur Crossref, DOI dans le .bib)127hill2018geospatial (RIW 64(4) 737–756) · pace2020residuals (JREFE 60 170–180) · lorenz2023interpretable128(REE 51(5) 1178–1208) · diewert2016tokyo (RSUE 60 300–315) · diewert2015decomposition (Econometric Reviews 34129106–126) · diebold1995comparing (JBES 13(3) 253–263) · giacomini2006tests (Econometrica 74(6) 1545–1578) ·130bergmeir2012crossvalidation (Information Sciences 191 192–213) · roberts2017crossvalidation (Ecography 40(8)131913–929) · kuminoff2010which (JEEM 60(3) 145–160) · bishop2020best (REEP 14(2) 260–281) · bourassa2007spatial132(JREFE 35(2) 143–160) · bourassa2003submarkets (JHE 12(1) 12–28) · goodman2003segmentation (JHE 12(3) 181–201) ·133zurada2011comparison (JRER 33(3) 349–388) · antipov2012mass (ESWA 39(2) 1772–1778) · perezrave2019machine134(J. Property Research 36(1) 59–96) · mccluskey2013prediction (JPR 30(4) 239–265) · schulz2014automated (JPR 31(2)135131–153) · fik2003modeling (REE 31(4) 623–646) · clapp2003semiparametric (JREFE 27(3) 303–320) ·136pace1998spatiotemporal (JREFE 17(1) 15–33) · dube2013pooled (LSRS 6(1) 1–18) · hill2009boom (JHE 18(3) 193–205) ·137manning2001estimating (J. Health Econ. 20(4) 461–494) · thibodeau2003marking (REE 31(1) 1–22) ·138khoshnoud2023evolution (JREL 31(1) 1–47).139Total : 33 → **58** entrées (31 conservées + 27 ajoutées), toutes citées, toutes vérifiées.140141## 3. Réanalyses exécutées (laptop, Apple Silicon 18 cœurs, Python 3.14 / scikit-learn 1.6.1)142143| Script | Contenu | Durée | Sorties |144|---|---|---|---|145| `01_build_sample.py` | reconstruction de l'échantillon (+ clés `parcel`, `coord`) — 514 212 ventes identiques | 2 s | `data/processed/analysis.parquet` |146| `02_horserace.py` | 20 modèles × 2 splits, règles médiane + Duan, prédictions sauvegardées | 3 min 28 s | `horserace_*.csv`, `boxcox.csv`, `predictions_*.parquet` (non commités) |147| `03_extensions.py` | indices, profils, learning curves, segments (règle médiane) | 4 min 18 s | `index.csv`, `profiles.csv`, `learning.csv`, `segments.csv` |148| `06_robustness.py` (nouveau) | bootstrap + DM, même période, par trimestre, fuite, re-nivellement, paires, splits groupés (2 courses complètes), FE emboîtés, Box–Cox fin, sensibilité HGB | 16 min 16 s | `inference_*.csv`, `same_period.csv`, `by_quarter.csv`, `leakage.csv`, `relevel.csv`, `pairs.csv`, `horserace_group_*.csv`, `nested_fe.csv`, `boxcox_fine.csv`, `hgb_sensitivity.csv` |149| `04_make_figures.py` | 10 figures (+ `fig_horizon.png`) | < 1 min | `figures/` |150| `05_make_tables.py` | 16 tables LaTeX (9 nouvelles) | < 1 s | `results/tables/` |151152Tous les nombres du texte proviennent de ces sorties ; aucune table n'est tapée à la main.153154## 4. Éléments non modifiés / analyses recommandées non exécutées155- Modèle linéaire à surface spatiale (krigeage des résidus, splines bivariées en lat/lng, effets hiérarchiques156 bayésiens) : non estimé (hors cadre « 20 modèles ») — recommandé pour fermer l'écart linéaire/boosting par l'autre157 côté.158- Holdout spatialement bloqué (cellules entières en test) : non exécuté (change la question en extrapolation159 spatiale ; les FE spatiaux y sont par construction inopérants).160- Re-nivellement par un indice **publié** (hors échantillon, non oracle) : non exécuté (aucun indice externe161 chargé ; le re-nivellement présenté utilise le ratio médian du test, borne supérieure).162- Variante « médiane calibrée » (exp(ẑ + médiane des résidus d'entraînement)) : discutée, non tabulée.163- Fenêtres temporelles alternatives (p. ex. train < 2024, test 2024) : non exécutées — limite déclarée §8.4.164- Comparaison avec LightGBM / XGBoost natifs ou réseaux de neurones : hors périmètre.165- La règle de nettoyage des lots > P99.5 → 0 (héritée) est documentée mais conservée pour préserver l'échantillon.166