Building a Bayesian Diagnosis Assistant in 1 Hour

How doctors, probabilities, and code come together to make smarter diagnoses
Introduction
What if we could reason like a doctor — but with math?
In this post, I’ll walk you through how I built a Bayesian Inference-based Diagnosis Assistant in just one hour. This system updates its beliefs as new symptoms are observed — exactly how expert clinicians refine their diagnoses.
We'll cover:
🤔 Intuition behind Bayesian updates
🧮 Coding the inference engine
📉 Visualizing belief & uncertainty
🧰 Wrapping it into a reusable diagnostic tool
🌐 Deploying as a Streamlit app
Let’s dive in.
1. The Problem: Diagnosing from Symptoms
Imagine a patient walks in with a fever. You suspect flu, but could it also be pneumonia?
Every time the patient tells you more (e.g., “I also have chest pain”), you update your beliefs. That’s the essence of Bayesian inference: combining prior beliefs with new evidence.
2. Bayesian Inference: The Core Idea
Here’s Bayes' Theorem in plain terms:
$$P(Disease∣Symptom)= P(Symptom) P(Symptom∣Disease)⋅P(Disease) $$
We apply this repeatedly as new symptoms come in — a process called sequential inference.
3. Data Setup
We simulate a mini knowledge base with priors and likelihoods.
priors = {
"Flu": 0.10,
"Pneumonia": 0.05,
"Cold": 0.15
}
likelihoods = {
"Fever": {"Flu": 0.9, "Pneumonia": 0.85, "Cold": 0.2},
"Cough": {"Flu": 0.8, "Pneumonia": 0.7, "Cold": 0.9},
"Chest Pain": {"Flu": 0.1, "Pneumonia": 0.6, "Cold": 0.05}
}
4. Writing the Inference Engine
We start with a function that updates beliefs for one symptom:
def bayesian_update(priors, likelihoods, symptom):
unnormalized = {
d: priors[d] * likelihoods[symptom][d] for d in priors
}
evidence = sum(unnormalized.values())
return {d: p / evidence for d, p in unnormalized.items()}
Then we handle multiple symptoms sequentially:
def sequential_bayes(priors, likelihoods, symptoms):
for symptom in symptoms:
priors = bayesian_update(priors, likelihoods, symptom)
return priors
5. Visualizing the Beliefs
def plot_posteriors(posteriors, title="Diagnosis"):
sns.barplot(x=list(posteriors.keys()), y=list(posteriors.values()))
plt.title(title)
plt.ylim(0, 1)
plt.show()
This shows how certainty shifts as new symptoms are observed.
6. Measuring Uncertainty with Entropy
Entropy helps us measure how confident our model is.
def compute_entropy(posteriors):
return -sum(p * np.log2(p) for p in posteriors.values() if p > 0)
High entropy → unsure
Low entropy → confident
We track entropy as we get more evidence.
7. Packaging into a Diagnosis Tool
To make this reusable, we wrapped the whole logic:
def diagnose(symptoms, priors, likelihoods):
posteriors = sequential_bayes(priors, likelihoods, symptoms)
entropy = compute_entropy(posteriors)
return posteriors, entropy
You can now call diagnose(["Fever", "Chest Pain"])
and get both the disease probabilities and how confident the system is.
8. Deploying with Streamlit
We built a simple web UI using Streamlit:
import streamlit as st
symptoms = st.multiselect("Select symptoms", list(likelihoods.keys()))
if symptoms:
posteriors, entropy = diagnose(symptoms, priors, likelihoods)
st.write(posteriors)
st.write(f"Entropy: {entropy:.2f} bits")
Run with:
streamlit run app.py
Final Thoughts
In just an hour, we:
Built a reasoning engine using Bayesian inference
Visualized how belief evolves with evidence
Quantified uncertainty
Wrapped it into a reusable tool
Deployed it as an interactive app
This is more than just a toy project — it's a microcosm of how real diagnostic systems work. And the best part? It's fully interpretable.
Subscribe to my newsletter
Read articles from Sudhin Karki directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Sudhin Karki
Sudhin Karki
I am a Machine Learning enthusiast with a motivation of building ML integrated apps. I am currently exploring the groundbreaking ML / DL papers and trying to understand how this is shaping the future.