jaimalklyde commited on
Commit
dca8265
·
verified ·
1 Parent(s): e65b23b

Update src/module/Indicateurs_DQ.py

Browse files
Files changed (1) hide show
  1. src/module/Indicateurs_DQ.py +96 -0
src/module/Indicateurs_DQ.py CHANGED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MODULE: INDICATEURS DATA QUALITY (DQ)
3
+ =====================================
4
+ Responsabilité : Audit, Détection d'anomalies, Visualisation des erreurs.
5
+ Ne modifie pas les données, les juge.
6
+ """
7
+ import streamlit as st
8
+ import pandas as pd
9
+ import plotly.express as px
10
+ import plotly.graph_objects as go
11
+ from Function.Validation_Contract import ETL_Engine
12
+
13
+ def show_dq_dashboard(client, sheet_name):
14
+ st.markdown("## 🛡️ CENTRE DE CONTRÔLE DATA QUALITY")
15
+
16
+ # On charge via l'ETL mais on va surtout analyser les NaN et les outliers
17
+ etl = ETL_Engine(client, sheet_name)
18
+
19
+ # On vérifie si les données sont déjà en session, sinon on charge
20
+ if 'data_explorer' not in st.session_state or not st.session_state.data_explorer.dataframes:
21
+ st.info("Chargement des données pour Audit...")
22
+ success, data = etl.run_etl()
23
+ if success:
24
+ # Astuce: on stocke quand même dans le session_state global pour partager
25
+ # Mais ici on s'en sert pour la DQ
26
+ pass
27
+ else:
28
+ st.error(f"Erreur chargement : {data}")
29
+ return
30
+ else:
31
+ data = st.session_state.data_explorer.dataframes
32
+
33
+ # --- KPI GLOBAL ---
34
+ st.markdown("### 📊 Synthèse de Santé des Données")
35
+ col1, col2, col3, col4 = st.columns(4)
36
+
37
+ df_pat = data.get('patients')
38
+ df_sej = data.get('sejours')
39
+ df_res = data.get('ressources')
40
+
41
+ # Calcul des indicateurs inspirés du notebook
42
+ missing_birth = df_pat['date_naissance'].isnull().sum() if df_pat is not None else 0
43
+ inverted_dates = df_sej[df_sej['date_sortie'] < df_sej['date_entree']].shape[0] if df_sej is not None else 0
44
+ capa_overflow = df_res[df_res['lits_occupes'] > df_res['lits_total']].shape[0] if df_res is not None else 0
45
+ duplicates = df_pat.duplicated(subset=['nom', 'prenom']).sum() if df_pat is not None else 0
46
+
47
+ col1.metric("Doublons Patients", duplicates, delta=None, delta_color="inverse")
48
+ col2.metric("Dates Inversées (Séjours)", inverted_dates, delta="Bloquant", delta_color="inverse")
49
+ col3.metric("Violations Capacité", capa_overflow, delta="Critique", delta_color="inverse")
50
+ col4.metric("Dates Naissance Manquantes", missing_birth, delta="Qualité", delta_color="inverse")
51
+
52
+ st.divider()
53
+
54
+ # --- SECTION 1 : COMPLETENESS (Remplissage) ---
55
+ st.subheader("1. Complétude des Données (Missing Values)")
56
+ if df_pat is not None:
57
+ # Calcul du taux de remplissage par colonne
58
+ missing_df = df_pat.isnull().mean() * 100
59
+ missing_df = missing_df[missing_df > 0].reset_index()
60
+ missing_df.columns = ['Colonne', 'Pourcentage Manquant']
61
+
62
+ fig_miss = px.bar(missing_df, x='Colonne', y='Pourcentage Manquant',
63
+ title="Données manquantes - Table Patients",
64
+ color='Pourcentage Manquant', color_continuous_scale='Reds')
65
+ st.plotly_chart(fig_miss, use_container_width=True)
66
+
67
+ # --- SECTION 2 : ACCURACY (Outliers) ---
68
+ st.subheader("2. Exactitude & Valeurs Aberrantes")
69
+ c1, c2 = st.columns(2)
70
+
71
+ with c1:
72
+ if df_pat is not None:
73
+ # Visualisation des âges > 100 ans ou < 0
74
+ fig_age = px.box(df_pat, y='age', title="Distribution des Âges (Détection Outliers)",
75
+ points="all") # Affiche tous les points
76
+ # Zone rouge pour les âges impossibles
77
+ fig_age.add_hrect(y0=120, y1=200, fillcolor="red", opacity=0.1, annotation_text="Erreur > 120 ans")
78
+ fig_age.add_hrect(y0=-10, y1=0, fillcolor="red", opacity=0.1, annotation_text="Négatif")
79
+ st.plotly_chart(fig_age, use_container_width=True)
80
+
81
+ with c2:
82
+ if df_res is not None:
83
+ # Visualisation Occupation > 100%
84
+ df_res['taux_pct'] = df_res['taux_occupation'] * 100
85
+ fig_capa = px.scatter(df_res, x='date', y='taux_pct', color='service_code',
86
+ title="Anomalies de Capacité (>100%)")
87
+ fig_capa.add_hline(y=100, line_dash="dash", line_color="red", annotation_text="Saturation Théorique")
88
+ st.plotly_chart(fig_capa, use_container_width=True)
89
+
90
+ # --- SECTION 3 : CONSISTENCY (Intégrité) ---
91
+ st.subheader("3. Cohérence Temporelle")
92
+ if inverted_dates > 0:
93
+ st.error(f"🚨 ALERT : {inverted_dates} séjours ont une date de sortie antérieure à la date d'entrée.")
94
+ st.dataframe(df_sej[df_sej['date_sortie'] < df_sej['date_entree']].head(10), use_container_width=True)
95
+ else:
96
+ st.success("✅ Aucune incohérence temporelle détectée dans les séjours.")