nath13huggingface commited on
Commit
286122f
·
1 Parent(s): 1921443

Mise à jour de l'application Geodechets

Browse files
model_paths/model_ols_Déblais_gravats.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:14e12a722cf964db3e110a6cdb86bc0b0a0061f0cb347c9b7996080a437b771f
3
+ size 1178661
model_paths/model_ols_Déchets_verts.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:273d5f0172243a494b2115e6bf7fa3e04d153a0dc83c2fc2f55b838490924517
3
+ size 1178659
model_paths/model_ols_Encombrants.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9f294743fd864c5f71b45bfe4b18d561a0ab4211224004c834100735e05372a3
3
+ size 1178656
model_paths/model_ols_Matériaux_recyclables.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9940a9ee9a3aa6548bf33d1d1e27ad2db7ebbe5b893438d72d13eb17c8fc6495
3
+ size 1178667
model_paths/model_ols_Total_autres_dechets.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:daaed3339dfbe9c3ab4a2ece88b693f1d3626471a2b9269c364ec37984c9ebe8
3
+ size 1178665
requirements.txt CHANGED
@@ -1,3 +1,14 @@
 
1
  altair
2
  pandas
3
- streamlit
 
 
 
 
 
 
 
 
 
 
 
1
+
2
  altair
3
  pandas
4
+ streamlit
5
+ matplotlib
6
+ numpy
7
+ openpyxl
8
+ statsmodels
9
+ requests
10
+ boto3
11
+ shap
12
+ langchain
13
+ langchain-mistralai
14
+ python-dotenv
src/streamlit_app.py CHANGED
@@ -1,40 +1,210 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
1
+ # import altair as alt
2
+ # import numpy as np
3
+ # import pandas as pd
4
+ # import streamlit as st
5
+
6
+ # """
7
+ # # Welcome to Streamlit!
8
+
9
+ # Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
+ # If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
+ # forums](https://discuss.streamlit.io).
12
+
13
+ # In the meantime, below is an example of what you can do with just a few lines of code:
14
+ # """
15
+
16
+ # num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
+ # num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
+
19
+ # indices = np.linspace(0, 1, num_points)
20
+ # theta = 2 * np.pi * num_turns * indices
21
+ # radius = indices
22
+
23
+ # x = radius * np.cos(theta)
24
+ # y = radius * np.sin(theta)
25
+
26
+ # df = pd.DataFrame({
27
+ # "x": x,
28
+ # "y": y,
29
+ # "idx": indices,
30
+ # "rand": np.random.randn(num_points),
31
+ # })
32
+
33
+ # st.altair_chart(alt.Chart(df, height=700, width=700)
34
+ # .mark_point(filled=True)
35
+ # .encode(
36
+ # x=alt.X("x", axis=None),
37
+ # y=alt.Y("y", axis=None),
38
+ # color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
+ # size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
+ # ))
41
+ # Import des bibliothéques
42
  import streamlit as st
43
+ import pandas as pd
44
+ import pickle
45
+ import matplotlib.pyplot as plt
46
+ from dotenv import load_dotenv
47
+ import os
48
+
49
+ import numpy as np
50
+ import shap
51
+ from sklearn.linear_model import LinearRegression
52
+ from langchain_mistralai import ChatMistralAI
53
+ from langchain_core.output_parsers import StrOutputParser
54
+
55
+ # Chargement des données
56
+ df = pd.read_csv("https://geodechet.s3.eu-west-3.amazonaws.com/v1/dataset/df_dummies_2019.csv").drop(columns=["Unnamed: 0"], errors="ignore")
57
+ observed_df = pd.read_excel("https://geodechet.s3.eu-west-3.amazonaws.com/v1/dataset/data_wip_v5.xlsx")
58
+
59
+ # liste des départements présents dans les colonnes du df, sans le préfixe "Département_".
60
+ departements = [col.replace("Département_", "") for col in df.columns if col.startswith("Département_")]
61
+
62
+ # Mise en page
63
+ st.set_page_config(layout="wide")
64
+ st.markdown("<h1 style='text-align: center;'>♻️ Simulateur de production de déchets par département</h1>", unsafe_allow_html=True)
65
+
66
+ # Titre + Choix département alignés
67
+ top_col1, top_col2 = st.columns([1, 2])
68
+ with top_col1:
69
+ st.markdown("<h3 style='text-align: center;'>📍 Choix du département</h3>", unsafe_allow_html=True)
70
+ with top_col2:
71
+ st.markdown("<h3 style='text-align: center;'>📈 Comparaison entre valeurs observées et prédites</h3>", unsafe_allow_html=True)
72
+
73
+ # Séparation en colonnes
74
+ top_input_col, chart_col = st.columns([1, 2])
75
+
76
+ with top_input_col:
77
+ selected_dept = st.selectbox("Sélectionner un département", sorted(departements), index=sorted(departements).index("Ain") if "Ain" in departements else 0)
78
+ row_default = df[df[f"Département_{selected_dept}"] == 1].iloc[0]
79
+ default_dict = row_default.to_dict()
80
+
81
+ st.subheader("⚙️ Paramètres modifiables")
82
+ form_input = {}
83
+
84
+ categories = {
85
+ "📊 Population": [
86
+ "densité", , "pop_globale",
87
+ "tranche_age_0-24", "tranche_age_25-59", "tranche_age_60+",
88
+ "csp1_agriculteurs", "csp2_artisans_commerçant_chef_entreprises",
89
+ "csp3_cadres_professions_intellectuelles", "csp4_professions_intermédiaires",
90
+ "csp5_employés", "csp6_ouvriers", "csp7_retraités", "csp8_sans_activité"
91
+ ],
92
+ "🏭 Activité économique": [
93
+ "nb_salaries_secteur_agricole", "nb_salaries_secteur_industrie", "nb_salaries_secteur_service",
94
+ "nbre_entreprises", "nbre_entreprises_agricole", "nbre_entreprises_industrie", "nbre_entreprises_service"
95
+ ],
96
+ "🗑️ Déchets": [
97
+ "tonnage_dechet_produit",
98
+ "Total_autres_dechets",
99
+ "Déblais_gravats",
100
+ "Déchets_verts",
101
+ "Encombrants",
102
+ "Matériaux_recyclables"
103
+ ]
104
+ }
105
+
106
+ for category_name, variables in categories.items():
107
+ with st.expander(category_name, expanded=True):
108
+ for var in variables:
109
+ if var in default_dict:
110
+ col_slider, col_input = st.columns([2, 1])
111
+ with col_slider:
112
+ slider_value = st.slider(
113
+ f"🔧 {var}",
114
+ min_value=float(default_dict[var]) * 0,
115
+ max_value=float(default_dict[var]) * 1.5,
116
+ value=float(default_dict[var]),
117
+ step=1.0,
118
+ key=f"slider_{var}"
119
+ )
120
+ with col_input:
121
+ text_val = st.text_input(f"{var} (manuel)", value=str(slider_value), key=f"text_{var}")
122
+ try:
123
+ form_input[var] = float(text_val)
124
+ except ValueError:
125
+ form_input[var] = slider_value
126
+
127
+ input_df = pd.DataFrame([form_input])
128
+ input_df_complete = row_default.to_frame().T.copy()
129
+ for col in input_df.columns:
130
+ if col in input_df_complete.columns:
131
+ input_df_complete.at[input_df_complete.index[0], col] = input_df.at[0, col]
132
+
133
+ with chart_col:
134
+ st.markdown("<div style='margin-top: 30px;'></div>", unsafe_allow_html=True)
135
+
136
+ btn_col = st.columns([3, 2, 3])[1]
137
+ with btn_col:
138
+ run_eval = st.button("🔍 Lancer l'évaluation")
139
+
140
+ st.markdown("<div style='margin-top: 40px;'></div>", unsafe_allow_html=True)
141
+
142
+ model_paths = {
143
+ "Déblais et Gravats": "src/model_paths/Déblais_gravats.pkl",
144
+ "Déchets verts": "src/model_paths/Déchets_verts.pkl",
145
+ "Encombrants": "src/model_paths/Encombrants.pkl",
146
+ "Matériaux recyclables": "src/model_paths/Matériaux_recyclables.pkl",
147
+ "Total autres déchets": "src/model_paths/Total_autres_dechets.pkl"
148
+ }
149
+
150
+ col_mapping = {
151
+ "Déblais et Gravats": "Déblais_gravats",
152
+ "Déchets verts": "Déchets_verts",
153
+ "Encombrants": "Encombrants",
154
+ "Matériaux recyclables": "Matériaux_recyclables",
155
+ "Total autres déchets": "Total_autres_dechets"
156
+ }
157
+
158
+ valeurs_observees = []
159
+ valeurs_predites = []
160
+ labels = []
161
+
162
+ if run_eval:
163
+ for typologie, path in model_paths.items():
164
+ try:
165
+ with open(path, "rb") as f:
166
+ model = pickle.load(f)
167
+
168
+ expected_cols = model.model.exog_names
169
+ if "const" in expected_cols and "const" not in input_df_complete.columns:
170
+ input_df_complete["const"] = 1.0
171
+
172
+ prediction = max(0, model.predict(input_df_complete[expected_cols]).iloc[0])
173
+ valeurs_predites.append(prediction)
174
+ labels.append(typologie)
175
+
176
+ filtered = observed_df[
177
+ (observed_df["Département"] == selected_dept) & (observed_df["année"] == 2019)
178
+ ]
179
+
180
+ excel_col = col_mapping.get(typologie)
181
+ if not filtered.empty and excel_col in filtered.columns:
182
+ valeurs_observees.append(filtered[excel_col].values[0])
183
+ else:
184
+ valeurs_observees.append(0.0)
185
+ except Exception as e:
186
+ st.error(f"Erreur avec le modèle {typologie}")
187
+ st.exception(e)
188
+
189
+ if valeurs_observees and valeurs_predites:
190
+ x = np.arange(len(labels))
191
+ width = 0.4
192
+ fig, ax = plt.subplots(figsize=(10, 6))
193
+
194
+ bars1 = ax.bar(x - width / 2, valeurs_observees, width, label='Observé (2019)', color='steelblue')
195
+ bar_colors = [(1, 0, 0, 0.6) if pred > obs else (0, 0.6, 0, 0.6)
196
+ for pred, obs in zip(valeurs_predites, valeurs_observees)]
197
+ bars2 = ax.bar(x + width / 2, valeurs_predites, width, label='Prévision', color=bar_colors)
198
+
199
+ for i in range(len(labels)):
200
+ ax.text(x[i] - width / 2, valeurs_observees[i] + max(valeurs_observees) * 0.01, f"{valeurs_observees[i]:,.0f}",
201
+ ha='center', va='bottom', fontsize=9)
202
+ ax.text(x[i] + width / 2, valeurs_predites[i] + max(valeurs_predites) * 0.01, f"{valeurs_predites[i]:,.0f}",
203
+ ha='center', va='bottom', fontsize=9)
204
 
205
+ ax.set_ylabel("Tonnes")
206
+ ax.set_title("Comparaison Observé vs Prédit")
207
+ ax.set_xticks(x)
208
+ ax.set_xticklabels(labels, rotation=45, ha='right')
209
+ ax.legend()
210
+ st.pyplot(fig)