Spaces:
Runtime error
Runtime error
File size: 7,947 Bytes
f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c f7d9075 b40f96c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
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") |