Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import joblib | |
| import pandas as pd | |
| import numpy as np | |
| # Chargement des modèles | |
| 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 | |
| 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}") |