testgeodechet / app.py
nath13huggingface's picture
test app.py
0ace658
Raw
History Blame Contribute Delete
7.95 kB
import streamlit as st
import pandas as pd
import numpy as np
import pickle
from pathlib import Path
import os
import boto3
import statsmodels.api as sm
import plotly.express as px
from dotenv import load_dotenv
from io import BytesIO
# Nettoyage du cache au démarrage
st.cache_data.clear()
st.cache_resource.clear()
# Configuration page pleine largeur
st.set_page_config(
page_title="Simulation Geodechets",
page_icon="♻️",
layout="wide"
)
# Titre de l'app
st.title("Application Geodechets")
st.write("### Simulation de production de déchets par département")
# Chargement des secrets AWS
load_dotenv("secrets.env")
AWS_KEY = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET = os.getenv("AWS_SECRET_ACCESS_KEY")
# Connexion S3
s3 = boto3.client(
's3',
aws_access_key_id=AWS_KEY,
aws_secret_access_key=AWS_SECRET,
region_name="eu-west-3"
)
# Fonction pour charger CSV depuis S3
@st.cache_data
def load_data_from_s3(bucket_name, key):
obj = s3.get_object(Bucket=bucket_name, Key=key)
df = pd.read_csv(BytesIO(obj['Body'].read()))
return df
# Fonction pour charger Pickle depuis S3
@st.cache_resource
def load_pickle_from_s3(bucket_name, key):
obj = s3.get_object(Bucket=bucket_name, Key=key)
return pickle.load(BytesIO(obj['Body'].read()))
# Chargement des données CSV
try:
df = load_data_from_s3("mygeodechet", "df_reduced.csv")
except Exception as e:
st.error(f"Erreur lors du chargement des données : {e}")
df = None
# Chargement des modèles Pickle
model_files = {
"Déblais et gravats": "models/model_ols_Déblais_gravats.pkl",
"Déchets verts": "models/model_ols_Déchets_verts.pkl",
"Encombrants": "models/model_ols_Encombrants.pkl",
"Matériaux recyclables": "models/model_ols_Matériaux_recyclables.pkl",
"Total autres déchets": "models/model_ols_Total_autres_dechets.pkl"
}
models = {}
for label, path in model_files.items():
try:
models[label] = load_pickle_from_s3("mygeodechet", path)
# st.success(f"✅ Modèle '{label}' chargé depuis S3 !")
except Exception as e:
st.error(f"Erreur lors du chargement du modèle '{label}' : {e}")
models[label] = None
# Sélection du département
if df is not None:
departement = st.selectbox("Choix du département :", sorted(df["Département"].unique()))
df_dep = df[df["Département"] == departement].copy()
st.dataframe(df_dep.head(7), use_container_width=True)
# -------------------------------------------------------------------------------------------------
# Ajustement des paramètres sur 4 colonnes, avant simultaion, pour l'année 2021
# selection année 2021
df_2021 = df_dep[df_dep["année"] == 2021]
# liste des variables à slider
numeric_cols = [
'pop_globale', 'densité',
'tranche_age_0-24', 'tranche_age_25-59', 'tranche_age_60+',
'csp1_agriculteurs', 'csp2_artisans_commerçant_chef_entreprises',
'csp3_cadres_professions_intellectuelles', 'csp4_professions_intermédiaires',
'csp5_employés', 'csp6_ouvriers', 'csp7_retraités', 'csp8_sans_activité',
'nbre_entreprises', 'nbre_entreprises_agricole', 'nbre_entreprises_industrie',
'nbre_entreprises_service', 'nb_salaries_secteur_agricole',
'nb_salaries_secteur_industrie', 'nb_salaries_secteur_service'
]
# titre
st.write("### Paramètres à ajuster")
col1, col2, col3, col4 = st.columns(4)
cols = [col1, col2, col3, col4]
user_inputs = {}
for i, feature in enumerate(numeric_cols):
min_val = float(df_dep[feature].min())*0.5 # 50% de moins
max_val = float(df_dep[feature].max()) *1.5 # 50% de plus
mean_val = float(df_dep[feature].mean())
target_col = cols[i % 4] # distribue à travers les 4 colonnes
with target_col:
# slider avec step raisonnable
step = max((max_val - min_val) / 50.0, 1.0)
user_inputs[feature] = st.slider(feature, min_val, max_val, float(mean_val), step=step, key=f"sl_{feature}")
# -------------------------------------------------------------------------------------------------------
# Partie simulation
st.markdown("---")
# st.markdown("### Lancez la simulation")
if st.button("Lancer la simulation"):
# Préparer X_user
X_user = pd.DataFrame([user_inputs])
# Nettoyage / conversion : remplace virgules (si jamais), force numérique et fillna
X_user = X_user.apply(lambda col: pd.to_numeric(col.astype(str).str.replace(",", "."), errors="coerce"))
X_user = X_user.fillna(0.0)
results = []
for label, pipeline in models.items():
if pipeline is None:
st.error(f"Modèle manquant pour {label}")
results.append({"Type de déchet": label, "Prédiction (tonnes)": "Erreur"})
continue
try:
preprocessor = pipeline["preprocessor"]
ols_model = pipeline["ols_model"]
# Ajouter toutes les colonnes attendues par le preprocessor avec 0.0 si manquantes
for feat in preprocessor.feature_names_in_:
if feat not in X_user.columns:
X_user[feat] = 0.0
# Réordonner et forcer float uniquement pour les colonnes du preprocessor
X_sim = X_user[preprocessor.feature_names_in_].astype(float)
# Transformation + constante
X_transformed = preprocessor.transform(X_sim)
X_const = sm.add_constant(X_transformed, has_constant='add')
# Prédiction
pred = ols_model.predict(X_const)[0]
results.append({"Type de déchet": label, "Prédiction (tonnes)": round(float(pred), 2)})
except Exception as e:
st.error(f"Erreur modèle {label}: {e}")
results.append({"Type de déchet": label, "Prédiction (tonnes)": "Erreur"})
# -----------------------------------------------------------------------------------------------------------------
# 2éme Partie
# Affichage résultats en deux colonnes (résultats / graph)
res_col, graph_col = st.columns([1, 2])
with res_col:
df_results = pd.DataFrame(results)
st.write("#### Résultats Prédictions")
st.dataframe(df_results, use_container_width=True)
with graph_col:
st.write("#### Analyse comparative des déchets : 2021 (réel) vs modèle prédictif")
# Filtrer uniquement les résultats numériques
good = df_results[df_results["Prédiction (tonnes)"].apply(lambda v: isinstance(v, (int, float)))].copy()
if not good.empty:
# Créer un DataFrame avec les valeurs 2021
df_2021_vals = pd.DataFrame({
'Type de déchet': ['Déblais et gravats', 'Déchets verts', 'Encombrants',
'Matériaux recyclables', 'Total autres déchets'],
'2021': [
float(df_2021['Déblais_gravats'].values[0]),
float(df_2021['Déchets_verts'].values[0]),
float(df_2021['Encombrants'].values[0]),
float(df_2021['Matériaux_recyclables'].values[0]),
float(df_2021['Total_autres_dechets'].values[0])
]
})
# Fusionner avec les prédictions
df_plot = pd.merge(good, df_2021_vals, on='Type de déchet') # Le merge sert à mettre ces données côte à côte pour le même type de déchet.
df_plot = df_plot.melt(id_vars='Type de déchet', value_vars=['2021', 'Prédiction (tonnes)'],
var_name='Année', value_name='Tonnes') # attend un format “long” pour faire des barres côte à côte par catégorie.
# Graphique barres côte à côte
fig = px.bar(df_plot, x='Type de déchet', y='Tonnes', color='Année', barmode='group', height=300)
st.plotly_chart(fig, use_container_width=True)
else:
st.info("Aucun résultat numérique à afficher")