Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| from sklearn.linear_model import LinearRegression | |
| from sklearn.metrics import mean_absolute_error, r2_score | |
| # Configuration de la page | |
| st.set_page_config( | |
| page_title="AI Immo Predictor", | |
| page_icon="🏠", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| # Style personnalisé | |
| st.markdown(""" | |
| <style> | |
| .main { | |
| background-color: #f8f9fa; | |
| } | |
| .stMetric { | |
| background-color: #ffffff; | |
| padding: 15px; | |
| border-radius: 10px; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.05); | |
| } | |
| .stAlert { | |
| border-radius: 10px; | |
| } | |
| h1, h2, h3 { | |
| color: #1e3a8a; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # 1. DONNÉES | |
| donnees = { | |
| 'm2': [30, 50, 70, 90, 110, 130, 30, 50, 70, 50, 45, 85, 120, 60, 95, 55, 75, 100, 65, 80, 40, 90, 115, 140, 35, 60, 95, 105, 125, 150], | |
| 'dist': [1, 2, 3, 5, 8, 10, 15, 20, 25, 2, 4, 6, 12, 5, 8, 3, 4, 7, 2, 5, 1, 6, 9, 11, 18, 3, 7, 8, 10, 13], | |
| 'neuf': [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1], | |
| 'pieces': [1, 2, 3, 4, 4, 5, 1, 2, 3, 2, 2, 3, 4, 3, 4, 2, 3, 4, 3, 3, 1, 4, 5, 6, 1, 2, 4, 4, 5, 6], | |
| 'parking': [0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1], | |
| 'etage': [0, 2, 1, 3, 0, 1, 0, 1, 0, 4, 2, 3, 0, 2, 5, 3, 1, 2, 5, 4, 0, 3, 1, 0, 2, 4, 6, 2, 1, 3], | |
| 'balcon': [0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1], | |
| 'jardin': [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1], | |
| 'ascenseur': [0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1], | |
| 'dpe': [4, 3, 4, 3, 5, 4, 6, 5, 6, 2, 4, 3, 1, 4, 3, 2, 4, 2, 1, 3, 5, 2, 3, 4, 6, 2, 3, 1, 3, 1], | |
| 'annee': [1985, 2000, 1995, 2005, 1980, 1990, 1975, 1988, 1970, 2020, 1998, 2008, 2022, 2002, 2010, 2018, 1992, 2015, 2021, 2005, 1982, 2012, 2003, 1995, 1978, 2019, 2011, 2023, 2007, 2024], | |
| 'etat': [2, 2, 2, 2, 1, 2, 1, 1, 1, 3, 2, 2, 3, 2, 2, 3, 2, 3, 3, 2, 1, 3, 2, 2, 1, 3, 2, 3, 2, 3], | |
| 'prix': [180000, 275000, 362000, 418000, 485000, 515000, 115000, 182000, 238000, 315000, 220000, 380000, 540000, 290000, 430000, 298000, 355000, 475000, 325000, 395000, 195000, 445000, 520000, 580000, 145000, 310000, 460000, 495000, 535000, 625000] | |
| } | |
| df = pd.DataFrame(donnees) | |
| # 2. ENTRAÎNEMENT DU MODÈLE | |
| X = df[['m2', 'dist', 'neuf', 'pieces', 'parking', 'etage', 'balcon', 'jardin', 'ascenseur', 'dpe', 'annee', 'etat']] | |
| y = df['prix'] | |
| ia = LinearRegression() | |
| ia.fit(X, y) | |
| predictions = ia.predict(X) | |
| erreur = mean_absolute_error(y, predictions) | |
| score_r2 = r2_score(y, predictions) | |
| # INTERFACE UTILISATEUR | |
| st.title("🏠 AI Immo Predictor") | |
| st.markdown("### L'intelligence artificielle au service de votre investissement") | |
| # Barre latérale pour les entrées | |
| with st.sidebar: | |
| st.header("📍 Caractéristiques du Bien") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| s = st.number_input("Surface (m2)", min_value=10, max_value=500, value=75) | |
| p = st.number_input("Pièces", min_value=1, max_value=20, value=3) | |
| with col2: | |
| d = st.number_input("Distance centre (km)", min_value=0.0, max_value=100.0, value=5.0) | |
| etg = st.number_input("Étage", min_value=0, max_value=50, value=2) | |
| col3, col4 = st.columns(2) | |
| with col3: | |
| n = st.selectbox("Neuf ?", ["NON", "OUI"]) | |
| park = st.selectbox("Parking ?", ["OUI", "NON"]) | |
| balc = st.selectbox("Balcon ?", ["OUI", "NON"]) | |
| with col4: | |
| jard = st.selectbox("Jardin ?", ["NON", "OUI"]) | |
| asc = st.selectbox("Ascenseur ?", ["OUI", "NON"]) | |
| etat_input = st.slider("État (1=Rénover, 3=Excellent)", 1, 3, 2) | |
| dpe_input = st.slider("DPE (1=A, 7=G)", 1, 7, 3) | |
| annee_input = st.number_input("Année de construction", 1900, 2025, 2010) | |
| st.divider() | |
| prix_voulu = st.number_input("Prix affiché (euros)", min_value=0, value=350000, step=5000) | |
| # Conversion des entrées | |
| code_neuf = 1 if n == "OUI" else 0 | |
| parking = 1 if park == "OUI" else 0 | |
| balcon = 1 if balc == "OUI" else 0 | |
| jardin = 1 if jard == "OUI" else 0 | |
| ascenseur = 1 if asc == "OUI" else 0 | |
| # Prédiction | |
| entree = np.array([[s, d, code_neuf, p, parking, etg, balcon, jardin, ascenseur, dpe_input, annee_input, etat_input]]) | |
| estimation = ia.predict(entree)[0] | |
| prix_min = estimation - erreur | |
| prix_max = estimation + erreur | |
| # AFFICHAGE DES RÉSULTATS | |
| col_res1, col_res2, col_res3 = st.columns(3) | |
| with col_res1: | |
| st.metric("Estimation IA", f"{estimation:,.0f} €") | |
| with col_res2: | |
| ecart = ((prix_voulu - estimation) / estimation) * 100 | |
| st.metric("Écart Marché", f"{ecart:+.1f} %", delta=-ecart, delta_color="inverse") | |
| with col_res3: | |
| st.metric("Marge d'erreur", f"± {erreur:,.0f} €") | |
| # Verdict | |
| st.divider() | |
| if prix_voulu < (estimation - erreur): | |
| st.success(f"### 🔥 EXCELLENTE AFFAIRE !\nVous économisez environ **{estimation - prix_voulu:,.0f} €** par rapport au marché.") | |
| st.balloons() | |
| elif prix_voulu > (estimation + erreur): | |
| st.error(f"### ⚠️ TROP CHER !\nCe bien est surévalué d'environ **{prix_voulu - estimation:,.0f} €**.") | |
| else: | |
| st.info("### ✅ PRIX CORRECT\nLe prix est parfaitement aligné avec les tendances actuelles du marché.") | |
| # ANALYSES VISUELLES POUR CONVAINCRE | |
| st.header("📊 Analyses Détaillées") | |
| tab1, tab2, tab3 = st.tabs(["Analyse de Prix", "Influence des Critères", "Données du Marché"]) | |
| with tab1: | |
| # Graphique de la fourchette de prix | |
| fig_range = go.Figure() | |
| fig_range.add_trace(go.Bar( | |
| name='Estimation IA', | |
| x=['Prix (€)'], | |
| y=[estimation], | |
| error_y=dict(type='data', array=[erreur], visible=True), | |
| marker_color='#1e3a8a' | |
| )) | |
| fig_range.add_trace(go.Scatter( | |
| name='Prix Vendeur', | |
| x=['Prix (€)'], | |
| y=[prix_voulu], | |
| mode='markers', | |
| marker=dict(color='red', size=15, symbol='star') | |
| )) | |
| fig_range.update_layout(title="Comparaison Estimation vs Prix Vendeur", showlegend=True) | |
| st.plotly_chart(fig_range, use_container_width=True) | |
| with tab2: | |
| # Importance des coefficients | |
| carac_noms = ['Surface', 'Distance', 'Neuf', 'Pièces', 'Parking', 'Étage', 'Balcon', 'Jardin', 'Ascenseur', 'DPE', 'Année', 'État'] | |
| coefs = ia.coef_ | |
| df_coef = pd.DataFrame({'Critère': carac_noms, 'Impact sur le prix (€)': coefs}) | |
| df_coef = df_coef.sort_values(by='Impact sur le prix (€)', ascending=True) | |
| fig_coef = px.bar(df_coef, x='Impact sur le prix (€)', y='Critère', orientation='h', | |
| title="Quels critères influencent le plus le prix ?", | |
| color='Impact sur le prix (€)', color_continuous_scale='RdYlGn') | |
| st.plotly_chart(fig_coef, use_container_width=True) | |
| with tab3: | |
| # Corrélation Surface / Prix | |
| fig_scatter = px.scatter(df, x='m2', y='prix', color='dist', size='prix', | |
| hover_data=['annee', 'pieces'], | |
| title="Distribution des prix selon la surface et la distance", | |
| labels={'m2': 'Surface (m2)', 'prix': 'Prix (€)', 'dist': 'Distance (km)'}, | |
| color_continuous_scale='Viridis') | |
| st.plotly_chart(fig_scatter, use_container_width=True) | |
| # Footer | |
| st.divider() | |
| st.markdown(f""" | |
| <div style='text-align: center; color: gray;'> | |
| Modèle entraîné sur {len(df)} transactions récentes | Précision du modèle (R2) : {score_r2:.2%}<br> | |
| <i>AI Immo Predictor v1.0 - Propulsé par Machine Learning</i> | |
| </div> | |
| """, unsafe_allow_html=True) |