Machine Learning in Clojure with libpython‑clj: Using Bayesian Networks for Smarter, Interpretable AI [Series 2] - Flexiana
avatar

Jiri Knesl

Posted on 11th December 2025

Machine Learning in Clojure with libpython‑clj: Using Bayesian Networks for Smarter, Interpretable AI [Series 2]

news-paper News |

This is the second part of our Machine Learning in Clojure with libpython‑clj series. If you missed Series 1, we covered how Clojure can use Python’s ML libraries through libpython‑clj. In this article, we focus on Bayesian Networks. We will show how to train them, run queries against them, and use them in Clojure.

Machine learning is not only for Python. With libpython‑clj, Clojure teams can use PyMC, scikit‑learn, and pgmpy. They can keep the JVM and the functional style they prefer. The aim is simple: make ML in Clojure clear, practical, and ready for production.

Bayesian Networks are good when you need clarity. They model uncertainty. They use domain knowledge. And they answer “what if?” questions without guesswork.

➤ Small to medium datasets.

➤ Compliance‑heavy work in healthcare, finance, and logistics.

➤ When explainability is required.

This walkthrough demonstrates how to build a simple BN in Python. Then run it from Clojure using libpython‑clj. The process is straightforward.

Flexiana is a Clojure consultancy. We help teams connect Clojure and ML in real projects. We share code, write about patterns, and ship systems that are easy to reason about. If you need support with interop, pipelines, or interpretable models, we are a solid partner.

“Bayesian reasoning helps teams make better calls in logistics, healthcare, and fintech. With Clojure’s REPL and Python’s ML tools, you move faster and stay confident.” – Flexiana ML Team

A Bayesian Network is a directed acyclic graph. Each node is a random variable. Each edge shows how one variable depends on another. The graph encodes conditional probabilities describing how events influence one another.

Bayesian Networks are not just about guessing what will happen next. They show why something is likely or not, based on how the graph’s parts connect. When you are dealing with uncertainty, these networks give you both a prediction and a peek behind the curtain.

Neural Networks (NNs) really stand out for image recognition, speech, and other messy, unstructured data. They work best with huge datasets and find hidden patterns.

Bayesian Networks fit different needs:

➤ When datasets are smaller, but domain knowledge is strong

➤ When decisions must be explained to stakeholders

➤ When uncertainty needs to be modelled clearly

With all these considered, Neural Networks find hidden patterns. Bayesian Networks help with clarity, reasoning, and trust. 

You can actually see how Bayesian Networks think. Every variable and every link is there in the graph. If something happens, you can trace the entire path back and explain it. That is a big deal in sectors like healthcare and finance, where you must explain to regulators or your team exactly why a decision was made. With Neural Networks, they usually keep that logic hidden, which just isn’t good enough when you need transparency.

Bayesian Networks handle uncertainty directly. They do not just return one answer but give you probabilities, so you know what might happen and what’s not, and how sure the model is. That helps when your data is messy or incomplete. Neural Networks, on the other hand, typically select a single outcome, which can be misleading when the situation is unclear.  

Bayesian Networks can include domain knowledge. You can turn relationships and rules from the real world into edges and probability tables. This keeps the model grounded, especially when you do not have a ton of data. Neural Networks, on the other hand, require large datasets to learn patterns and are not well-suited to encoding expert rules.

PyMC Labs recently pointed out that “Bayesian modelling is really shaping business decisions these days. Probabilistic forecasting models are proliferating across retail, finance, energy, and beyond. Businesses are increasingly adopting these approaches.

Flexiana focuses on interpretable ML for compliance‑heavy work. Our projects lean on clear reasoning and stable interoperability. Pairing Clojure’s functional style with BN reasoning helps teams build systems that are practical and explainable.

“What if?” analysis: If a shipment is delayed, what is the churn risk? BNs model scenarios and return clear probabilities.

Small or medium datasets: Expert knowledge– Encode known relationships directly. Useful when data is limited.

Compliance‑heavy industries: Interpretable reasoning– Show why an outcome is likely. Fits healthcare, finance, and logistics.

Flexiana case mentioned: Decision support– Flexiana has used BNs for logistics and healthcare clients. The focus is on clear reasoning and compliance‑friendly workflows.

High‑dimensional inputs: Images and audio involve thousands of features. BNs struggle at this scale.

Unstructured data: Text, images, and raw audio need feature extraction. Deep learning handles this better.

Arbitrary function approximation: Neural Networks capture complex, nonlinear patterns. BNs are built for probabilistic reasoning, not every function shape. 

Here’s a basic example with pgmpy, a Python library. It builds a small Bayesian Network with two nodes and one dependency.


What this does:

➤ Builds a BN with two variables: Rain and Traffic.

➤ Shows that rain raises the chance of traffic

➤ Checks that the model and probabilities are valid

For more details, check the official documentation:

pgmpy Documentation

PyMC Documentation

Train in Python: Build and check the BN with pgmpy or PyMC.

Load via libpython‑clj:  Import the Python model into Clojure.

Wrap inference in Clojure:  Write small functions for queries and “what if?” checks.

Clojure code snippet

Enterprise JVM focus: Flexiana’s tutorials show how to bridge Python ML with Clojure in enterprise JVM stacks. The focus is clear interop, stable deployment, and explainable models.

Utility functions for boxed math: Avoid unnecessary boxing. Use primitives where possible and keep Python calls lean.

Batch calls for efficiency: Run queries in groups to cut overhead.

Caching strategies: Cache fixed CPDs and reuse common results. Memoize repeated “what if?” checks.

Bayesian networks are great for running “what if?” modeling in logistics. If a shipment is delayed, these models help you assess the risk of supplier bottlenecks, missed deliveries, or customer loss. Managers do not have to guess; they receive precise numbers and can plan accordingly.

Use case: You can map out how a delay might lead to customer churn, or spot risks up and down the supply chain.

Output: You can hand these probabilities to your ops or finance teams and actually explain what’s behind them.

Value: You get more innovative backup plans and fewer surprises.

BNs connect symptoms, test results, and conditions, showing how each piece of information changes the probabilities of a diagnosis. The reasoning is not hidden- clinicians can see not just what the model predicts, but how sure it is.

Use case: If you plug in a set of symptoms, you get a clear picture of which conditions are most likely. 

Output: The logic stays out in the open, so anyone reviewing the case can follow every step. 

Value: This kind of transparency is good when you need to explain decisions or meet strict compliance rules.

BNs do not just spot fraud- they break down what made a transaction suspicious in the first place. You get to see exactly which factors raised the red flag, not just a vague alert. That kind of clarity makes audits and regulator checks way smoother.

Use case: They scan transaction patterns and highlight the risky ones.

Output: Real reasons for every alert, not just a score.

Value: You end up with detection you can actually trust and clearer investigations.

Faster orchestration and deployment: For starters, you can move fast. The REPL lets you test ideas and make changes quickly, so updates are faster without waiting around for long builds.

Seamless JVM integration: Clojure integrates nicely with the JVM. You can plug ML models right into your current systems. No need for extra layers or awkward workarounds.

Lower barrier for Clojure teams:  if your team already knows Clojure, you do not have to rebuild your stack or retrain everyone to bring machine learning into the picture. You can use the tools you know while still taking advantage of ML.

➤ Structure: A clear DAG with three variables; Cancer has two parents.

➤ Nodes: Random variables with named states.

➤ Edges: Smoking and Pollution feed into Cancer.

➤ CPDs: Tables capture prior knowledge and uncertainty.

➤ Inference: Use variable elimination for “what if?” queries.

This example uses libpython‑clj to import pgmpy, set up the network, and run queries in Clojure.

Interop flow:

➤ Build: Mirror the Python BN and CPDs with libpython‑clj.

➤ Infer: Call pgmpy’s VariableElimination from Clojure.

➤ Return: Get Python objects, then print or convert to Clojure data.

Label conversion: Map states to values, e.g., {“no” 0.90, “yes” 0.10}.

Engagement tip: Log queries and results to show stakeholders how each node shapes outcomes.

Not at all. Neural Networks learn patterns from tons of data, while Bayesian Networks focus on cause and effect, mapping out probabilities and showing you how they conclude.

Honestly, they are not built for that. Bayesian Networks are helpful for small or medium datasets, especially when you need expert input. If you have large, unstructured datasets, deep learning usually performs better.

Clojure runs on the JVM, so it integrates well with enterprise environments. Plus, if you need something from Python, you can call those libraries- no need to pick one or the other.

It makes things easy. Clojure can import Python ML libraries directly- train your model in Python, then query it from Clojure. No need to build complicated bridges between the two.

Healthcare, finance, and logistics rely on Bayesian models. They want explainable results, clear probabilities, and the ability to test out “what if?” scenarios quickly.

Machine learning in Clojure is practical for real teams. With libpython‑clj, you can use Python’s ML libraries while staying in the JVM stack you already trust. That means faster iteration, smoother deployment, and less friction for Clojure developers.

Bayesian Networks add clear value. They do not just predict; they show the reasoning. This matters in healthcare, finance, and logistics, where decisions carry weight. BNs handle uncertainty and map cause‑and‑effect, so managers and auditors can see why a result makes sense.

If your team is exploring ML in Clojure, now is a good time to try it. Share your thoughts, compare notes, and check the sample code in our GitHub repo. 

If you want help, Flexiana’s consulting team can guide design, deployment, and integration so it fits your stack.

That wraps up Series 2 and our exploration of Bayesian Networks in Clojure with libpython-clj.

In Series 3, we unlock causal insights using Microsoft’s EconML to go beyond prediction and start understanding why things happen.
👉 Continue with Series 3: https://flexiana.com/news/2025/12/machine-learning-in-clojure-with-libpython-clj-unlocking-causal-insights-using-microsofts-econml-series-3