immo-predict / src /app.py
Grailleton's picture
initial commit Immo-Predict V4 !
aaa2e91
Raw
History Blame Contribute Delete
4.64 kB
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}")