"""
Module: Regression Lineaire
Categorie: Supervised Regression
Difficulte: Debutant

Genere depuis la plateforme ML Formation
"""

# Imports
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, mean_squared_error, r2_score

# Charger le dataset
df = pd.read_csv('housing_simple.csv')

# Charger et explorer les donnees
# Type: Code executable
# =============================================================================
# ETAPE 1 : EXPLORATION DES DONNEES
# =============================================================================
# Avant de construire un modele, nous devons COMPRENDRE nos donnees.

# Fonction pour formater les nombres au style francais (espace comme separateur)
def fmt(n, decimals=0):
    return f"{n:,.{decimals}f}".replace(",", " ")

print("=" * 70)
print("EXPLORATION DU DATASET IMMOBILIER")
print("=" * 70)
print()

# --- 1.1 Apercu des premieres lignes ---
print("1. APERCU DES DONNEES")
print("-" * 40)
print("Voici les 5 premieres lignes du dataset :")
print("(Chaque ligne = un bien immobilier vendu)")
print()
display(df.head(), title="Apercu du dataset immobilier")

# --- 1.2 Dimensions du dataset ---
n_lignes, n_colonnes = df.shape
print()
print("2. DIMENSIONS DU DATASET")
print("-" * 40)
print(f"   Nombre de biens immobiliers : {n_lignes}")
print(f"   Nombre de caracteristiques  : {n_colonnes}")
print()
print(f"   Interpretation concrete :")
print(f"   → Nous avons {n_lignes} exemples de ventes passees pour entrainer notre modele.")
print(f"   → Pour chaque vente, nous connaissons {n_colonnes} informations.")

# --- 1.3 Types de donnees ---
print()
print("3. COLONNES DISPONIBLES")
print("-" * 40)
for col in df.columns:
    dtype = df[col].dtype
    exemple = df[col].iloc[0]
    print(f"   • {col:12} | Type: {str(dtype):8} | Exemple: {exemple}")

print()
print("   Roles des colonnes :")
print("   → 'surface'  : Variable explicative (ce qu'on connait)")
print("   → 'nb_rooms' : Variable explicative (ce qu'on connait)")
print("   → 'price'    : Variable cible (ce qu'on veut predire)")

# --- 1.4 Statistiques descriptives ---
print()
print("4. STATISTIQUES DESCRIPTIVES")
print("-" * 40)
print("Voici les statistiques cles de chaque colonne :")
print()
display(df.describe().round(2), title="Statistiques descriptives")

# --- 1.5 Interpretation des statistiques ---
print()
print("5. INTERPRETATION DES STATISTIQUES")
print("-" * 40)

surface_min = df['surface'].min()
surface_max = df['surface'].max()
surface_mean = df['surface'].mean()

price_min = df['price'].min()
price_max = df['price'].max()
price_mean = df['price'].mean()

print(f"   SURFACES :")
print(f"   → Les biens vont de {surface_min:.0f} m² a {surface_max:.0f} m²")
print(f"   → Surface moyenne : {surface_mean:.0f} m²")
print(f"   → C'est un marche plutot oriente vers des appartements/maisons de taille moyenne.")
print()
print(f"   PRIX :")
print(f"   → Les prix vont de {fmt(price_min)} EUR a {fmt(price_max)} EUR")
print(f"   → Prix moyen : {fmt(price_mean)} EUR")
print(f"   → Ecart important ({price_max/price_min:.1f}x), suggere une bonne variabilite.")
print()
print("   POURQUOI C'EST IMPORTANT ?")
print("   → Une bonne variabilite dans les donnees permet au modele")
print("     d'apprendre des patterns robustes.")
print("   → Si tous les biens avaient le meme prix, impossible d'apprendre !")

# --- 1.6 Verification des valeurs manquantes ---
print()
print("6. VERIFICATION DE LA QUALITE DES DONNEES")
print("-" * 40)
missing = df.isnull().sum()
if missing.sum() == 0:
    print("   ✓ Aucune valeur manquante ! Le dataset est complet.")
else:
    print("   ⚠ Valeurs manquantes detectees :")
    for col, count in missing.items():
        if count > 0:
            print(f"     - {col}: {count} valeurs manquantes")

print()
print("=" * 70)
print("CONCLUSION : Nos donnees sont pretes pour la modelisation !")
print("=" * 70)


# Visualiser la relation surface-prix
# Type: Code executable
# =============================================================================
# ETAPE 2 : VISUALISATION DE LA RELATION
# =============================================================================
# La visualisation est ESSENTIELLE avant de modeliser.
# Elle nous permet de :
# 1) Verifier si une relation lineaire existe (prerequis de la regression)
# 2) Detecter des anomalies ou outliers
# 3) Avoir une intuition sur la force de la relation

print("=" * 70)
print("ANALYSE VISUELLE : SURFACE vs PRIX")
print("=" * 70)
print()
print("Question : Y a-t-il une relation entre la surface et le prix ?")
print("→ Si oui, la regression lineaire sera appropriee.")
print("→ Si non, il faudra envisager d'autres approches.")
print()

# Creation du graphique
plt.figure(figsize=(10, 6))
plt.scatter(df['surface'], df['price'], alpha=0.6, color='#9B7AC4', s=50)
plt.xlabel('Surface (m²)', fontsize=12)
plt.ylabel('Prix (EUR)', fontsize=12)
plt.title('Relation entre Surface et Prix des biens immobiliers', fontsize=14)
plt.grid(True, alpha=0.3)

# Ajouter des annotations explicatives
plt.annotate('Chaque point = un bien vendu', xy=(0.02, 0.98), xycoords='axes fraction',
             fontsize=10, color='gray', ha='left', va='top')

plt.tight_layout()
plt.show()

# --- Analyse de la correlation ---
print()
print("ANALYSE DE LA CORRELATION")
print("-" * 40)
correlation = df['surface'].corr(df['price'])
print(f"   Coefficient de correlation (r) : {correlation:.3f}")
print()

# Interpretation du coefficient
print("   INTERPRETATION :")
if abs(correlation) >= 0.8:
    force = "tres forte"
    emoji = "★★★"
elif abs(correlation) >= 0.6:
    force = "forte"
    emoji = "★★☆"
elif abs(correlation) >= 0.4:
    force = "moderee"
    emoji = "★☆☆"
else:
    force = "faible"
    emoji = "☆☆☆"

direction = "positive (plus grand = plus cher)" if correlation > 0 else "negative"

print(f"   → Force de la relation : {force.upper()} {emoji}")
print(f"   → Direction : {direction}")
print()
print("   GUIDE D'INTERPRETATION DU COEFFICIENT r :")
print("   |r| > 0.8  : Correlation tres forte  → Excellent pour la regression")
print("   |r| > 0.6  : Correlation forte       → Bon pour la regression")
print("   |r| > 0.4  : Correlation moderee    → Acceptable")
print("   |r| < 0.4  : Correlation faible     → Regression peu fiable")
print()
print("   CONCLUSION VISUELLE :")
print("   → Les points suivent globalement une tendance ascendante.")
print("   → La regression lineaire semble appropriee pour ces donnees.")
print("   → On peut estimer qu'un bien plus grand coute plus cher.")


# Preparer et entrainer le modele
# Type: Code executable
# =============================================================================
# ETAPE 3 : PREPARATION ET ENTRAINEMENT DU MODELE
# =============================================================================
# C'est ici que la "magie" du Machine Learning opère !
# Nous allons :
# 1) Preparer les donnees dans le bon format
# 2) Diviser en ensemble d'entrainement et de test
# 3) Entrainer le modele
# 4) Interpreter les parametres appris

# Fonction pour formater les nombres au style francais (espace comme separateur)
def fmt(n, decimals=0):
    return f"{n:,.{decimals}f}".replace(",", " ")

print("=" * 70)
print("ENTRAINEMENT DU MODELE DE REGRESSION LINEAIRE")
print("=" * 70)
print()

# --- 3.1 Preparation des donnees ---
print("1. PREPARATION DES DONNEES")
print("-" * 40)

X = df[['surface']].values  # Variable explicative (2D array requis par sklearn)
y = df['price'].values       # Variable cible (1D array)

print(f"   Variable explicative (X) : surface des biens")
print(f"   Variable cible (y)       : prix de vente")
print()
print(f"   Format de X : {X.shape} (matrice 2D : {X.shape[0]} exemples x {X.shape[1]} feature)")
print(f"   Format de y : {y.shape} (vecteur 1D : {y.shape[0]} valeurs)")
print()
print("   Note technique : sklearn exige que X soit 2D meme avec 1 seule variable.")

# --- 3.2 Division train/test ---
print()
print("2. DIVISION TRAIN/TEST")
print("-" * 40)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print(f"   Total des donnees   : {len(X)} biens")
print(f"   Donnees TRAIN (80%) : {len(X_train)} biens → pour apprendre")
print(f"   Donnees TEST (20%)  : {len(X_test)} biens → pour evaluer")
print()
print("   POURQUOI DIVISER ?")
print("   → Le modele apprend UNIQUEMENT sur les donnees train.")
print("   → Les donnees test simulent de 'nouveaux' biens jamais vus.")
print("   → Cela permet d'evaluer si le modele generalise bien.")
print()
print("   Analogie : C'est comme reviser sur des exercices (train)")
print("              puis passer un examen avec des questions nouvelles (test).")

# --- 3.3 Entrainement ---
print()
print("3. ENTRAINEMENT DU MODELE")
print("-" * 40)
print("   Le modele cherche les parametres a (pente) et b (intercept)")
print("   qui minimisent l'erreur sur les donnees d'entrainement...")
print()

model = LinearRegression()
model.fit(X_train, y_train)

print("   ✓ Modele entraine avec succes !")
print()

# --- 3.4 Parametres appris ---
print("4. PARAMETRES APPRIS PAR LE MODELE")
print("-" * 40)

pente = model.coef_[0]
intercept = model.intercept_

print(f"   Equation apprise : Prix = {pente:.2f} × Surface + {intercept:.2f}")
print()
print(f"   COEFFICIENT (pente) : {fmt(pente, 2)} EUR/m²")
print(f"   → Interpretation : Chaque m² supplementaire ajoute {fmt(pente)} EUR au prix.")
print(f"   → Exemple : Passer de 50 a 60 m² (+10 m²) = +{fmt(pente*10)} EUR")
print()
print(f"   INTERCEPT (ordonnee a l'origine) : {fmt(intercept, 2)} EUR")
print(f"   → Interpretation : C'est le 'prix de base' theorique pour 0 m².")
print(f"   → En pratique : Represente les couts fixes (terrain, charges, etc.)")
print()

# --- 3.5 Test de prediction ---
print("5. TEST DE PREDICTION")
print("-" * 40)
print("   Verifions que notre modele fonctionne avec un exemple concret :")
print()

surface_test = 75
prix_predit = model.predict([[surface_test]])[0]

print(f"   Pour un bien de {surface_test} m² :")
print(f"   → Calcul : {pente:.2f} × {surface_test} + {intercept:.2f}")
print(f"   → Prix predit : {fmt(prix_predit)} EUR")
print()
print("   Ce prix vous semble-t-il realiste pour votre marche local ?")

print()
print("=" * 70)
print("MODELE PRET ! Passons a l'evaluation des performances.")
print("=" * 70)


# Evaluer les performances
# Type: Code executable
# =============================================================================
# ETAPE 4 : EVALUATION DES PERFORMANCES
# =============================================================================
# Un modele entraine n'est rien sans evaluation !
# Nous devons mesurer OBJECTIVEMENT sa qualite.
# C'est comme noter un etudiant : les metriques sont les criteres de notation.

# Fonction pour formater les nombres au style francais (espace comme separateur)
def fmt(n, decimals=0):
    return f"{n:,.{decimals}f}".replace(",", " ")

print("=" * 70)
print("EVALUATION DES PERFORMANCES DU MODELE")
print("=" * 70)
print()

# Re-preparation (pour cellule autonome)
X = df[['surface']].values
y = df['price'].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = LinearRegression()
model.fit(X_train, y_train)

# --- 4.1 Predictions sur le jeu de test ---
print("1. PREDICTIONS SUR DONNEES TEST")
print("-" * 40)
y_pred = model.predict(X_test)

print(f"   Nombre de predictions : {len(y_pred)}")
print()
print("   Comparaison Prix Reel vs Prix Predit (5 premiers exemples) :")
print("   " + "-" * 50)
print(f"   {'Surface':>10} {'Prix Reel':>15} {'Prix Predit':>15} {'Erreur':>12}")
print("   " + "-" * 50)

for i in range(5):
    surface = X_test[i][0]
    reel = y_test[i]
    predit = y_pred[i]
    erreur = reel - predit
    signe = "+" if erreur >= 0 else ""
    print(f"   {surface:>10.0f} m² {fmt(reel):>14}€ {fmt(predit):>14}€ {signe + fmt(erreur):>11}€")

print()
print("   Observation : Les predictions sont proches des valeurs reelles !")

# --- 4.2 Calcul des metriques ---
print()
print("2. METRIQUES DE PERFORMANCE")
print("-" * 40)

mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = np.mean(np.abs(y_test - y_pred))
r2 = r2_score(y_test, y_pred)

print()
print(f"   MSE  (Mean Squared Error)    : {fmt(mse):>15}")
print(f"   RMSE (Root Mean Squared Err) : {fmt(rmse):>15} EUR")
print(f"   MAE  (Mean Absolute Error)   : {fmt(mae):>15} EUR")
print(f"   R²   (Coefficient de determ) : {r2:>15.4f}")

# --- 4.3 Interpretation detaillee ---
print()
print("3. INTERPRETATION DES METRIQUES")
print("-" * 40)
print()

print("   MSE (Mean Squared Error) :")
print(f"   → Valeur : {fmt(mse)}")
print("   → Signification : Moyenne des erreurs au carre.")
print("   → Probleme : Unite en EUR², difficile a interpreter directement.")
print()

print("   RMSE (Root Mean Squared Error) :")
print(f"   → Valeur : {fmt(rmse)} EUR")
print("   → Signification : Erreur 'typique' de prediction.")
print(f"   → Interpretation concrete : En moyenne, le modele se trompe")
print(f"     d'environ {fmt(rmse)} EUR sur le prix d'un bien.")
prix_moyen = y_test.mean()
erreur_pct = (rmse / prix_moyen) * 100
print(f"   → En pourcentage du prix moyen ({fmt(prix_moyen)} EUR) : {erreur_pct:.1f}%")
print()

print("   MAE (Mean Absolute Error) :")
print(f"   → Valeur : {fmt(mae)} EUR")
print("   → Signification : Erreur absolue moyenne (sans les carres).")
print("   → Avantage : Moins sensible aux erreurs extremes que RMSE.")
print()

print("   R² (Coefficient de determination) :")
print(f"   → Valeur : {r2:.4f} soit {r2*100:.1f}%")
print("   → Signification : Part de variance expliquee par le modele.")
print(f"   → Interpretation : La surface explique {r2*100:.1f}% des variations de prix.")
print(f"   → Les {(1-r2)*100:.1f}% restants dependent d'autres facteurs")
print("     (localisation, etat, etage, etc.).")

# --- 4.4 Guide de reference ---
print()
print("4. GUIDE D'INTERPRETATION DU R²")
print("-" * 40)
print("   R² > 0.9  : Excellent   → Predictions tres fiables")
print("   R² > 0.7  : Bon         → Modele utilisable en pratique")
print("   R² > 0.5  : Acceptable  → Modele indicatif, a ameliorer")
print("   R² < 0.5  : Faible      → Modele insuffisant")
print()

if r2 > 0.7:
    verdict = "BON"
    conseil = "Le modele peut etre utilise pour des estimations fiables."
elif r2 > 0.5:
    verdict = "ACCEPTABLE"
    conseil = "Ajoutez des variables (nb_rooms, localisation) pour ameliorer."
else:
    verdict = "INSUFFISANT"
    conseil = "La surface seule ne suffit pas. Enrichissez les donnees."

print(f"   VERDICT POUR NOTRE MODELE : {verdict}")
print(f"   → {conseil}")

# --- 4.5 Contexte metier ---
print()
print("5. MISE EN CONTEXTE METIER")
print("-" * 40)
print(f"   Pour un agent immobilier, une erreur de {fmt(rmse)} EUR signifie :")
print(f"   → Sur un bien a 200 000 EUR : fourchette 195 000 - 205 000 EUR")
print(f"   → Sur un bien a 500 000 EUR : fourchette 490 000 - 510 000 EUR")
print()
print("   Est-ce acceptable ? Cela depend du contexte :")
print("   → Pour une premiere estimation : OUI")
print("   → Pour une offre d'achat ferme : Ajouter d'autres criteres")

print()
print("=" * 70)
print("EVALUATION TERMINEE !")
print("=" * 70)


# Visualiser la regression
# Type: Code executable
# =============================================================================
# ETAPE 5 : VISUALISATION DE LA REGRESSION
# =============================================================================
# Une image vaut mille mots !
# Cette visualisation montre comment le modele "voit" la relation.

# Fonction pour formater les nombres au style francais (espace comme separateur)
def fmt(n, decimals=0):
    return f"{n:,.{decimals}f}".replace(",", " ")

print("=" * 70)
print("VISUALISATION DE LA DROITE DE REGRESSION")
print("=" * 70)
print()

# Re-preparation (pour cellule autonome)
X = df[['surface']].values
y = df['price'].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

print("Ce graphique montre :")
print("→ Points violets : Donnees reelles (prix de vente effectifs)")
print("→ Ligne jaune    : Droite de regression (prediction du modele)")
print()

# Creation du graphique
plt.figure(figsize=(12, 7))

# Points reels
plt.scatter(X_test, y_test, alpha=0.7, color='#9B7AC4', s=60,
            label='Donnees reelles', edgecolors='white', linewidth=0.5)

# Droite de regression (triee pour affichage propre)
sort_idx = np.argsort(X_test.flatten())
plt.plot(X_test[sort_idx], y_pred[sort_idx], color='#F7E64D',
         linewidth=3, label='Droite de regression', zorder=5)

# Annotations
pente = model.coef_[0]
intercept = model.intercept_
equation = f'Prix = {fmt(pente)} × Surface + {fmt(intercept)}'
plt.annotate(f'Equation: {equation}', xy=(0.02, 0.95), xycoords='axes fraction',
             fontsize=11, fontweight='bold', color='#1A1A1A',
             bbox=dict(boxstyle='round', facecolor='#F7E64D', alpha=0.8))

plt.xlabel('Surface (m²)', fontsize=12)
plt.ylabel('Prix (EUR)', fontsize=12)
plt.title('Regression Lineaire : Prediction du Prix Immobilier', fontsize=14, fontweight='bold')
plt.legend(loc='lower right', fontsize=11)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

# --- Analyse visuelle ---
print()
print("ANALYSE VISUELLE")
print("-" * 40)
print("   Ce que le graphique nous apprend :")
print()
print("   1. TENDANCE GENERALE :")
print("      → La droite capture bien la tendance : plus grand = plus cher.")
print()
print("   2. DISPERSION AUTOUR DE LA DROITE :")
print("      → Les points ne sont pas parfaitement alignes.")
print("      → C'est normal : d'autres facteurs influencent le prix")
print("        (localisation, etat, etage, vue, etc.)")
print()
print("   3. PREDICTIONS :")
print("      → Pour estimer le prix d'un bien, on lit la valeur sur la droite.")
print(f"      → Exemple : Un bien de 100 m² serait estime a environ")
print(f"        {fmt(model.predict([[100]])[0])} EUR.")
print()
print("   4. LIMITES DU MODELE :")
print("      → Le modele ne capture pas les variations individuelles.")
print("      → Deux biens de meme surface peuvent avoir des prix differents.")
print("      → Solution : Ajouter plus de variables explicatives.")


# Exercice: Regression multi-variable
# Type: Exercice
# =============================================================================
# EXERCICE : REGRESSION MULTI-VARIABLE
# =============================================================================
# Objectif : Ameliorer le modele en utilisant DEUX variables explicatives
# (surface ET nb_rooms) au lieu d'une seule.
#
# Question : Est-ce que le nombre de pieces apporte de l'information
# supplementaire pour predire le prix ?

print("=" * 70)
print("EXERCICE : AMELIORER LE MODELE AVEC PLUSIEURS VARIABLES")
print("=" * 70)
print()
print("Contexte :")
print("→ Notre modele actuel utilise uniquement la surface.")
print("→ Le nombre de pieces (nb_rooms) pourrait aussi influencer le prix.")
print("→ Verifions si ajouter cette variable ameliore les predictions !")
print()

# Preparez les donnees avec 2 features
X_multi = df[['surface', 'nb_rooms']].values
y = df['price'].values

# Divisez en train/test
X_train, X_test, y_train, y_test = train_test_split(
    X_multi, y, test_size=0.2, random_state=42
)

print("Donnees preparees :")
print(f"→ Variables explicatives : surface + nb_rooms")
print(f"→ Forme de X : {X_multi.shape}")
print()

# TODO: Creez et entrainez un nouveau modele
# model_multi = ...
# model_multi.fit(...)

# TODO: Faites des predictions
# y_pred_multi = ...

# TODO: Calculez le R2 et comparez avec le modele simple
# r2_multi = ...
# print(f"R2 multi-variable : {r2_multi:.4f}")

print("-" * 40)
print("CONSEIL : Comparez le R² obtenu avec celui du modele simple (~0.7-0.8)")
print("Si R² augmente, nb_rooms apporte de l'information utile !")


# SHAP pour la regression lineaire
# Type: Code executable
# =============================================================================
# EXPLICABILITE AVEC SHAP
# =============================================================================
# SHAP (SHapley Additive exPlanations) permet d'expliquer CHAQUE prediction.
# Meme pour un modele simple comme la regression lineaire, SHAP formalise
# l'explicabilite de maniere rigoureuse.

# Fonction pour formater les nombres au style francais (espace comme separateur)
def fmt(n, decimals=0):
    return f"{n:,.{decimals}f}".replace(",", " ")

print("=" * 70)
print("EXPLICABILITE AVEC SHAP")
print("=" * 70)
print()
print("SHAP repond a la question : 'Pourquoi CE prix pour CE bien ?'")
print()

# Preparation et entrainement
X = df[['surface', 'nb_rooms']].values
y = df['price'].values
feature_names = ['surface', 'nb_rooms']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

model = LinearRegression()
model.fit(X_train, y_train)

# SHAP avec LinearExplainer (optimise pour modeles lineaires)
print("1. CALCUL DES VALEURS SHAP")
print("-" * 40)
explainer = shap.LinearExplainer(model, X_train)
shap_values = explainer.shap_values(X_test)
print("   ✓ Valeurs SHAP calculees pour chaque prediction")
print()

# Prendre un exemple specifique
idx = 5
sample = X_test[idx]
prediction = model.predict([sample])[0]
prix_moyen = y_train.mean()

print("2. EXPLICATION D'UNE PREDICTION")
print("-" * 40)
print(f"   BIEN ANALYSE :")
print(f"   → Surface      : {sample[0]:.0f} m²")
print(f"   → Nb pieces    : {sample[1]:.0f}")
print(f"   → Prix predit  : {fmt(prediction)} EUR")
print()

print("   DECOMPOSITION DU PRIX :")
print(f"   → Prix moyen de reference : {fmt(prix_moyen)} EUR")
print(f"   → Contributions :")
for i, name in enumerate(feature_names):
    contribution = shap_values[idx][i]
    signe = "+" if contribution > 0 else ""
    print(f"      • {name:12} : {signe}{fmt(contribution)} EUR")

total_shap = sum(shap_values[idx])
print(f"   → Total des contributions : {'+' if total_shap >= 0 else ''}{fmt(total_shap)} EUR")
print()
print(f"   VERIFICATION : {fmt(prix_moyen)} + ({'+' if total_shap >= 0 else ''}{fmt(total_shap)}) = {fmt(prix_moyen + total_shap)} EUR")
print(f"   (≈ prediction de {fmt(prediction)} EUR)")
print()

print("3. INTERPRETATION METIER")
print("-" * 40)
print(f"   'Ce bien est estime a {fmt(prediction)} EUR car :'")
print(f"   → Le prix moyen du marche est de {fmt(prix_moyen)} EUR")

for i, name in enumerate(feature_names):
    contribution = shap_values[idx][i]
    if name == 'surface':
        if contribution > 0:
            print(f"   → Sa surface de {sample[0]:.0f} m² AJOUTE {fmt(contribution)} EUR (au-dessus de la moyenne)")
        else:
            print(f"   → Sa surface de {sample[0]:.0f} m² RETIRE {fmt(abs(contribution))} EUR (en-dessous de la moyenne)")
    elif name == 'nb_rooms':
        if contribution > 0:
            print(f"   → Ses {sample[1]:.0f} pieces AJOUTENT {fmt(contribution)} EUR")
        else:
            print(f"   → Ses {sample[1]:.0f} pieces RETIRENT {fmt(abs(contribution))} EUR")
print()

# Visualisation SHAP
print("4. VISUALISATION GLOBALE")
print("-" * 40)
print("   Ce graphique montre l'impact de chaque feature sur toutes les predictions :")
print("   → Plus le point est a droite, plus la feature augmente le prix.")
print("   → La couleur indique la valeur de la feature (rouge = haute, bleu = basse).")
print()

plt.figure(figsize=(10, 5))
shap.summary_plot(shap_values, X_test, feature_names=feature_names, show=False)
plt.title('Impact SHAP des features sur le prix immobilier')
plt.tight_layout()
plt.show()

print()
print("=" * 70)
print("SHAP : L'explicabilite au service de la confiance !")
print("=" * 70)

