SPB Git forge

spb/wp14_uqo

Public
3commits 1branches 1releases
1.5 MBsize
maindefault branch
4 h agolast push
Python 52.4% TeX 47.6%
12.4 KB · 173 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).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 |173