Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| # CSS inchangé | |
| st.markdown(""" | |
| <style> | |
| .block-container {padding-top: 1.2rem; padding-bottom: 1rem;} | |
| h1, h2, h3 {margin: 0.4rem 0;} | |
| .stExpander {margin-bottom: 0.6rem;} | |
| div.row-widget.stHorizontal {gap: 0.6rem;} | |
| .stNumberInput > div > div > input {text-align: center;} | |
| section.main > div {padding: 1rem 1.2rem;} | |
| </style> | |
| """, unsafe_allow_html=True) | |
| st.set_page_config(page_title="Bayes – Calcul rapide", layout="wide") | |
| st.title("🧠 Bayes – Calcul interactif") | |
| st.caption("P(A|B) = [P(B|A) × P(A)] / P(B)") | |
| with st.expander("Rappel formule", expanded=False): | |
| st.markdown("P(B) = P(B|A)×P(A) + P(B|¬A)×P(¬A)") | |
| # ─── Mode + select ──────────────────────────────────────────────────────── | |
| col_mode, col_ex = st.columns([40, 60]) | |
| with col_mode: | |
| mode_ds = st.toggle("Mode Data Science (Recall/Precision)", value=False) | |
| if mode_ds: | |
| lbl = { | |
| "prev": "Prévalence (Classe +)", | |
| "recall": "Recall (Sensibilité)", | |
| "spe": "Spécificité (TNR)", | |
| "post": "Précision (VPP)", | |
| } | |
| else: | |
| lbl = { | |
| "prev": "Prior P(A)", | |
| "recall": "Sensibilité P(+|A)", | |
| "spe": "Spécificité P(-|¬A)", | |
| "post": "Postérieur P(A|+)", | |
| } | |
| with col_ex: | |
| exemples = [ | |
| "Manuel", | |
| "Cancer dépistage ~0.8%", | |
| "Fraude CB ~0.1%", | |
| "Grossesse ~4–5%", | |
| "ADN culpabilité ~0.001%" | |
| ] | |
| choix = st.selectbox("Exemple", exemples, index=0, key="exemple_select") | |
| # Détection changement + suffix pour clés dynamiques | |
| if "prev_choix" not in st.session_state: | |
| st.session_state.prev_choix = "INIT" | |
| exemple_changed = choix != st.session_state.prev_choix | |
| key_suffix = f"_{choix.replace(' ', '_')}" if exemple_changed else "" | |
| # Mise à jour | |
| st.session_state.prev_choix = choix | |
| # Defaults | |
| defaults = { | |
| "Cancer dépistage ~0.8%": (0.8, 85.0, 92.0), | |
| "Fraude CB ~0.1%": (0.1, 92.0, 99.85), | |
| "Grossesse ~4–5%": (4.5, 99.0, 99.5), | |
| "ADN culpabilité ~0.001%": (0.001, 99.9, 99.99), | |
| }.get(choix, (5.0, 90.0, 95.0)) | |
| # ─── Inputs avec clés dynamiques quand changement ───────────────────────── | |
| c1, c2, c3, c4 = st.columns(4, gap="small") | |
| with c1: | |
| st.caption(f"{lbl['prev']} (%)") | |
| prev = st.number_input( | |
| label = lbl['prev'], | |
| min_value = 0.0, | |
| max_value = 100.0, | |
| value = float(defaults[0]), | |
| step = 0.01, | |
| key = f"prev{key_suffix}", | |
| label_visibility = "collapsed" | |
| ) | |
| with c2: | |
| st.caption(f"{lbl['recall']} (%)") | |
| recall = st.number_input( | |
| label = lbl['recall'], | |
| min_value = 0.0, | |
| max_value = 100.0, | |
| value = float(defaults[1]), | |
| step = 0.1, | |
| key = f"rec{key_suffix}", | |
| label_visibility = "collapsed" | |
| ) | |
| with c3: | |
| st.caption(f"{lbl['spe']} (%)") | |
| speci = st.number_input( | |
| label = lbl['spe'], | |
| min_value = 0.0, | |
| max_value = 100.0, | |
| value = float(defaults[2]), | |
| step = 0.1, | |
| key = f"spe{key_suffix}", | |
| label_visibility = "collapsed" | |
| ) | |
| with c4: | |
| st.caption(f"{lbl['post']} (%)") | |
| post = st.number_input( | |
| label = lbl['post'], | |
| min_value = 0.0, | |
| max_value = 100.0, | |
| value = 50.0, | |
| step = 0.1, | |
| key = f"post{key_suffix}", | |
| label_visibility = "collapsed" | |
| ) | |
| # ─── Checkboxes (inchangées, mais on peut les reset si tu veux) ─────────── | |
| st.write("") | |
| st.subheader("Calculer :", divider=False) | |
| cols = st.columns(4, gap="small") | |
| calc_prev = cols[0].checkbox(lbl["prev"], key="c_prev") | |
| calc_recall = cols[1].checkbox(lbl["recall"], key="c_rec") | |
| calc_speci = cols[2].checkbox(lbl["spe"], key="c_spe") | |
| calc_post = cols[3].checkbox(lbl["post"], value=True, key="c_post") | |
| # Bouton Calculer (inchangé) | |
| if st.button("Calculer", type="primary", use_container_width=True): | |
| p = prev / 100 | |
| se = recall / 100 | |
| sp = speci / 100 | |
| po = post / 100 | |
| checked = sum([calc_prev, calc_recall, calc_speci, calc_post]) | |
| if checked != 1: | |
| st.error("Cocher **exactement une** grandeur à calculer") | |
| else: | |
| try: | |
| res = None | |
| label = "" | |
| if calc_post: | |
| res = (se * p) / (se * p + (1 - sp) * (1 - p)) | |
| label = lbl["post"] | |
| elif calc_prev: | |
| res = (po * (1 - sp)) / (se - po * (se - (1 - sp))) | |
| label = lbl["prev"] | |
| elif calc_recall: | |
| res = (po * (1 - sp) * (1 - p)) / (p * (1 - po)) | |
| label = lbl["recall"] | |
| elif calc_speci: | |
| res = 1 - (se * p * (1 - po)) / (po * (1 - p)) | |
| label = lbl["spe"] | |
| res_pct = res * 100 | |
| if 0 <= res <= 1: | |
| st.success(f"**{label} = {res_pct:,.3f} %**") | |
| else: | |
| st.warning(f"Résultat : {res_pct:,.2f} % → paramètres incohérents") | |
| except ZeroDivisionError: | |
| st.error("Division par zéro – vérifiez les valeurs extrêmes") | |
| except Exception as e: | |
| st.error(f"Erreur : {str(e)}") | |
| # Sources et astuce (inchangés) | |
| with st.expander("Sources et références des exemples", expanded=False): | |
| st.markdown("... ton contenu ...") | |
| with st.expander("Astuce rapide", expanded=False): | |
| st.caption("Plus la prévalence est faible → plus la précision chute...") |