Geodechets / src /streamlit_app.py
nath13huggingface's picture
df_reduced
c2e3777
Raw
History Blame Contribute Delete
10.1 kB
# import altair as alt
# import numpy as np
# import pandas as pd
# import streamlit as st
# """
# # Welcome to Streamlit!
# Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
# If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
# forums](https://discuss.streamlit.io).
# In the meantime, below is an example of what you can do with just a few lines of code:
# """
# num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
# num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
# indices = np.linspace(0, 1, num_points)
# theta = 2 * np.pi * num_turns * indices
# radius = indices
# x = radius * np.cos(theta)
# y = radius * np.sin(theta)
# df = pd.DataFrame({
# "x": x,
# "y": y,
# "idx": indices,
# "rand": np.random.randn(num_points),
# })
# st.altair_chart(alt.Chart(df, height=700, width=700)
# .mark_point(filled=True)
# .encode(
# x=alt.X("x", axis=None),
# y=alt.Y("y", axis=None),
# color=alt.Color("idx", legend=None, scale=alt.Scale()),
# size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
# ))
# Import des bibliothéques
import streamlit as st
import pandas as pd
import pickle
import matplotlib.pyplot as plt
from dotenv import load_dotenv
import os
import io
from io import StringIO
import boto3
import numpy as np
import shap
from sklearn.linear_model import LinearRegression
from langchain_mistralai import ChatMistralAI
from langchain_core.output_parsers import StrOutputParser
# Charge les variables d'environnement
load_dotenv("secrets.env")
# Initialise le client S3
s3 = boto3.client(
's3',
aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"),
aws_secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY"),
region_name="eu-west-3"
)
# 1. Charge df_dummies_2019.csv → Pour les VALEURS PAR DÉFAUT des sliders
obj_dummies = s3.get_object(Bucket="mygeodechet", Key="df_dummies_2019.csv")
dummies_data = obj_dummies['Body'].read()
df = pd.read_csv(io.BytesIO(dummies_data)).drop(columns=["Unnamed: 0"], errors="ignore")
# 2. Charge df_reduced.csv → Pour les PRÉDICTIONS (input des modèles)
obj_reduced = s3.get_object(Bucket="mygeodechet", Key="df_reduced.csv")
reduced_data = obj_reduced['Body'].read()
observed_df = pd.read_csv(io.BytesIO(reduced_data)).drop(columns=["Unnamed: 0"], errors="ignore")
# # 1. Charge le CSV (df_dummies_2019.csv)
# obj_csv = s3.get_object(Bucket="mygeodechet", Key="df_dummies_2019.csv")
# csv_data = obj_csv['Body'].read() # Lit le contenu binaire
# df = pd.read_csv(io.BytesIO(csv_data)).drop(columns=["Unnamed: 0"], errors="ignore")
# # 2. Charge l'Excel (data_wip_v5.xlsx)
# obj_excel = s3.get_object(Bucket="mygeodechet", Key="data_wip_v5.xlsx")
# excel_data = obj_excel['Body'].read() # Lit le contenu binaire
# observed_df = pd.read_excel(io.BytesIO(excel_data)) # Utilise BytesIO
# # Chargement des données
# df = pd.read_csv("https://mygeodechet.s3.eu-west-3.amazonaws.com/df_dummies_2019.csv").drop(columns=["Unnamed: 0"], errors="ignore")
# observed_df = pd.read_excel("https://mygeodechet.s3.eu-west-3.amazonaws.com/data_wip_v5.xlsx")
# liste des départements présents dans les colonnes du df, sans le préfixe "Département_".
departements = [col.replace("Département_", "") for col in df.columns if col.startswith("Département_")]
# Mise en page
st.set_page_config(layout="wide")
st.markdown("<h1 style='text-align: center;'>♻️ Simulateur de production de déchets par département</h1>", unsafe_allow_html=True)
# Titre + Choix département alignés
top_col1, top_col2 = st.columns([1, 2])
with top_col1:
st.markdown("<h3 style='text-align: center;'>📍 Choix du département</h3>", unsafe_allow_html=True)
with top_col2:
st.markdown("<h3 style='text-align: center;'>📈 Comparaison entre valeurs observées et prédites</h3>", unsafe_allow_html=True)
# Séparation en colonnes
top_input_col, chart_col = st.columns([1, 2])
with top_input_col:
selected_dept = st.selectbox("Sélectionner un département", sorted(departements), index=sorted(departements).index("Ain") if "Ain" in departements else 0)
row_default = df[df[f"Département_{selected_dept}"] == 1].iloc[0]
default_dict = row_default.to_dict()
st.subheader("⚙️ Paramètres modifiables")
form_input = {}
categories = {
"📊 Population": [
"densité", "pop_globale",
"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é"
],
"🏭 Activité économique": [
"nb_salaries_secteur_agricole", "nb_salaries_secteur_industrie", "nb_salaries_secteur_service",
"nbre_entreprises", "nbre_entreprises_agricole", "nbre_entreprises_industrie", "nbre_entreprises_service"
],
"🗑️ Déchets": [
"tonnage_dechet_produit",
"Total_autres_dechets",
"Déblais_gravats",
"Déchets_verts",
"Encombrants",
"Matériaux_recyclables"
]
}
for category_name, variables in categories.items():
with st.expander(category_name, expanded=True):
for var in variables:
if var in default_dict:
col_slider, col_input = st.columns([2, 1])
with col_slider:
slider_value = st.slider(
f"🔧 {var}",
min_value=float(default_dict[var]) * 0,
max_value=float(default_dict[var]) * 1.5,
value=float(default_dict[var]),
step=1.0,
key=f"slider_{var}"
)
with col_input:
text_val = st.text_input(f"{var} (manuel)", value=str(slider_value), key=f"text_{var}")
try:
form_input[var] = float(text_val)
except ValueError:
form_input[var] = slider_value
input_df = pd.DataFrame([form_input])
input_df_complete = row_default.to_frame().T.copy()
for col in input_df.columns:
if col in input_df_complete.columns:
input_df_complete.at[input_df_complete.index[0], col] = input_df.at[0, col]
with chart_col:
st.markdown("<div style='margin-top: 30px;'></div>", unsafe_allow_html=True)
btn_col = st.columns([3, 2, 3])[1]
with btn_col:
run_eval = st.button("🔍 Lancer l'évaluation")
st.markdown("<div style='margin-top: 40px;'></div>", unsafe_allow_html=True)
model_paths = {
"Déblais et Gravats": "src/model_paths/model_ols_Déblais_gravats.pkl",
"Déchets verts": "src/model_paths/model_ols_Déchets_verts.pkl",
"Encombrants": "src/model_paths/model_ols_Encombrants.pkl",
"Matériaux recyclables": "src/model_paths/model_ols_Matériaux_recyclables.pkl",
"Total autres déchets": "src/model_paths/model_ols_Total_autres_dechets.pkl"
}
col_mapping = {
"Déblais et Gravats": "Déblais_gravats",
"Déchets verts": "Déchets_verts",
"Encombrants": "Encombrants",
"Matériaux recyclables": "Matériaux_recyclables",
"Total autres déchets": "Total_autres_dechets"
}
valeurs_observees = []
valeurs_predites = []
labels = []
if run_eval:
for typologie, path in model_paths.items():
try:
with open(path, "rb") as f:
model = pickle.load(f)
# expected_cols = model.model.exog_names
# if "const" in expected_cols and "const" not in input_df_complete.columns:
# input_df_complete["const"] = 1.0
# prediction = max(0, model.predict(input_df_complete[expected_cols]).iloc[0])
prediction = max(0, model.predict(input_df_complete).iloc[0])
valeurs_predites.append(prediction)
labels.append(typologie)
filtered = observed_df[
(observed_df["Département"] == selected_dept) & (observed_df["année"] == 2019)
]
excel_col = col_mapping.get(typologie)
if not filtered.empty and excel_col in filtered.columns:
valeurs_observees.append(filtered[excel_col].values[0])
else:
valeurs_observees.append(0.0)
except Exception as e:
st.error(f"Erreur avec le modèle {typologie}")
st.exception(e)
if valeurs_observees and valeurs_predites:
x = np.arange(len(labels))
width = 0.4
fig, ax = plt.subplots(figsize=(10, 6))
bars1 = ax.bar(x - width / 2, valeurs_observees, width, label='Observé (2019)', color='steelblue')
bar_colors = [(1, 0, 0, 0.6) if pred > obs else (0, 0.6, 0, 0.6)
for pred, obs in zip(valeurs_predites, valeurs_observees)]
bars2 = ax.bar(x + width / 2, valeurs_predites, width, label='Prévision', color=bar_colors)
for i in range(len(labels)):
ax.text(x[i] - width / 2, valeurs_observees[i] + max(valeurs_observees) * 0.01, f"{valeurs_observees[i]:,.0f}",
ha='center', va='bottom', fontsize=9)
ax.text(x[i] + width / 2, valeurs_predites[i] + max(valeurs_predites) * 0.01, f"{valeurs_predites[i]:,.0f}",
ha='center', va='bottom', fontsize=9)
ax.set_ylabel("Tonnes")
ax.set_title("Comparaison Observé vs Prédit")
ax.set_xticks(x)
ax.set_xticklabels(labels, rotation=45, ha='right')
ax.legend()
st.pyplot(fig)