Bayes / app.py
Eric2mangel's picture
Update app.py
96f6798 verified
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...")