SPB Git forge

spb/rent-ka

Public
8commits 1branches 0releases
7.4 MBsize
maindefault branch
19 days agolast push
Python 68.8% TypeScript 18.6% CSS 8.7% JavaScript 3.3% HTML 0.6%
8.2 KB

# Framework de juste valeur (fair value) — Lou-Ka / Groupe-KA

Module : louka/fairvalue.py · Version modèle : fv-logement-1.0 · Créé : 2026-08-18

Estime en continu la juste valeur locative de chaque annonce publiée et la classe sous le marché / dans le marché / au-dessus du marché. Conçu comme le moteur générique « estimation de juste valeur » du Groupe-KA : toutes les spécificités logement vivent dans CONFIG (voir « Décliner sur immo-ka / auto-ka » plus bas).

# 1. Données d'entrée

  • Jeu de référence : toutes les annonces active=1 AND published=1 AND dup_of IS NULL au prix mensuel plausible (175–20 000 $). Les annonces en quarantaine qualité (quality.py) sont exclues — le framework repose sur les données enrichies et nettoyées des connecteurs.
  • Exclusions supplémentaires : prix affichés non mensuels (« /semaine », « par nuit » — regex _NON_MENSUEL) ; elles ne polluent ni les médianes ni les verdicts.
  • Chambres/colocations : segment dédié bed="ch" (détection unit_type="Chambre" ou regex _CHAMBRE sur le titre) — une chambre n'est jamais comparée au loyer d'un logement entier.
  • Rafraîchi à chaque cycle de synchronisation (ingest.watch, après géocodage, quality et dedup) et à la demande : python run.py fairvalue. Calcul complet : ~15 s pour ~47 000 annonces (pur Python + grille spatiale).

# 2. Méthode en trois niveaux

# N1 — Référence par segment

Segments en échelle de repli, avec volume minimal min_segment=8 : ville|quartier|chambres → ville|chambres → chambres (province) → global. Statistiques robustes : médiane + p25/p75 (jamais la moyenne). Groupes de chambres : 0 (studio), 1, 2, 3, 4+, ch (chambre/coloc).

# N2 — Ajustements par caractéristiques

Coefficients multiplicatifs appris des données (aucun coefficient inventé) : médiane de prix/p50(segment) des annonces AVEC la caractéristique ÷ celle des annonces SANS (minimum coef_min_pairs=60 de chaque côté, bornés à coef_bounds=(0.85, 1.35)). Centrage obligatoire : le p50 du segment contient déjà le mélange avec/sans, donc l'ajustement appliqué est (c si présent, sinon 1) / (part×c + (1−part)) — sans ce centrage, toutes les estimations gonflent et tout paraît « sous-évalué » (bug observé lors de la première passe : 54 % de « sous »). Caractéristique au statut inconnu = effet moyen (neutre). Superficie : (aire/aire_type_segment)^0.35, borné.

Coefficients appris le 2026-08-18 : stationnement ×1,27 · lave-vaisselle ×1,13 · électricité incluse ×1,12 · meublé ×1,11 · chauffage inclus ×1,10 · balcon ×1,08 · climatisation ×1,07 · ascenseur ×1,06 · piscine ×1,06.

# N3 — Comparables kNN géographiques

Pour les annonces géolocalisées : grille spatiale ~2 km, voisines du même groupe de chambres à < 3 km, pondération gaussienne exp(−(d/800 m)²) avec bonus ×1,3 si même type d'unité, k=12, minimum 4 comparables. Estimateur : médiane pondérée des loyers (la moyenne serait tirée par l'asymétrie).

# Combinaison et garde-fous

  • fv = 0,6×kNN + 0,4×(segment ajusté) quand le kNN existe, sinon segment ajusté.
  • Couloir de sécurité : fv bornée à [0,70×p25 ; 1,30×p75] du segment.
  • Fourchette : dispersion relative du segment appliquée à fv ; élargie si les deux méthodes divergent de > 25 % (et la confiance est abaissée).
  • Confiance : fort (≥ 8 comparables, segment fin, méthodes concordantes), moyen (≥ 4 comparables ou segment ville ≥ 15 annonces), faible sinon.

# 3. Classification et règles de prudence

Écart relatif d = (prix − fv)/fv : sous si d ≤ −8 %, sur si d ≥ +8 %, marche entre les deux.

Pas de verdict (pastille absente, estimation « indicative ») si :

  • confiance faible (peu de comparables / segment rare) ;
  • prix ambigu (price_from : « à partir de » = prix plancher) ;
  • écart hors du plausible (verdict_dev_bounds = (−50 %, +100 %)) — donnée probablement corrompue (coquille de prix, périodicité mal lue).

# 4. Stockage, historisation, traçabilité

  • fairvalue (1 rangée/annonce) : fv, fourchette, écart, verdict, confiance, méthode utilisée, nb de comparables, segment de référence, version du modèle, horodatage — chaque estimation est explicable.
  • fv_segments (append-only) : p25/p50/p75 + volume de chaque segment (niveaux 1-2) à chaque calcul → évolution des loyers de référence dans le temps.
  • Cache miniatures/geo non touchés. fairvalue.explain(uid) reconstruit la distribution du segment pour la fiche (histogramme 24 classes, bornes p1-p99).

# 5. Exposition

  • Site : pastille sur les cartes (FairValueBadge, icône + libellé + %, lisible daltoniens), bloc « Analyse de prix Lou-Ka » sur la fiche (PriceAnalysis : fv, fourchette, écart, confiance, mini-histogramme avec marqueurs « Ce loyer » / « Juste valeur »), filtre « ▼ Sous le marché » (tri meilleures affaires d'abord : ?deal=sous&sort=deal), page de transparence /juste-valeur.
  • API Lou-Ka : champs fv, fv_low, fv_high, fv_deviation, fv_verdict, fv_confidence dans /api/listings (+ filtre deal=, tri sort=deal), pins GeoJSON, /api/fairvalue/{uid} (analyse détaillée + histogramme).
  • API-KA : /api/v1/louka/fairvalue/{uid} (proxy live pour l'app iOS KA) ; les snapshots quotidiens louka_data embarquent automatiquement les champs fv.
  • Stats : KPI « Annonces sous le marché », donut de répartition, tableau « Écart au marché par ville » (statsdash.py) — repris dans le PDF Groupe-KA.

# 6. Calibration et recalibrage

  • Seuils initiaux ±8 % : distribution obtenue ≈ 24 % sous / 39 % dans / 24 % sur / 13 % sans verdict (2026-08-18, ~47 k annonces).
  • Procédure de recalibrage (périodique, trimestrielle suggérée) :
    1. SELECT fv_verdict, durée de présence — comparer le temps en ligne (last_seen − first_seen des annonces désactivées) par verdict : les « sous » doivent partir significativement plus vite que les « sur ».
    2. Ajuster seuil_sous/seuil_sur pour maximiser cette séparation.
    3. Re-vérifier le centrage : AVG(deviation) sur le parc doit rester ≈ 0 (±2 %) ; sinon revoir les coefficients (biais N2) ou le poids kNN.
    4. Bumper MODEL_VERSION à tout changement (traçabilité des estimations).
  • Tests de non-régression : tests/test_fairvalue.py (synthétiques, hors-ligne).

# 7. Décliner sur immo-ka (vente) et auto-ka (véhicules)

Le moteur est générique : segments en échelle + coefficients centrés + kNN + couloir + confiance. Pour décliner :

  1. Copier fairvalue.py, remplacer _load() (requête du jeu de référence) et CONFIG :
    • immo-ka : segment = ville|quartier|type de propriété|chambres, valeur = prix demandé, caractéristiques = garage, sous-sol fini, piscine, année, terrain ; ajustement superficie avec élasticité plus forte (~0,6) ; kNN rayon 2 km. Bornes de plausibilité : 50 k–10 M $.
    • auto-ka : segment = marque|modèle|année±1, « géographie » remplacée par la distance en kilométrage (kNN sur km au lieu de lat/lng), caractéristiques = transmission, motorisation, groupe d'options ; dépréciation = équivalent de l'ajustement superficie.
  2. Garder tels quels : _pct, centrage des coefficients, couloir, médiane pondérée kNN, règles de prudence, historisation, MODEL_VERSION.
  3. Reprendre l'UI : FairValueBadge/PriceAnalysis sont paramétrés par les mêmes champs API (fv_*).

# 8. Limites connues

  • Les « bonnes affaires » à −40/−50 % contiennent encore quelques loyers à la chambre non détectés (annonces ambiguës « chambre dans grand 4½ » sans mots-clés) — bornées par verdict_dev_bounds.
  • Les alertes « bonne affaire » sur critères sauvegardés nécessitent une infrastructure de notification (courriel/push) absente de Lou-Ka à ce jour ; l'URL /?deal=sous est partageable/enregistrable en attendant.
  • Segments ruraux minces → repli ville|chambres provincial, confiance faible, pas de pastille (comportement voulu : rien d'inventé).