jaimalklyde commited on
Commit
d7a4991
·
verified ·
1 Parent(s): 0ea73d0

Update src/module/Forecasting.py

Browse files
Files changed (1) hide show
  1. src/module/Forecasting.py +40 -40
src/module/Forecasting.py CHANGED
@@ -163,10 +163,10 @@ class HospitalForecaster:
163
  Returns:
164
  Dictionnaire des métriques
165
  """
166
- progress_bar = st.progress(0, text="🔄 Entraînement en cours...")
167
 
168
  # ===== 1. LightGBM =====
169
- progress_bar.progress(0.1, text="⚡ LightGBM...")
170
  lgb_model = lgb.LGBMRegressor(
171
  n_estimators=500,
172
  learning_rate=0.05,
@@ -190,7 +190,7 @@ class HospitalForecaster:
190
  self._evaluate_model('LightGBM', lgb_model)
191
 
192
  # ===== 2. XGBoost =====
193
- progress_bar.progress(0.4, text="🚀 XGBoost...")
194
  xgb_model = xgb.XGBRegressor(
195
  n_estimators=500,
196
  learning_rate=0.05,
@@ -214,7 +214,7 @@ class HospitalForecaster:
214
  self._evaluate_model('XGBoost', xgb_model)
215
 
216
  # ===== 3. Random Forest =====
217
- progress_bar.progress(0.7, text="🌲 Random Forest...")
218
  rf_model = RandomForestRegressor(
219
  n_estimators=300,
220
  max_depth=15,
@@ -485,7 +485,7 @@ def show_forecasting_module(client, sheet_name):
485
  if 'ml_features' not in st.session_state:
486
  st.error("❌ **Données ML absentes.** Veuillez d'abord exécuter le module **Feature Engineering**.")
487
 
488
- if st.button("🔄 Aller au Feature Engineering"):
489
  st.switch_page("pages/03_Features.py")
490
  return
491
 
@@ -496,7 +496,7 @@ def show_forecasting_module(client, sheet_name):
496
  # ===== CONFIGURATION =====
497
  st.divider()
498
 
499
- with st.expander("⚙️ Configuration de l'Entraînement", expanded=False):
500
  col1, col2, col3 = st.columns(3)
501
 
502
  with col1:
@@ -534,7 +534,7 @@ def show_forecasting_module(client, sheet_name):
534
 
535
  try:
536
  # Préparation des données
537
- with st.spinner("📊 Préparation des données (Train/Val/Test)..."):
538
  split_info = forecaster.prepare_data(
539
  target_col=target,
540
  val_days=val_days,
@@ -542,7 +542,7 @@ def show_forecasting_module(client, sheet_name):
542
  )
543
 
544
  # Affichage des plages de dates
545
- st.markdown("### 📅 Plages de Dates des Sets")
546
 
547
  col1, col2, col3 = st.columns(3)
548
 
@@ -583,7 +583,7 @@ def show_forecasting_module(client, sheet_name):
583
  except Exception as e:
584
  st.error(f"❌ **Erreur lors de l'entraînement :** {str(e)}")
585
  import traceback
586
- with st.expander("🔍 Détails de l'erreur"):
587
  st.code(traceback.format_exc())
588
  return
589
 
@@ -595,16 +595,16 @@ def show_forecasting_module(client, sheet_name):
595
 
596
  # ===== ONGLETS PRINCIPAUX =====
597
  tab_future, tab_audit, tab_export = st.tabs([
598
- "🔮 Prédictions Futures",
599
- "⚖️ Audit & Comparaison",
600
- "📥 Export & Données"
601
  ])
602
 
603
  # ================================================================
604
  # ONGLET 1 : PRÉDICTIONS FUTURES
605
  # ================================================================
606
  with tab_future:
607
- st.markdown("### 🚀 Projections Récursives avec Saisonnalité")
608
 
609
  col_h1, col_h2 = st.columns([3, 1])
610
 
@@ -622,7 +622,7 @@ def show_forecasting_module(client, sheet_name):
622
  months_map = {"1 Mois": 1, "3 Mois": 3, "6 Mois": 6, "12 Mois": 12}
623
  months = months_map[horizon_label]
624
 
625
- with st.spinner("🔮 Calcul de la trajectoire récursive avec saisonnalité..."):
626
  f_dates, f_values, conf_intervals = forecaster.generate_future_forecast_recursive(months)
627
 
628
  # Graphique des prédictions futures
@@ -633,7 +633,7 @@ def show_forecasting_module(client, sheet_name):
633
  fig.add_trace(go.Scatter(
634
  x=hist['date'],
635
  y=hist[target],
636
- name="📊 Historique Réel",
637
  line=dict(color='gray', width=2),
638
  opacity=0.6
639
  ))
@@ -642,7 +642,7 @@ def show_forecasting_module(client, sheet_name):
642
  fig.add_trace(go.Scatter(
643
  x=f_dates,
644
  y=f_values,
645
- name=f"🔮 Projection {best}",
646
  line=dict(color='#00E676', width=3),
647
  mode='lines+markers',
648
  marker=dict(size=5)
@@ -697,7 +697,7 @@ def show_forecasting_module(client, sheet_name):
697
  col2.metric("Maximum Prévu", f"{np.max(f_values):.1f}")
698
  col3.metric("Minimum Prévu", f"{np.min(f_values):.1f}")
699
  col4.metric("Tendance",
700
- "↗️ Hausse" if f_values[-1] > f_values[0] else "↘️ Baisse",
701
  f"{((f_values[-1] / f_values[0]) - 1) * 100:+.1f}%")
702
 
703
  # Détection d'anomalies futures
@@ -715,20 +715,20 @@ def show_forecasting_module(client, sheet_name):
715
  else:
716
  st.success("✅ Aucun pic anormal détecté dans la période")
717
 
718
- st.caption(f"💡 Prédiction générée par **{best}** | Fiabilité : **{metrics[best]['R²']*100:.0f}%**")
719
 
720
  # ================================================================
721
  # ONGLET 2 : AUDIT & COMPARAISON
722
  # ================================================================
723
  with tab_audit:
724
- st.markdown("### 🏆 Le Champion de la Prédiction")
725
 
726
  # Annonce du vainqueur
727
  col_winner, col_reset = st.columns([4, 1])
728
 
729
  with col_winner:
730
  st.success(f"""
731
- ### ✨ Gagnant : **{best}**
732
 
733
  Sur les **{split_info['test']['n_samples']} derniers jours** de test, ce modèle a montré
734
  la meilleure précision avec une erreur moyenne de seulement **{metrics[best]['MAE']:.2f}** unités par jour.
@@ -738,7 +738,7 @@ def show_forecasting_module(client, sheet_name):
738
  """)
739
 
740
  with col_reset:
741
- if st.button("♻️ Réinitialiser", help="Relancer l'entraînement"):
742
  for key in ['forecaster', 'metrics', 'split_info', 'forecast_target']:
743
  if key in st.session_state:
744
  del st.session_state[key]
@@ -747,7 +747,7 @@ def show_forecasting_module(client, sheet_name):
747
  st.divider()
748
 
749
  # ===== TABLEAU COMPARATIF =====
750
- st.markdown("### 📊 Tableau Comparatif Détaillé")
751
 
752
  comparison_data = []
753
  for model_name in ['XGBoost', 'LightGBM', 'Random Forest']:
@@ -769,7 +769,7 @@ def show_forecasting_module(client, sheet_name):
769
  )
770
 
771
  # Explications des métriques
772
- with st.expander("📖 Comprendre les Métriques"):
773
  st.markdown("""
774
  **R² (Coefficient de Détermination) :**
775
  - Mesure de 0% à 100% : plus c'est proche de 100%, mieux c'est
@@ -797,7 +797,7 @@ def show_forecasting_module(client, sheet_name):
797
  st.divider()
798
 
799
  # ===== GRAPHIQUE COMPARATIF SUR TEST SET =====
800
- st.markdown("### 👁️ Comparaison Visuelle sur le Test Set")
801
 
802
  fig_comp = go.Figure()
803
 
@@ -805,7 +805,7 @@ def show_forecasting_module(client, sheet_name):
805
  fig_comp.add_trace(go.Scatter(
806
  x=forecaster.dates_test,
807
  y=forecaster.y_test,
808
- name="🎯 RÉALITÉ",
809
  line=dict(color='white', width=4, dash='dot'),
810
  mode='lines+markers',
811
  marker=dict(size=6)
@@ -845,22 +845,22 @@ def show_forecasting_module(client, sheet_name):
845
 
846
  st.plotly_chart(fig_comp, use_container_width=True)
847
 
848
- st.caption("💡 **Plus une ligne colorée est proche de la ligne blanche, meilleur est le modèle**")
849
 
850
  st.divider()
851
 
852
  # ===== SHAP : INTERPRÉTABILITÉ =====
853
- st.markdown("### 🧠 Comprendre les Décisions de l'IA (SHAP)")
854
 
855
  st.info("""
856
  **SHAP** (SHapley Additive exPlanations) révèle **quelles variables influencent le plus**
857
  les prédictions du modèle.
858
 
859
- 👉 Plus la barre est longue, plus cette feature est importante pour les décisions de l'IA.
860
  """)
861
 
862
  if SHAP_AVAILABLE:
863
- with st.spinner("🔍 Calcul des valeurs SHAP (analyse d'importance)..."):
864
  explainer, shap_values, X_sample = forecaster.compute_shap_values(n_samples=200)
865
 
866
  if shap_values is not None:
@@ -890,7 +890,7 @@ def show_forecasting_module(client, sheet_name):
890
  plt.close()
891
 
892
  # Explications textuelles
893
- st.markdown("#### 📌 Interprétation")
894
 
895
  # Top 5 features
896
  feature_importance = pd.DataFrame({
@@ -905,19 +905,19 @@ def show_forecasting_module(client, sheet_name):
905
 
906
  # Traduction en français
907
  if 'lag' in feature:
908
- explanation = f"📅 Historique récent ({feature})"
909
  elif 'mean' in feature or 'rolling' in feature:
910
- explanation = f"📈 Tendance sur plusieurs jours ({feature})"
911
  elif 'taux' in feature:
912
- explanation = f"💹 Taux ou ratio ({feature})"
913
  elif 'personnel' in feature:
914
- explanation = f"👥 Ressources humaines ({feature})"
915
  elif 'scenario' in feature or 'intensity' in feature:
916
- explanation = f"🚨 Scénario/événement ({feature})"
917
  elif 'mois' in feature or 'jour' in feature:
918
- explanation = f"📆 Facteur temporel ({feature})"
919
  else:
920
- explanation = f"🔧 {feature}"
921
 
922
  st.write(f"- {explanation}")
923
 
@@ -937,7 +937,7 @@ def show_forecasting_module(client, sheet_name):
937
 
938
  with col1:
939
  # Export des métriques
940
- st.markdown("#### 📊 Métriques des Modèles")
941
 
942
  metrics_df = pd.DataFrame(metrics).T
943
  metrics_csv = metrics_df.to_csv(index=True).encode('utf-8')
@@ -953,7 +953,7 @@ def show_forecasting_module(client, sheet_name):
953
 
954
  with col2:
955
  # Export des prédictions sur test
956
- st.markdown("#### 🎯 Prédictions Test Set")
957
 
958
  predictions_df = pd.DataFrame({
959
  'date': forecaster.dates_test,
@@ -975,7 +975,7 @@ def show_forecasting_module(client, sheet_name):
975
  st.dataframe(predictions_df.head(10), use_container_width=True)
976
 
977
  # Export des prédictions futures
978
- st.markdown("#### 🔮 Prédictions Futures")
979
 
980
  if 'f_dates' in locals() and 'f_values' in locals():
981
  future_df = pd.DataFrame({
 
163
  Returns:
164
  Dictionnaire des métriques
165
  """
166
+ progress_bar = st.progress(0, text=" Entraînement en cours...")
167
 
168
  # ===== 1. LightGBM =====
169
+ progress_bar.progress(0.1, text=" LightGBM...")
170
  lgb_model = lgb.LGBMRegressor(
171
  n_estimators=500,
172
  learning_rate=0.05,
 
190
  self._evaluate_model('LightGBM', lgb_model)
191
 
192
  # ===== 2. XGBoost =====
193
+ progress_bar.progress(0.4, text=" XGBoost...")
194
  xgb_model = xgb.XGBRegressor(
195
  n_estimators=500,
196
  learning_rate=0.05,
 
214
  self._evaluate_model('XGBoost', xgb_model)
215
 
216
  # ===== 3. Random Forest =====
217
+ progress_bar.progress(0.7, text=" Random Forest...")
218
  rf_model = RandomForestRegressor(
219
  n_estimators=300,
220
  max_depth=15,
 
485
  if 'ml_features' not in st.session_state:
486
  st.error("❌ **Données ML absentes.** Veuillez d'abord exécuter le module **Feature Engineering**.")
487
 
488
+ if st.button(" Aller au Feature Engineering"):
489
  st.switch_page("pages/03_Features.py")
490
  return
491
 
 
496
  # ===== CONFIGURATION =====
497
  st.divider()
498
 
499
+ with st.expander(" Configuration de l'Entraînement", expanded=False):
500
  col1, col2, col3 = st.columns(3)
501
 
502
  with col1:
 
534
 
535
  try:
536
  # Préparation des données
537
+ with st.spinner(" Préparation des données (Train/Val/Test)..."):
538
  split_info = forecaster.prepare_data(
539
  target_col=target,
540
  val_days=val_days,
 
542
  )
543
 
544
  # Affichage des plages de dates
545
+ st.markdown("### Plages de Dates des Sets")
546
 
547
  col1, col2, col3 = st.columns(3)
548
 
 
583
  except Exception as e:
584
  st.error(f"❌ **Erreur lors de l'entraînement :** {str(e)}")
585
  import traceback
586
+ with st.expander(" Détails de l'erreur"):
587
  st.code(traceback.format_exc())
588
  return
589
 
 
595
 
596
  # ===== ONGLETS PRINCIPAUX =====
597
  tab_future, tab_audit, tab_export = st.tabs([
598
+ " Prédictions Futures",
599
+ " Audit & Comparaison",
600
+ " Export & Données"
601
  ])
602
 
603
  # ================================================================
604
  # ONGLET 1 : PRÉDICTIONS FUTURES
605
  # ================================================================
606
  with tab_future:
607
+ st.markdown("### Projections Récursives avec Saisonnalité")
608
 
609
  col_h1, col_h2 = st.columns([3, 1])
610
 
 
622
  months_map = {"1 Mois": 1, "3 Mois": 3, "6 Mois": 6, "12 Mois": 12}
623
  months = months_map[horizon_label]
624
 
625
+ with st.spinner(" Calcul de la trajectoire récursive avec saisonnalité..."):
626
  f_dates, f_values, conf_intervals = forecaster.generate_future_forecast_recursive(months)
627
 
628
  # Graphique des prédictions futures
 
633
  fig.add_trace(go.Scatter(
634
  x=hist['date'],
635
  y=hist[target],
636
+ name=" Historique Réel",
637
  line=dict(color='gray', width=2),
638
  opacity=0.6
639
  ))
 
642
  fig.add_trace(go.Scatter(
643
  x=f_dates,
644
  y=f_values,
645
+ name=f" Projection {best}",
646
  line=dict(color='#00E676', width=3),
647
  mode='lines+markers',
648
  marker=dict(size=5)
 
697
  col2.metric("Maximum Prévu", f"{np.max(f_values):.1f}")
698
  col3.metric("Minimum Prévu", f"{np.min(f_values):.1f}")
699
  col4.metric("Tendance",
700
+ " Hausse" if f_values[-1] > f_values[0] else " Baisse",
701
  f"{((f_values[-1] / f_values[0]) - 1) * 100:+.1f}%")
702
 
703
  # Détection d'anomalies futures
 
715
  else:
716
  st.success("✅ Aucun pic anormal détecté dans la période")
717
 
718
+ st.caption(f" Prédiction générée par **{best}** | Fiabilité : **{metrics[best]['R²']*100:.0f}%**")
719
 
720
  # ================================================================
721
  # ONGLET 2 : AUDIT & COMPARAISON
722
  # ================================================================
723
  with tab_audit:
724
+ st.markdown("### Le Champion de la Prédiction")
725
 
726
  # Annonce du vainqueur
727
  col_winner, col_reset = st.columns([4, 1])
728
 
729
  with col_winner:
730
  st.success(f"""
731
+ ### Gagnant : **{best}**
732
 
733
  Sur les **{split_info['test']['n_samples']} derniers jours** de test, ce modèle a montré
734
  la meilleure précision avec une erreur moyenne de seulement **{metrics[best]['MAE']:.2f}** unités par jour.
 
738
  """)
739
 
740
  with col_reset:
741
+ if st.button(" Réinitialiser", help="Relancer l'entraînement"):
742
  for key in ['forecaster', 'metrics', 'split_info', 'forecast_target']:
743
  if key in st.session_state:
744
  del st.session_state[key]
 
747
  st.divider()
748
 
749
  # ===== TABLEAU COMPARATIF =====
750
+ st.markdown("### Tableau Comparatif Détaillé")
751
 
752
  comparison_data = []
753
  for model_name in ['XGBoost', 'LightGBM', 'Random Forest']:
 
769
  )
770
 
771
  # Explications des métriques
772
+ with st.expander(" Comprendre les Métriques"):
773
  st.markdown("""
774
  **R² (Coefficient de Détermination) :**
775
  - Mesure de 0% à 100% : plus c'est proche de 100%, mieux c'est
 
797
  st.divider()
798
 
799
  # ===== GRAPHIQUE COMPARATIF SUR TEST SET =====
800
+ st.markdown("### Comparaison Visuelle sur le Test Set")
801
 
802
  fig_comp = go.Figure()
803
 
 
805
  fig_comp.add_trace(go.Scatter(
806
  x=forecaster.dates_test,
807
  y=forecaster.y_test,
808
+ name=" RÉALITÉ",
809
  line=dict(color='white', width=4, dash='dot'),
810
  mode='lines+markers',
811
  marker=dict(size=6)
 
845
 
846
  st.plotly_chart(fig_comp, use_container_width=True)
847
 
848
+ st.caption(" **Plus une ligne colorée est proche de la ligne blanche, meilleur est le modèle**")
849
 
850
  st.divider()
851
 
852
  # ===== SHAP : INTERPRÉTABILITÉ =====
853
+ st.markdown("### Comprendre les Décisions de l'IA (SHAP)")
854
 
855
  st.info("""
856
  **SHAP** (SHapley Additive exPlanations) révèle **quelles variables influencent le plus**
857
  les prédictions du modèle.
858
 
859
+ Plus la barre est longue, plus cette feature est importante pour les décisions de l'IA.
860
  """)
861
 
862
  if SHAP_AVAILABLE:
863
+ with st.spinner(" Calcul des valeurs SHAP (analyse d'importance)..."):
864
  explainer, shap_values, X_sample = forecaster.compute_shap_values(n_samples=200)
865
 
866
  if shap_values is not None:
 
890
  plt.close()
891
 
892
  # Explications textuelles
893
+ st.markdown("#### Interprétation")
894
 
895
  # Top 5 features
896
  feature_importance = pd.DataFrame({
 
905
 
906
  # Traduction en français
907
  if 'lag' in feature:
908
+ explanation = f" Historique récent ({feature})"
909
  elif 'mean' in feature or 'rolling' in feature:
910
+ explanation = f" Tendance sur plusieurs jours ({feature})"
911
  elif 'taux' in feature:
912
+ explanation = f" Taux ou ratio ({feature})"
913
  elif 'personnel' in feature:
914
+ explanation = f" Ressources humaines ({feature})"
915
  elif 'scenario' in feature or 'intensity' in feature:
916
+ explanation = f" Scénario/événement ({feature})"
917
  elif 'mois' in feature or 'jour' in feature:
918
+ explanation = f" Facteur temporel ({feature})"
919
  else:
920
+ explanation = f" {feature}"
921
 
922
  st.write(f"- {explanation}")
923
 
 
937
 
938
  with col1:
939
  # Export des métriques
940
+ st.markdown("#### Métriques des Modèles")
941
 
942
  metrics_df = pd.DataFrame(metrics).T
943
  metrics_csv = metrics_df.to_csv(index=True).encode('utf-8')
 
953
 
954
  with col2:
955
  # Export des prédictions sur test
956
+ st.markdown("#### Prédictions Test Set")
957
 
958
  predictions_df = pd.DataFrame({
959
  'date': forecaster.dates_test,
 
975
  st.dataframe(predictions_df.head(10), use_container_width=True)
976
 
977
  # Export des prédictions futures
978
+ st.markdown("#### Prédictions Futures")
979
 
980
  if 'f_dates' in locals() and 'f_values' in locals():
981
  future_df = pd.DataFrame({