SPB Git forge

spb/wp14_uqo

Public
3commits 1branches 1releases
1.5 MBsize
maindefault branch
37 min agolast push
Python 52.4% TeX 47.6%
15.8 KB · 209 lines markdown
Rendered Raw Blame History
1# Méthodologie — Modèle hédonique de prix des maisons (Québec)23*Pipeline : Realtor.ca + DuProprio → nettoyage → feature engineering (règles + LLM + vision) → régression hédonique log-linéaire à effets fixes.*45---67## 1. Origine des données89| Source | Fichier | Nb enreg. | Nature |10|---|---|---|---|11| **Realtor.ca** | `dataset_realtor-property-crawler_...json` (161 Mo) | 27 302 | Annonces MLS via crawler Realtor (Apify) |12| **DuProprio** | `dataset_duproprio-property-crawler_...json` (87 Mo) | 7 693 | Annonces vente sans intermédiaire (Apify) |1314- **Collecte** : scrapers Apify, extraction le **2026-07-03**. Chaque enregistrement est un objet JSON structuré.15- **Champs communs** : `source`, `url`, `listingId`, `title`, `price`/`priceNumber`, `currency`, `address{full,street,city,province,postalCode,...}`, `property{...}`, `features[]`, `description`, `images[]`, `scrapedAt`.16- **Spécificités** :17  - Realtor : `property.buildingType`, `storeys`, `yearBuilt`, `parkingSpaces`, **`rooms[]`** (dimensions par pièce), pas de coordonnées GPS, images sans caption utile.18  - DuProprio : `property.type`, `levels`, **`coordinates{lat,lon}`** (7 691 présentes), images **avec captions** (`Kitchen`, etc.), pas de `rooms`.19- **Instantané transversal** (cross-section) : un seul point dans le temps → pas de dimension temporelle, donc pas d'effet fixe temporel nécessaire.2021**Identifiant unique** construit : `uid = source + ":" + listingId` (évite toute collision entre les deux espaces d'ID).2223---2425## 2. Construction du dataset combiné « maisons »26271. **Fusion** des deux tableaux JSON (schéma harmonisé).282. **Définition de « maison »** (choix utilisateur : unifamiliales + townhouses) :29   - Realtor : `buildingType ∈ {House, Row / Townhouse}`30   - DuProprio : `type ∈ {Home, Bungalow, Semi Detached, Intergenerational, Country Home, Cottage, Villa, Townhouse}`31   - Exclus : condos, plex (duplex→quintuplex), terrains/lots, fermes, commercial, mobile homes.323. **Filtre prix présent** : `priceNumber` non nul et > 0.3334→ **19 273 maisons avec prix** (15 470 Realtor + 3 803 DuProprio).3536---3738## 3. Nettoyage des aberrations3940Les prix scrappés contiennent des erreurs de parsing (min 899 $, max 368 G$). Règles appliquées :4142| Variable | Règle | Justification |43|---|---|---|44| Prix | garder **50 k$ – 15 M$** | plage plausible d'une maison au QC ; retire loyers mal parsés et concaténations |45| Superficie habitable | 300 – 20 000 ft² (sinon → manquant) | valeurs physiquement possibles |46| Terrain | 200 – 5 000 000 ft² (sinon → manquant) | idem |47| Chambres / sdb | 0–15 / 0–12 (sinon → manquant) | plafonds réalistes |48| **Prix/pied²** | garder **P0,5 – P99,5** (≈ 73–1 276 $/ft²) sur les biens à surface réelle | retire les erreurs résiduelles de parsing prix ou surface |4950→ **19 115 maisons** conservées (158 retirées) dans la première version du pipeline (`04_hedonic_ols_base.py`). Dans la version finale (scripts 05–18), la reconstruction de la surface par les pièces précède le filtre prix/pi², ce qui donne **19 123 maisons** (150 retirées) ; c'est ce chiffre qui figure dans le papier.5152**Principe** : on borne plutôt que de supprimer quand une seule variable est aberrante (on met la variable à *manquant* et on l'impute), pour ne pas perdre l'observation entière.5354---5556## 4. Construction des variables5758### 4.1 Variable cible59`ln_price = ln(priceNumber)` — transformation logarithmique (rend la distribution symétrique, linéarise les effets multiplicatifs, coefficients ≈ **% d'impact sur le prix**).6061### 4.2 Variables structurelles (règles déterministes)62- **Surface & terrain** : parsing d'unités hétérogènes → tout en **pieds carrés**.63  - `"1535 sqft"`, `"1,333.2 ft²"`, `"11 561.52 ft²"` (séparateurs de milliers variés), `"961.6 m2"` (m² × 10,7639).64- **Reconstruction de surface via les pièces (Realtor)** : dimensions `"23 ft ,4 in x 13 ft ,8 in"` → pieds-décimaux → aire ; somme sur toutes les pièces. Calibration sur le recouvrement (ratio médian surface réelle / somme pièces ≈ **0,98**) → sert à combler `squareFeet` manquant.65  - Constat : les annonces à pièces détaillées ≈ celles qui ont déjà `squareFeet` → gain de couverture faible, mais les **comptes/types de pièces** restent informatifs.66- **Autres** : `beds`, `baths`, `parking` (Realtor), `storeys`/`levels`, `age = 2026 − yearBuilt` (+ `age²` pour la courbure), drapeaux `has_*` marquant les valeurs imputées.6768### 4.3 Aménités (règles par mots-clés bilingues)6917 dummies détectés dans `features[] + description + title` (FR/EN) : piscine, bord de l'eau, garage, foyer, climatisation/thermopompe, sous-sol fini, cul-de-sac, golf, ski, proximité parc/école/autoroute/transport, absence de voisin arrière.7071### 4.4 Détail des pièces (Realtor, `rooms[]`)72Nombre de pièces, nombre de niveaux, chambre principale, sous-sol, bureau, salle familiale, atelier, **cellier à vin**, solarium, mezzanine, bibliothèque, buanderie.7374### 4.5 Signaux de listing75Nombre de photos (`n_images`, écrêté à 60), présence de visite virtuelle — proxies de gamme/qualité de la mise en marché.7677### 4.6 Variables géographiques (effets fixes)78- **Ville** nettoyée (Realtor : on retire le quartier entre parenthèses ; minuscules ; normalisation). Villes avec **≥ 20 annonces** → dummy propre ; les rares → `__other__`. ≈ 194 villes en effets fixes.79- **Type de propriété** harmonisé, regroupé si < 30 annonces.80- **Source** (Realtor/DuProprio) → dummy captant les différences systématiques entre plateformes.8182### 4.7 Imputation83Valeurs manquantes après nettoyage : imputées par **médiane par type de propriété** (puis médiane globale), **avec un drapeau `has_*`** pour que le modèle distingue « valeur observée » de « valeur imputée ».8485---8687## 5. Mécanismes IA pour le feature engineering8889Deux couches IA extraient des variables **impossibles à obtenir par règles** — l'une du texte, l'autre des images.9091### 5.1 Extraction de specs depuis la description — **GPT-4o-mini** (OpenAI)92- **But** : transformer la description libre en 20 attributs structurés (état : à rénover→neuf, clé en main, cuisine/sdb rénovée, revêtements de sol, comptoirs quartz/granit, chauffage, vue sur l'eau, revenus locatifs, grand terrain, secteur tranquille, + mots-clés de vente).93- **Mécanisme** : appel Chat Completions avec **`response_format = json_schema` strict** (schéma imposé, énumérations fermées) → sortie JSON valide garantie, pas de parsing fragile. `temperature = 0` (déterminisme). Système : « extracteur factuel, uniquement d'après le texte ; absence → false/inconnu/[] ».94- **Ingénierie** : ~600 tokens in / ~110 out par annonce ; **parallèle** (24 threads), **résumable** (cache `specs.jsonl` clé = uid), **retry** exponentiel sur 429/5xx.95- **Coût/temps** : ~$3 / ~19 k annonces.9697### 5.2 Attributs visuels de façade — **Claude Haiku 4.5** (Anthropic, vision)98- **But** : lire ce que le texte ne dit pas — **état visuel réel, attrait extérieur (curb appeal), niveau de rénovation, matériaux, aménagement paysager, cadre (urbain/banlieue/rural/bord d'eau/boisé), indice de luxe, qualité de la photo**.99- **Sélection d'image** : 1 photo/annonce = la façade. Realtor → 1re photo. DuProprio → photo dont la caption est l'adresse (pas une pièce), via exclusion de mots-clés de pièces.100- **Mécanisme** : Messages API, image passée par **URL** (`source.type = url`, pas de téléchargement), **`output_config.format = json_schema`** (12 attributs, énumérations fermées). Système : « évaluateur objectif ; scores fondés sur critères concrets (surfaces, matériaux, aménagement), pas sur un goût personnel ; si non-extérieur → is_exterior=false ».101- **Ingénierie** : ~2 470 tokens in / ~100 out par image ; **parallèle** (16 threads), **résumable** (cache `facade_specs.jsonl`), **retry** sur 429/5xx/529.102- **Coût/temps** : ~$57 / ~19 k images.103- **Pourquoi Haiku** : modèle vision le moins cher et rapide, largement suffisant pour de la classification d'attributs concrets.104105### 5.3 Pourquoi le JSON structuré strict est central106Le schéma imposé (types + `enum` + champs requis + `additionalProperties:false`) fait valider la sortie **au niveau de l'API** : le modèle est forcé de renvoyer exactement les champs attendus, dans le bon domaine de valeurs. On obtient des variables **directement tabulables**, reproductibles, sans post-traitement de texte libre.107108### 5.4 Intégration au dataset109Les sorties LLM (clé `uid`) sont converties en variables numériques : booléens → 0/1, `condition` → score ordinal 0-5, revêtements → dummies (bois franc, quartz/granit), vue → dummy eau, etc., **avec un drapeau `has_gpt` / `is_exterior`** pour marquer la disponibilité.110111---112113## 6. Modèle économétrique114115### 6.1 Spécification — hédonique log-linéaire à effets fixes116$$\ln(P_i) = \alpha + \beta\,\ln(\text{surface}_i) + \gamma\,\ln(\text{terrain}_i) + \sum_k \delta_k X_{ki} + \sum_c \lambda_c \mathbb{1}[\text{ville}_i=c] + \varepsilon_i$$117118- **Log-log** sur surface et terrain → coefficients = **élasticités** (% prix par % surface).119- **Log-niveau** sur le reste → un coefficient $b$ ≈ **$(e^b-1)\times100$ % d'impact** sur le prix.120- **Effets fixes ville** ($\lambda_c$) : absorbent tout le différentiel de localisation (le plus gros déterminant du prix). Chaque coefficient = prime/décote de la ville vs la ville de référence.121- **Effets fixes type de propriété** et **source**.122123### 6.2 Double spécification (couverture vs richesse)124Realtor ne rapporte `squareFeet` que pour ~38 % des annonces → deux modèles, prédictions combinées :125- **Modèle A (riche)** : inclut `ln(surface)`, estimé sur les biens à surface **mesurée** (réelle ou reconstruite via pièces). Meilleur ajustement.126- **Modèle B (large)** : sans surface, estimé sur **toutes** les maisons → sert à pricer celles sans surface (via beds/baths/terrain/pièces + specs).127- Prédiction finale : A si surface mesurée, sinon B.128129### 6.3 Estimation & inférence130- **MCO (OLS)** sur `ln_price`.131- **Erreurs-types robustes à l'hétéroscédasticité HC3** (les résidus immobiliers sont hétéroscédastiques ; HC3 est conservateur en petit/moyen échantillon).132- **Correction du biais de rétrotransformation** : $\hat{P} = e^{\hat{\ln P}} \times e^{\hat\sigma^2/2}$ (correction normale de Duan) — sinon $e^{\hat{\ln P}}$ sous-estime systématiquement le niveau.133134### 6.4 Interprétation135Coefficients rapportés en **% d'impact prix** + significativité (p-values sur SE HC3). Effets fixes ville présentés comme primes de localisation.136137---138139## 7. Statistiques & diagnostics140141| Indicateur | Signification |142|---|---|143| **R² / R²-ajusté** | part de variance de `ln_price` expliquée |144| **Écart-type des résidus (log)** | → **erreur typique en %** = $(e^{\sigma}-1)\times100$ |145| **Erreur absolue médiane** | \|prix réel / prix prédit − 1\| médian sur toutes les prédictions |146| **% à ±15 % / ±25 %** | part des prédictions dans la fourchette |147| **`resid_pct`** par annonce | surprix/sous-prix vs modèle → repère aubaines & surévaluations |148149Progression observée : v2 (structurel) R²≈0,70 → v3 (+ pièces/photos) R²≈0,72 → v4 (+ specs GPT) → v5 (+ vision) attendu.150151---152153## 8. Limites & biais (transparence)154155- **Endogénéité / non-causalité** : de belles photos ou des specs riches corrèlent avec des courtiers haut de gamme et des biens chers → coefficients **prédictifs**, pas causaux. À ne pas lire comme « ajouter une piscine ⇒ +X % ».156- **Biais de sélection** : uniquement des biens **en vente** (prix demandé, pas prix de transaction) ; les biens sans surface/pièces sont non aléatoires (annonces moins complètes).157- **Imputation** : les médianes par type réduisent la variance des variables imputées (atténuation possible des coefficients) — d'où les drapeaux `has_*`.158- **Extraction LLM** : erreurs/hallucinations possibles ; `temperature=0` + schéma strict + énumérations fermées les limitent, mais pas de validation humaine systématique. La vision juge sur **une seule** photo.159- **Instantané unique** : pas de dynamique de marché ; primes de localisation figées au 2026-07-03.160- **Couverture géographique** : villes < 20 annonces regroupées en `__other__` (moins de finesse spatiale là où les données sont rares).161162---163164## 9. Fichiers produits165166| Fichier | Contenu |167|---|---|168| `hedonic.py`, `hedonic_v4.py` | pipelines reproductibles (nettoyage + modèles) |169| `extract_specs.py`, `facade_vision.py` | extracteurs LLM (texte / vision), parallèles & résumables |170| `specs.jsonl`, `facade_specs.jsonl` | sorties LLM brutes (clé uid) |171| `maisons_hedonic*.csv` | dataset final + prix prédit + `resid_pct` |172| `hedonic_*_summary.txt` | sorties statistiques complètes |173174175---176177## 10. Révision scientifique du 2026-10-17 (version 2.1 du papier)178179Réanalyses locales (`scripts/18_revision_language_leakage_spatial.py`, ~5 min, aucun appel API ; résultats dans180`results/revision_2026-10-17.json`, tables `paper/tables/rob_*.tex` et `agreement.tex`) :181182- **Fuite d'information par le texte.** Les 3 767 descriptions DuProprio de l'échantillon nettoyé contiennent toutes la183  fiche structurée de la plateforme rendue en texte, dont le prix demandé (« Asking Price $499,999 », égal au prix184  enregistré dans 3 761 cas) et, pour 46,6 % d'entre elles, l'évaluation municipale ; 2,5 % des descriptions Realtor.ca185  contiennent un montant en dollars, aucune le prix demandé. Le LLM a donc lu la variable dépendante pour 19,7 % de186  l'échantillon. Gain in-sample de la couche texte (modèle A) : +0,6 pt sur Realtor.ca contre +3,3 pt sur DuProprio ;187  couche vision (jamais exposée au texte) : +2,4 contre +4,1 pt. Les gains Realtor.ca sont retenus comme estimation188  crédible ; une ré-extraction sur des descriptions purgées du prix est recommandée (≈ 1 $).189- **Langue.** Règle de stop-words (ratio 1,5, comme WP 2) : 44,6 % FR, 43,1 % EN, 12,3 % mixte (DuProprio = traduction190  anglaise + original français). Sur Realtor.ca, 41,9 % EN ; prix médian EN 749 000 $ vs FR 524 900 $. Indicatrice EN :191  +7,2 % conditionnel (modèle A), +11,8 % (modèle B). Les prix implicites IA sont inchangés à la 3e décimale ; les gains192  des deux couches existent dans chaque langue.193- **Effets fixes RTA** (3 premiers caractères du code postal ; 419 RTA, 250 avec ≥ 20 annonces) : R² A 0,755 → 0,764 ;194  coefficients IA stables.195- **Validation spatiale** (GroupKFold par RTA vs 5-fold aléatoire) : tous les niveaux baissent de 3 à 5 pt de R² OOS196  (GBM texte+vision 0,770 → 0,734), les incréments texte/vision sont préservés.197- **Bootstrap en grappes** (299 réplications, 195 municipalités) : IC 95 % excluant zéro pour curb appeal, rénovation,198  luxe, garage, brique, pierre, vinyle, cadre rural, condition LLM, cuisine rénovée ; incluant zéro de peu pour199  aménagement paysager et bois franc.200- **Accord inter-sources** (LLM vs mots-clés sur le même texte ; vision vs texte/champs structurés) : κ = 0,96 garage,201  0,91 foyer, 0,81 piscine, 0,65 climatisation, 0,56 sous-sol fini, 0,50 bord de l'eau (le LLM sur-déclare : 22,5 % vs202  9,2 %) ; garage visible vs garage texte κ = 0,35 ; étages visuels exacts 60 %, à ± ½ étage 89 % ; type « maison en203  rangée » visuel : précision 18 % (champ non fiable, utilisé seulement comme contrôle).204- **Poids du blend** : w = 0,5 fixé a priori ; grille 0,3–0,7 → R² 0,771–0,780 ; poids choisi en CV emboîtée → 0,775.205- **Corrections de forme** : la température n'était pas fixée pour la vision (défaut API), seuls les alias de modèles206  sont connus ; 15 (et non 17) aménités par mots-clés ; 12 champs vision → 21 régresseurs ; catégorie de référence des207  EF ville = municipalités regroupées (< 20 annonces) ; la couche vision est le plus grand des deux incréments IA mais208  le bloc pièces/listing apporte davantage (+9,8 pt OLS).209