| | |
| | """ |
| | Interface pour le réseau bayésien d'évaluation d'autonomie |
| | Utilise pgmpy et pyAgrum pour charger et analyser le réseau BIF |
| | """ |
| |
|
| | import sys |
| | import os |
| | from typing import Dict, List, Optional, Tuple |
| | import pandas as pd |
| | import numpy as np |
| |
|
| | |
| | try: |
| | from pgmpy.readwrite import BIFReader |
| | from pgmpy.inference import VariableElimination |
| | from pgmpy.models import BayesianNetwork |
| | PGMPY_AVAILABLE = True |
| | except ImportError: |
| | PGMPY_AVAILABLE = False |
| | print("Warning: pgmpy not installed. Some features will be limited.") |
| |
|
| | try: |
| | import pyAgrum as gum |
| | PYAGRUM_AVAILABLE = True |
| | except ImportError: |
| | PYAGRUM_AVAILABLE = False |
| | print("Warning: pyAgrum not installed. Some features will be limited.") |
| |
|
| | |
| | try: |
| | import streamlit as st |
| | import plotly.graph_objects as go |
| | import plotly.express as px |
| | STREAMLIT_AVAILABLE = True |
| | except ImportError: |
| | STREAMLIT_AVAILABLE = False |
| |
|
| | class AutonomyBayesianNetwork: |
| | """Classe principale pour gérer le réseau bayésien d'autonomie""" |
| |
|
| | def __init__(self, bif_file: str = "autonomy_functional_complete.bif"): |
| | self.bif_file = bif_file |
| | self.pgmpy_model = None |
| | self.pyagrum_model = None |
| | self.inference_engine = None |
| |
|
| | |
| | self.non_actionable_vars = ['Age', 'Sex', 'Education_Level'] |
| | self.actionable_vars = ['Physical_Activity', 'BMI_Category', 'Smoking_Status', 'Social_Support', 'Social_Engagement'] |
| | self.intermediate_vars = ['Physical_Frailty', 'Cognitive_Function', 'Depression'] |
| | self.outcome_vars = ['Global_Autonomy'] |
| |
|
| | self.load_network() |
| |
|
| | def load_network(self): |
| | """Charge le réseau depuis le fichier BIF""" |
| | |
| | debug_messages = [] |
| | debug_messages.append(f"🔍 Debug - Chargement réseau:") |
| | debug_messages.append(f" - Fichier BIF: {self.bif_file}") |
| | debug_messages.append(f" - Répertoire courant: {os.getcwd()}") |
| | debug_messages.append(f" - Fichier existe: {os.path.exists(self.bif_file)}") |
| | debug_messages.append(f" - pgmpy disponible: {PGMPY_AVAILABLE}") |
| | debug_messages.append(f" - pyagrum disponible: {PYAGRUM_AVAILABLE}") |
| |
|
| | if os.path.exists(self.bif_file): |
| | try: |
| | with open(self.bif_file, 'r') as f: |
| | content_preview = f.read(200) |
| | debug_messages.append(f" - Aperçu fichier: {content_preview[:100]}...") |
| | except Exception as e: |
| | debug_messages.append(f" - Erreur lecture fichier: {e}") |
| | else: |
| | debug_messages.append(f" - ❌ Fichier {self.bif_file} non trouvé!") |
| |
|
| | |
| | self.debug_messages = debug_messages |
| |
|
| | |
| | for msg in debug_messages: |
| | print(msg) |
| |
|
| | if PGMPY_AVAILABLE and os.path.exists(self.bif_file): |
| | try: |
| | reader = BIFReader(self.bif_file) |
| | self.pgmpy_model = reader.get_model() |
| | self.inference_engine = VariableElimination(self.pgmpy_model) |
| | success_msg = f"✓ Réseau chargé avec pgmpy depuis {self.bif_file}" |
| | nodes_msg = f" - {len(list(self.pgmpy_model.nodes()))} nœuds, {len(list(self.pgmpy_model.edges()))} arcs" |
| | print(success_msg) |
| | print(nodes_msg) |
| | self.debug_messages.extend([success_msg, nodes_msg]) |
| | except Exception as e: |
| | error_msg = f"❌ Erreur pgmpy: {e}" |
| | print(error_msg) |
| | self.debug_messages.append(error_msg) |
| |
|
| | if PYAGRUM_AVAILABLE and os.path.exists(self.bif_file): |
| | try: |
| | self.pyagrum_model = gum.loadBN(self.bif_file) |
| | success_msg = f"✓ Réseau chargé avec pyAgrum depuis {self.bif_file}" |
| | print(success_msg) |
| | self.debug_messages.append(success_msg) |
| | except Exception as e: |
| | error_msg = f"❌ Erreur pyAgrum: {e}" |
| | print(error_msg) |
| | self.debug_messages.append(error_msg) |
| |
|
| | |
| | if self.pgmpy_model is None and self.pyagrum_model is None: |
| | final_msg = "❌ Aucun modèle chargé!" |
| | print(final_msg) |
| | self.debug_messages.append(final_msg) |
| |
|
| | |
| | if not PGMPY_AVAILABLE: |
| | suggestion = "💡 pgmpy non disponible - vérifiez requirements.txt et installation" |
| | print(suggestion) |
| | self.debug_messages.append(suggestion) |
| |
|
| | if not PYAGRUM_AVAILABLE: |
| | suggestion = "💡 pyAgrum non disponible - installation optionnelle" |
| | print(suggestion) |
| | self.debug_messages.append(suggestion) |
| |
|
| | def get_network_structure(self) -> Dict: |
| | """Retourne la structure du réseau""" |
| | structure = { |
| | 'nodes': [], |
| | 'edges': [], |
| | 'categories': {} |
| | } |
| |
|
| | |
| | if self.pgmpy_model: |
| | for node in self.pgmpy_model.nodes(): |
| | category = self._get_variable_category(node) |
| | structure['nodes'].append({ |
| | 'name': node, |
| | 'category': category |
| | }) |
| | structure['categories'][node] = category |
| |
|
| | structure['edges'] = list(self.pgmpy_model.edges()) |
| |
|
| | elif self.pyagrum_model and PYAGRUM_AVAILABLE: |
| | for node in self.pyagrum_model.names(): |
| | category = self._get_variable_category(node) |
| | structure['nodes'].append({ |
| | 'name': node, |
| | 'category': category, |
| | 'domain': list(self.pyagrum_model.variable(node).labels()) |
| | }) |
| | structure['categories'][node] = category |
| |
|
| | for arc in self.pyagrum_model.arcs(): |
| | parent = self.pyagrum_model.variable(arc[0]).name() |
| | child = self.pyagrum_model.variable(arc[1]).name() |
| | structure['edges'].append((parent, child)) |
| |
|
| | return structure |
| |
|
| | def _get_variable_category(self, var_name: str) -> str: |
| | """Détermine la catégorie d'une variable""" |
| | if var_name in self.non_actionable_vars: |
| | return 'non_actionable' |
| | elif var_name in self.actionable_vars: |
| | return 'actionable' |
| | elif var_name in self.intermediate_vars: |
| | return 'intermediate' |
| | elif var_name in self.outcome_vars: |
| | return 'outcome' |
| | else: |
| | return 'unknown' |
| |
|
| | def perform_inference_pgmpy(self, evidence: Dict, query_vars: List[str]) -> pd.DataFrame: |
| | """Effectue l'inférence avec pgmpy""" |
| | if not self.inference_engine: |
| | return pd.DataFrame() |
| |
|
| | try: |
| | result = self.inference_engine.query(variables=query_vars, evidence=evidence) |
| |
|
| | |
| | data = [] |
| | for var in query_vars: |
| | if hasattr(result, 'values'): |
| | |
| | probs = result.values |
| | if var in result.variables: |
| | var_idx = result.variables.index(var) |
| | states = result.state_names[var] |
| |
|
| | if len(result.variables) == 1: |
| | |
| | for i, state in enumerate(states): |
| | data.append({ |
| | 'Variable': var, |
| | 'State': state, |
| | 'Probability': probs[i] |
| | }) |
| | else: |
| | |
| | marg_factor = result.marginalize([v for v in result.variables if v != var], inplace=False) |
| | for i, state in enumerate(states): |
| | data.append({ |
| | 'Variable': var, |
| | 'State': state, |
| | 'Probability': marg_factor.values[i] |
| | }) |
| |
|
| | return pd.DataFrame(data) |
| | except Exception as e: |
| | print(f"Erreur d'inférence pgmpy: {e}") |
| | return pd.DataFrame() |
| |
|
| | def perform_inference_pyagrum(self, evidence: Dict, query_vars: List[str]) -> pd.DataFrame: |
| | """Effectue l'inférence avec pyAgrum ou pgmpy en fallback""" |
| | |
| | if self.pyagrum_model and PYAGRUM_AVAILABLE: |
| | try: |
| | ie = gum.LazyPropagation(self.pyagrum_model) |
| |
|
| | |
| | for var, value in evidence.items(): |
| | if var in self.pyagrum_model.names(): |
| | var_idx = self.pyagrum_model.idFromName(var) |
| | labels = self.pyagrum_model.variable(var_idx).labels() |
| | if value in labels: |
| | ie.setEvidence({var: value}) |
| |
|
| | ie.makeInference() |
| |
|
| | |
| | data = [] |
| | for var in query_vars: |
| | if var in self.pyagrum_model.names(): |
| | posterior = ie.posterior(var) |
| | var_idx = self.pyagrum_model.idFromName(var) |
| | labels = self.pyagrum_model.variable(var_idx).labels() |
| |
|
| | for i, label in enumerate(labels): |
| | data.append({ |
| | 'Variable': var, |
| | 'State': label, |
| | 'Probability': posterior[i] |
| | }) |
| |
|
| | return pd.DataFrame(data) |
| | except Exception as e: |
| | print(f"Erreur d'inférence pyAgrum: {e}") |
| |
|
| | |
| | if self.inference_engine: |
| | return self.perform_inference_pgmpy(evidence, query_vars) |
| |
|
| | return pd.DataFrame() |
| |
|
| | def analyze_intervention(self, intervention: Dict, target: str = 'Global_Autonomy') -> Dict: |
| | """Analyse l'impact d'une intervention sur l'autonomie""" |
| | results = { |
| | 'baseline': None, |
| | 'intervention': None, |
| | 'improvement': None |
| | } |
| |
|
| | |
| | baseline = self.perform_inference_pgmpy({}, [target]) |
| | if not baseline.empty: |
| | results['baseline'] = baseline |
| |
|
| | |
| | intervention_result = self.perform_inference_pgmpy(intervention, [target]) |
| | if not intervention_result.empty: |
| | results['intervention'] = intervention_result |
| |
|
| | |
| | if results['baseline'] is not None and results['intervention'] is not None: |
| | baseline_autonomous = results['baseline'][ |
| | results['baseline']['State'] == 'autonomous']['Probability'].values |
| | intervention_autonomous = results['intervention'][ |
| | results['intervention']['State'] == 'autonomous']['Probability'].values |
| |
|
| | if len(baseline_autonomous) > 0 and len(intervention_autonomous) > 0: |
| | results['improvement'] = { |
| | 'absolute': intervention_autonomous[0] - baseline_autonomous[0], |
| | 'relative': ((intervention_autonomous[0] - baseline_autonomous[0]) / |
| | baseline_autonomous[0] * 100) |
| | } |
| |
|
| | return results |
| |
|
| | def get_most_influential_factors(self, target: str = 'Global_Autonomy', |
| | n_top: int = 5) -> List[Tuple[str, float]]: |
| | """Identifie les facteurs les plus influents sur une variable cible""" |
| | influences = [] |
| |
|
| | |
| | variable_states = { |
| | 'Physical_Activity': ['sedentary', 'low', 'moderate', 'high'], |
| | 'BMI_Category': ['underweight_normal', 'overweight', 'obese_mild', 'obese_severe'], |
| | 'Smoking_Status': ['never', 'former', 'current'], |
| | 'Social_Support': ['poor', 'moderate', 'good'], |
| | 'Social_Engagement': ['low', 'moderate', 'high'] |
| | } |
| |
|
| | if self.inference_engine: |
| | for var in self.actionable_vars: |
| | if var in variable_states: |
| | states = variable_states[var] |
| | if len(states) >= 2: |
| | |
| | best_case = self.perform_inference_pgmpy( |
| | {var: states[-1]}, [target]) |
| | worst_case = self.perform_inference_pgmpy( |
| | {var: states[0]}, [target]) |
| |
|
| | if not best_case.empty and not worst_case.empty: |
| | best_prob = best_case[ |
| | best_case['State'] == 'autonomous']['Probability'].values |
| | worst_prob = worst_case[ |
| | worst_case['State'] == 'autonomous']['Probability'].values |
| |
|
| | if len(best_prob) > 0 and len(worst_prob) > 0: |
| | influence = abs(best_prob[0] - worst_prob[0]) |
| | influences.append((var, influence)) |
| |
|
| | |
| | influences.sort(key=lambda x: x[1], reverse=True) |
| | return influences[:n_top] |
| |
|
| | def generate_recommendations(self, patient_profile: Dict) -> List[Dict]: |
| | """Génère des recommandations personnalisées""" |
| | recommendations = [] |
| |
|
| | |
| | current_state = self.perform_inference_pgmpy( |
| | patient_profile, ['Global_Autonomy']) |
| |
|
| | if current_state.empty: |
| | return recommendations |
| |
|
| | current_autonomy_prob = current_state[ |
| | current_state['State'] == 'autonomous']['Probability'].values |
| |
|
| | if len(current_autonomy_prob) == 0: |
| | return recommendations |
| |
|
| | current_autonomy_prob = current_autonomy_prob[0] |
| |
|
| | |
| | best_states = { |
| | 'Physical_Activity': 'high', |
| | 'BMI_Category': 'underweight_normal', |
| | 'Smoking_Status': 'never', |
| | 'Social_Support': 'good', |
| | 'Social_Engagement': 'high' |
| | } |
| |
|
| | |
| | for var in self.actionable_vars: |
| | if var not in patient_profile and var in best_states: |
| | best_state = best_states[var] |
| | test_profile = patient_profile.copy() |
| | test_profile[var] = best_state |
| |
|
| | new_state = self.perform_inference_pgmpy( |
| | test_profile, ['Global_Autonomy']) |
| |
|
| | if not new_state.empty: |
| | new_autonomy_prob = new_state[ |
| | new_state['State'] == 'autonomous']['Probability'].values |
| |
|
| | if len(new_autonomy_prob) > 0: |
| | improvement = new_autonomy_prob[0] - current_autonomy_prob |
| |
|
| | if improvement > 0.01: |
| | |
| | rec_text = self._create_recommendation_text(var, best_state) |
| | recommendations.append({ |
| | 'variable': var, |
| | 'recommendation': rec_text, |
| | 'expected_improvement': improvement * 100, |
| | 'priority': 'high' if improvement > 0.1 else 'medium' |
| | }) |
| |
|
| | |
| | recommendations.sort(key=lambda x: x['expected_improvement'], reverse=True) |
| | return recommendations[:5] |
| |
|
| | def _create_recommendation_text(self, variable: str, state: str) -> str: |
| | """Crée un texte de recommandation personnalisé""" |
| | recommendations = { |
| | 'Physical_Activity': { |
| | 'high': "Pratiquer une activité physique intense (sport, course) au moins 150 min/semaine" |
| | }, |
| | 'BMI_Category': { |
| | 'underweight_normal': "Maintenir un poids corporel normal (IMC 18.5-24.9)" |
| | }, |
| | 'Smoking_Status': { |
| | 'never': "Éviter complètement le tabagisme ou arrêter de fumer" |
| | }, |
| | 'Social_Support': { |
| | 'good': "Développer un réseau de soutien social fort (famille, amis, communauté)" |
| | }, |
| | 'Social_Engagement': { |
| | 'high': "Participer activement à des activités sociales et communautaires" |
| | } |
| | } |
| |
|
| | if variable in recommendations and state in recommendations[variable]: |
| | return recommendations[variable][state] |
| | else: |
| | return f"Améliorer {variable} vers {state}" |
| |
|
| |
|
| | class BayesianNetworkCLI: |
| | """Interface en ligne de commande pour le réseau bayésien""" |
| |
|
| | def __init__(self): |
| | self.network = AutonomyBayesianNetwork() |
| |
|
| | def run(self): |
| | """Lance l'interface CLI""" |
| | print("\n" + "="*60) |
| | print("Interface Réseau Bayésien - Évaluation d'Autonomie") |
| | print("="*60) |
| |
|
| | while True: |
| | print("\nOptions disponibles:") |
| | print("1. Afficher la structure du réseau") |
| | print("2. Effectuer une inférence") |
| | print("3. Analyser une intervention") |
| | print("4. Identifier les facteurs influents") |
| | print("5. Générer des recommandations") |
| | print("6. Quitter") |
| |
|
| | choice = input("\nVotre choix (1-6): ") |
| |
|
| | if choice == '1': |
| | self.show_network_structure() |
| | elif choice == '2': |
| | self.perform_inference() |
| | elif choice == '3': |
| | self.analyze_intervention() |
| | elif choice == '4': |
| | self.identify_influential_factors() |
| | elif choice == '5': |
| | self.generate_recommendations() |
| | elif choice == '6': |
| | print("\nAu revoir!") |
| | break |
| | else: |
| | print("Choix invalide. Veuillez réessayer.") |
| |
|
| | def show_network_structure(self): |
| | """Affiche la structure du réseau""" |
| | structure = self.network.get_network_structure() |
| |
|
| | print("\n" + "-"*40) |
| | print("STRUCTURE DU RÉSEAU") |
| | print("-"*40) |
| |
|
| | print(f"\nNombre de noeuds: {len(structure['nodes'])}") |
| | print(f"Nombre d'arcs: {len(structure['edges'])}") |
| |
|
| | print("\nVariables par catégorie:") |
| | categories = {} |
| | for node in structure['nodes']: |
| | cat = node['category'] |
| | if cat not in categories: |
| | categories[cat] = [] |
| | categories[cat].append(node['name']) |
| |
|
| | for cat, vars in categories.items(): |
| | print(f"\n{cat.upper()}:") |
| | for var in vars: |
| | print(f" - {var}") |
| |
|
| | def perform_inference(self): |
| | """Effectue une inférence""" |
| | print("\n" + "-"*40) |
| | print("INFÉRENCE BAYÉSIENNE") |
| | print("-"*40) |
| |
|
| | evidence = {} |
| | print("\nEntrez l'évidence (laissez vide pour terminer):") |
| |
|
| | while True: |
| | var = input("Variable: ") |
| | if not var: |
| | break |
| | value = input(f"Valeur pour {var}: ") |
| | if value: |
| | evidence[var] = value |
| |
|
| | query_vars = input("\nVariables à inférer (séparées par virgule): ").split(',') |
| | query_vars = [v.strip() for v in query_vars if v.strip()] |
| |
|
| | if not query_vars: |
| | query_vars = ['Global_Autonomy'] |
| |
|
| | print(f"\nInférence avec évidence: {evidence}") |
| | print(f"Variables requêtées: {query_vars}") |
| |
|
| | result = self.network.perform_inference_pgmpy(evidence, query_vars) |
| |
|
| | if not result.empty: |
| | print("\nRésultats:") |
| | print(result.to_string(index=False)) |
| | else: |
| | print("\nAucun résultat disponible.") |
| |
|
| | def analyze_intervention(self): |
| | """Analyse une intervention""" |
| | print("\n" + "-"*40) |
| | print("ANALYSE D'INTERVENTION") |
| | print("-"*40) |
| |
|
| | intervention = {} |
| | print("\nDéfinir l'intervention:") |
| |
|
| | for var in self.network.actionable_vars: |
| | value = input(f"{var} (laissez vide pour ignorer): ") |
| | if value: |
| | intervention[var] = value |
| |
|
| | if not intervention: |
| | print("Aucune intervention définie.") |
| | return |
| |
|
| | print(f"\nAnalyse de l'intervention: {intervention}") |
| |
|
| | results = self.network.analyze_intervention(intervention) |
| |
|
| | if results['improvement']: |
| | print(f"\nAmélioration absolue: {results['improvement']['absolute']:.2%}") |
| | print(f"Amélioration relative: {results['improvement']['relative']:.1f}%") |
| |
|
| | if results['baseline'] is not None: |
| | print("\nÉtat de base:") |
| | print(results['baseline'][results['baseline']['Variable'] == 'Global_Autonomy'].to_string(index=False)) |
| |
|
| | if results['intervention'] is not None: |
| | print("\nAprès intervention:") |
| | print(results['intervention'][results['intervention']['Variable'] == 'Global_Autonomy'].to_string(index=False)) |
| |
|
| | def identify_influential_factors(self): |
| | """Identifie les facteurs les plus influents""" |
| | print("\n" + "-"*40) |
| | print("FACTEURS INFLUENTS") |
| | print("-"*40) |
| |
|
| | target = input("\nVariable cible (défaut: Global_Autonomy): ") or 'Global_Autonomy' |
| | n_top = int(input("Nombre de facteurs à afficher (défaut: 5): ") or 5) |
| |
|
| | factors = self.network.get_most_influential_factors(target, n_top) |
| |
|
| | if factors: |
| | print(f"\nTop {n_top} facteurs influençant {target}:") |
| | for i, (factor, influence) in enumerate(factors, 1): |
| | print(f"{i}. {factor}: {influence:.2%} d'influence") |
| | else: |
| | print("Aucun facteur influent trouvé.") |
| |
|
| | def generate_recommendations(self): |
| | """Génère des recommandations personnalisées""" |
| | print("\n" + "-"*40) |
| | print("RECOMMANDATIONS PERSONNALISÉES") |
| | print("-"*40) |
| |
|
| | profile = {} |
| | print("\nProfil du patient:") |
| |
|
| | |
| | age = input("Age (age_60_69/age_70_79/age_80_89/age_90_plus): ") |
| | if age: |
| | profile['Age'] = age |
| |
|
| | sex = input("Sexe (male/female): ") |
| | if sex: |
| | profile['Sex'] = sex |
| |
|
| | |
| | print("\nÉtat actuel (laissez vide si inconnu):") |
| | for var in ['Physical_Activity', 'BMI_Category', 'Smoking_Status']: |
| | value = input(f"{var}: ") |
| | if value: |
| | profile[var] = value |
| |
|
| | if not profile: |
| | print("Profil insuffisant pour générer des recommandations.") |
| | return |
| |
|
| | print(f"\nGénération de recommandations pour: {profile}") |
| |
|
| | recommendations = self.network.generate_recommendations(profile) |
| |
|
| | if recommendations: |
| | print("\nRecommandations prioritaires:") |
| | for i, rec in enumerate(recommendations, 1): |
| | print(f"\n{i}. {rec['recommendation']}") |
| | print(f" Amélioration attendue: +{rec['expected_improvement']:.1f}%") |
| | print(f" Priorité: {rec['priority']}") |
| | else: |
| | print("\nAucune recommandation significative identifiée.") |
| |
|
| |
|
| | def create_streamlit_app(): |
| | """Crée une application Streamlit pour l'interface web""" |
| | if not STREAMLIT_AVAILABLE: |
| | print("Streamlit n'est pas installé. Interface web non disponible.") |
| | return |
| |
|
| | st.set_page_config( |
| | page_title="Réseau Bayésien - Autonomie", |
| | page_icon="🧠", |
| | layout="wide" |
| | ) |
| |
|
| | st.title("🧠 Réseau Bayésien pour l'Évaluation d'Autonomie") |
| | st.markdown("---") |
| |
|
| | |
| | if 'network' not in st.session_state: |
| | st.session_state.network = AutonomyBayesianNetwork() |
| |
|
| | network = st.session_state.network |
| |
|
| | |
| | st.sidebar.title("Navigation") |
| | page = st.sidebar.selectbox( |
| | "Choisir une page", |
| | ["Structure du Réseau", "Inférence", "Analyse d'Intervention", |
| | "Facteurs Influents", "Recommandations"] |
| | ) |
| |
|
| | if page == "Structure du Réseau": |
| | st.header("📊 Structure du Réseau Bayésien") |
| |
|
| | structure = network.get_network_structure() |
| |
|
| | col1, col2, col3 = st.columns(3) |
| |
|
| | with col1: |
| | st.metric("Nombre de noeuds", len(structure['nodes'])) |
| | with col2: |
| | st.metric("Nombre d'arcs", len(structure['edges'])) |
| | with col3: |
| | st.metric("Variables actionnables", len(network.actionable_vars)) |
| |
|
| | |
| | st.subheader("Variables par catégorie") |
| |
|
| | categories = {} |
| | for node in structure['nodes']: |
| | cat = node['category'] |
| | if cat not in categories: |
| | categories[cat] = [] |
| | categories[cat].append(node['name']) |
| |
|
| | for cat in ['non_actionable', 'actionable', 'intermediate', 'outcome']: |
| | if cat in categories: |
| | with st.expander(f"{cat.replace('_', ' ').title()} ({len(categories[cat])} variables)"): |
| | for var in categories[cat]: |
| | st.write(f"• {var}") |
| |
|
| | elif page == "Inférence": |
| | st.header("🔍 Inférence Bayésienne") |
| |
|
| | col1, col2 = st.columns(2) |
| |
|
| | with col1: |
| | st.subheader("Évidence") |
| | evidence = {} |
| |
|
| | |
| | age = st.selectbox("Age", |
| | ["", "age_60_69", "age_70_79", "age_80_89", "age_90_plus"]) |
| | if age: |
| | evidence['Age'] = age |
| |
|
| | sex = st.selectbox("Sexe", ["", "male", "female"]) |
| | if sex: |
| | evidence['Sex'] = sex |
| |
|
| | |
| | activity = st.selectbox("Activité Physique", |
| | ["", "sedentary", "low", "moderate", "high"]) |
| | if activity: |
| | evidence['Physical_Activity'] = activity |
| |
|
| | bmi = st.selectbox("Catégorie IMC", |
| | ["", "underweight", "normal", "overweight", |
| | "obese_class1", "obese_class2"]) |
| | if bmi: |
| | evidence['BMI_Category'] = bmi |
| |
|
| | with col2: |
| | st.subheader("Variables à inférer") |
| | query_vars = st.multiselect( |
| | "Sélectionner les variables", |
| | network.outcome_vars + network.intermediate_vars, |
| | default=['Global_Autonomy'] |
| | ) |
| |
|
| | if st.button("Effectuer l'inférence"): |
| | if query_vars: |
| | result = network.perform_inference_pgmpy(evidence, query_vars) |
| |
|
| | if not result.empty: |
| | st.subheader("Résultats") |
| |
|
| | for var in query_vars: |
| | var_data = result[result['Variable'] == var] |
| | if not var_data.empty: |
| | fig = px.bar(var_data, x='State', y='Probability', |
| | title=f"Distribution de probabilité pour {var}") |
| | st.plotly_chart(fig) |
| | else: |
| | st.error("Aucun résultat disponible") |
| |
|
| | elif page == "Analyse d'Intervention": |
| | st.header("💊 Analyse d'Intervention") |
| |
|
| | st.subheader("Définir l'intervention") |
| |
|
| | intervention = {} |
| |
|
| | col1, col2 = st.columns(2) |
| |
|
| | with col1: |
| | for var in network.actionable_vars[:4]: |
| | value = st.selectbox(f"{var}", ["Non modifié"] + |
| | ["Option 1", "Option 2", "Option 3"]) |
| | if value != "Non modifié": |
| | intervention[var] = value |
| |
|
| | with col2: |
| | for var in network.actionable_vars[4:]: |
| | value = st.selectbox(f"{var}", ["Non modifié"] + |
| | ["Option 1", "Option 2", "Option 3"]) |
| | if value != "Non modifié": |
| | intervention[var] = value |
| |
|
| | if st.button("Analyser l'intervention"): |
| | if intervention: |
| | results = network.analyze_intervention(intervention) |
| |
|
| | if results['improvement']: |
| | col1, col2 = st.columns(2) |
| | with col1: |
| | st.metric("Amélioration absolue", |
| | f"{results['improvement']['absolute']:.2%}") |
| | with col2: |
| | st.metric("Amélioration relative", |
| | f"{results['improvement']['relative']:.1f}%") |
| |
|
| | |
| | if results['baseline'] is not None and results['intervention'] is not None: |
| | baseline_data = results['baseline'][ |
| | results['baseline']['Variable'] == 'Global_Autonomy'] |
| | intervention_data = results['intervention'][ |
| | results['intervention']['Variable'] == 'Global_Autonomy'] |
| |
|
| | comparison = pd.DataFrame({ |
| | 'State': baseline_data['State'].values, |
| | 'Baseline': baseline_data['Probability'].values, |
| | 'Intervention': intervention_data['Probability'].values |
| | }) |
| |
|
| | fig = go.Figure() |
| | fig.add_trace(go.Bar(name='Baseline', x=comparison['State'], |
| | y=comparison['Baseline'])) |
| | fig.add_trace(go.Bar(name='Intervention', x=comparison['State'], |
| | y=comparison['Intervention'])) |
| | fig.update_layout(title="Comparaison Baseline vs Intervention", |
| | barmode='group') |
| | st.plotly_chart(fig) |
| |
|
| | elif page == "Facteurs Influents": |
| | st.header("📈 Facteurs les Plus Influents") |
| |
|
| | target = st.selectbox("Variable cible", |
| | network.outcome_vars, |
| | index=network.outcome_vars.index('Global_Autonomy')) |
| |
|
| | n_top = st.slider("Nombre de facteurs", 3, 10, 5) |
| |
|
| | if st.button("Identifier les facteurs"): |
| | factors = network.get_most_influential_factors(target, n_top) |
| |
|
| | if factors: |
| | |
| | df_factors = pd.DataFrame(factors, columns=['Facteur', 'Influence']) |
| | df_factors['Influence'] = df_factors['Influence'] * 100 |
| |
|
| | fig = px.bar(df_factors, x='Influence', y='Facteur', |
| | orientation='h', |
| | title=f"Top {n_top} facteurs influençant {target}", |
| | labels={'Influence': 'Influence (%)'}) |
| | st.plotly_chart(fig) |
| |
|
| | |
| | st.subheader("Détails") |
| | for i, (factor, influence) in enumerate(factors, 1): |
| | st.write(f"{i}. **{factor}**: {influence:.2%} d'influence") |
| |
|
| | elif page == "Recommandations": |
| | st.header("📋 Recommandations Personnalisées") |
| |
|
| | st.subheader("Profil du Patient") |
| |
|
| | profile = {} |
| |
|
| | col1, col2 = st.columns(2) |
| |
|
| | with col1: |
| | age = st.selectbox("Age", |
| | ["age_60_69", "age_70_79", "age_80_89", "age_90_plus"]) |
| | profile['Age'] = age |
| |
|
| | sex = st.selectbox("Sexe", ["male", "female"]) |
| | profile['Sex'] = sex |
| |
|
| | activity = st.selectbox("Activité Physique actuelle", |
| | ["sedentary", "low", "moderate", "high"]) |
| | profile['Physical_Activity'] = activity |
| |
|
| | with col2: |
| | bmi = st.selectbox("Catégorie IMC actuelle", |
| | ["underweight", "normal", "overweight", |
| | "obese_class1", "obese_class2"]) |
| | profile['BMI_Category'] = bmi |
| |
|
| | smoking = st.selectbox("Statut tabagique", |
| | ["never", "former", "current"]) |
| | profile['Smoking_Status'] = smoking |
| |
|
| | if st.button("Générer les recommandations"): |
| | with st.spinner("Analyse en cours..."): |
| | recommendations = network.generate_recommendations(profile) |
| |
|
| | if recommendations: |
| | st.success("Recommandations générées avec succès!") |
| |
|
| | for i, rec in enumerate(recommendations, 1): |
| | priority_color = { |
| | 'high': '🔴', |
| | 'medium': '🟡', |
| | 'low': '🟢' |
| | }.get(rec['priority'], '⚪') |
| |
|
| | with st.container(): |
| | col1, col2 = st.columns([3, 1]) |
| | with col1: |
| | st.write(f"{priority_color} **{rec['recommendation']}**") |
| | with col2: |
| | st.metric("Amélioration", |
| | f"+{rec['expected_improvement']:.1f}%") |
| | else: |
| | st.info("Aucune recommandation significative identifiée.") |
| |
|
| |
|
| | def main(): |
| | """Fonction principale""" |
| | if len(sys.argv) > 1 and sys.argv[1] == 'web': |
| | |
| | if STREAMLIT_AVAILABLE: |
| | create_streamlit_app() |
| | else: |
| | print("Streamlit n'est pas installé. Installez-le avec: pip install streamlit") |
| | print("Lancement de l'interface CLI à la place...") |
| | cli = BayesianNetworkCLI() |
| | cli.run() |
| | else: |
| | |
| | cli = BayesianNetworkCLI() |
| | cli.run() |
| |
|
| |
|
| | if __name__ == "__main__": |
| | main() |