import streamlit as st import joblib import pandas as pd import numpy as np # Chargement des modèles @st.cache_resource def charger_modeles(): model_multi = joblib.load('src/model_multi.pkl') modeles_segment = joblib.load('src/modeles_segment.pkl') le = joblib.load('src/label_encoder_multi.pkl') features = joblib.load('src/features_multi.pkl') return model_multi, modeles_segment, le, features # Chargement des données pour les sélecteurs @st.cache_data def charger_donnees(): df = pd.read_csv('data/valeursfoncieres-2025-s1.txt/ValeursFoncieres-2025-S1.txt', sep='|', low_memory=False, usecols=['Commune', 'Code departement']) df = df.dropna() df['Commune'] = df['Commune'].str.strip().str.upper() df['Code departement'] = df['Code departement'].str.strip() return df def assigner_segment(type_bien, prix_estime): t = 'appart' if type_bien == 'Appartement' else 'maison' if prix_estime < 100000: g = 'bas' elif prix_estime < 250000: g = 'moyen_bas' elif prix_estime < 500000: g = 'moyen_haut' else: g = 'haut' return f"{t}_{g}" model_multi, modeles_segment, le, features = charger_modeles() df_ref = charger_donnees() departements = sorted(df_ref['Code departement'].unique().tolist()) # Configuration st.set_page_config(page_title="Immo Predict", page_icon="🏠", layout="centered") st.title("🏠 Immo Predict") st.subheader("Estimation du prix d'un bien immobilier en France") st.caption("Basé sur 3,7 millions de transactions DVF 2022-2025") st.divider() # Formulaire col1, col2 = st.columns(2) with col1: type_bien = st.selectbox("Type de bien", ["Appartement", "Maison"]) surface = st.number_input("Surface (m²)", min_value=9, max_value=500, value=70) nb_pieces = st.slider("Nombre de pièces", 1, 15, 3) with col2: departement = st.selectbox("Département", departements, index=departements.index('75') if '75' in departements else 0) communes_dept = sorted(df_ref[df_ref['Code departement'] == departement]['Commune'].unique().tolist()) commune = st.selectbox("Commune", communes_dept) surface_terrain = st.number_input("Surface terrain (m², 0 si appartement)", min_value=0, value=0) nb_lots = st.number_input("Nombre de lots (copropriété)", min_value=0, value=1) st.divider() if st.button("Estimer le prix 🔍", type="primary"): try: type_encode = 0 if type_bien == 'Appartement' else 1 try: commune_encode = le.transform([commune.upper()])[0] except: commune_encode = 0 try: dept_encode = le.transform([departement])[0] except: dept_encode = 0 X_pred = pd.DataFrame([[type_encode, surface, nb_pieces, nb_lots, surface_terrain, commune_encode, dept_encode]], columns=features) # Première estimation avec le modèle global prix_estime = model_multi.predict(X_pred)[0] # Sélection du bon segment segment = assigner_segment(type_bien, prix_estime) # Prédiction finale avec le modèle du segment if segment in modeles_segment: prix_final = modeles_segment[segment].predict(X_pred)[0] modele_info = f"Modèle spécialisé — segment {segment.replace('_', ' ')}" else: prix_final = prix_estime modele_info = "Modèle général" # Précision selon le segment precision_map = { 'appart_bas': 65.9, 'appart_moyen_bas': 83.4, 'appart_moyen_haut': 87.5, 'appart_haut': 79.5, 'maison_bas': 50.4, 'maison_moyen_bas': 81.1, 'maison_moyen_haut': 86.7, 'maison_haut': 78.8 } precision = precision_map.get(segment, 75.0) fourchette_bas = prix_final * 0.85 fourchette_haut = prix_final * 1.15 prix_m2 = prix_final / surface st.success(f"### Prix estimé : {prix_final:,.0f} €") col1, col2, col3 = st.columns(3) col1.metric("Fourchette basse", f"{fourchette_bas:,.0f} €") col2.metric("Prix au m²", f"{prix_m2:,.0f} €/m²") col3.metric("Fourchette haute", f"{fourchette_haut:,.0f} €") st.info(f"🎯 Précision du modèle sur ce segment : **{precision}%**") st.caption(f"ℹ️ {modele_info}") st.caption("⚠️ Estimation basée sur les transactions DVF 2022-2025. Hors marché du luxe (> 2M€).") except Exception as e: st.error(f"Erreur : {e}")