In critical applications like healthcare, knowing the probability isn’t enough. Knowing how confident we are in that probability makes all the difference.
🔍 The Problem
Diabetes prediction models abound, but they often give us just a number. Traditional classifiers like logistic regression or random forests will tell you, for instance, that there’s a 73% chance someone has diabetes.
But what if we asked:
“How sure are we about that 73%?”
Enter Bayesian Neural Networks (bnns), where uncertainty isn’t a bug—it’s a feature.
📊 The Data
We used the PimaIndiansDiabetes2 dataset from the mlbench package, containing clinical variables (e.g., glucose, BMI, insulin) and diabetes diagnosis. Missing values were removed, and outcomes were converted to binary.
library(bnns)
library(mlbench)
library(rsample)
library(ggplot2)
set.seed(123)
data("PimaIndiansDiabetes2")
trial_data <- PimaIndiansDiabetes2 |>
transform(diabetes = ifelse(diabetes == "pos", 1, 0)) |>
na.omit()
trial_data_split <- initial_split(trial_data, strata = diabetes, prop = 0.8)
trial_data_train <- training(trial_data_split)
trial_data_test <- testing(trial_data_split)
🧠 The Model
Our BNN has two hidden layers (24 and 12 nodes) and uses Cauchy priors to encourage sparsity. We used logistic output activation (out_act_fn = 2) for binary classification.
bnn_model <- bnns(
diabetes ~ .,
data = trial_data_train,
L = 2,
nodes = c(24, 12),
act_fn = c(4, 1),
out_act_fn = 2,
iter = 0.1e4,
warmup = 0.05e4,
chains = 4,
cores = 4,
prior_weights = list(dist = "cauchy", params = list(mu = 0, sigma = 0.3)),
prior_bias = list(dist = "cauchy", params = list(mu = 0, sigma = 0.3))
)
🎯 The Prediction
We predicted probabilities on the test set and extracted the posterior median and 95% credible intervals.
pred <- predict(bnn_model, newdata = trial_data_test)
pred_y <- apply(pred, MARGIN = 1, median)
pred_quantiles <- apply(pred, 1, function(x) quantile(x, probs = c(0.025, 0.975)), simplify = FALSE) |>
do.call(rbind, args = _)
📏 Model Performance
measure_bin(trial_data_test$diabetes, pred)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
$conf_mat
pred_label
obs 0 1
0 42 11
1 7 19
$accuracy
[1] 0.7721519
$ROC
Call:
roc.default(response = obs, predictor = pred)
Data: pred in 53 controls (obs 0) < 26 cases (obs 1).
Area under the curve: 0.8353
$AUC
[1] 0.8352685
Performance was comparable to classical methods (AUC ~0.835), but with a massive advantage: uncertainty quantification.
🔬 Visualizing Predictions
plot_data <- data.frame(
Actual = trial_data_test$diabetes,
Predicted = pred_y,
Lower = pred_quantiles[,1],
Upper = pred_quantiles[,2]
) |>
transform(width = Upper - Lower) |>
dplyr::arrange(width)
ggplot(plot_data, aes(x = Actual, y = Predicted)) +
geom_point(size = 2) +
geom_errorbar(aes(ymin = Lower, ymax = Upper), width = 0.05, color = "steelblue") +
labs(
title = "BNN Predictions for Patient Status",
subtitle = "Error bars show 95% credible intervals",
x = "Test Set Patient Status",
y = "Predicted Patient Status"
) +
theme_minimal()

🧠 Why Use bnns?
- Non-linear modeling: Captures complex relationships among covariates without heavy pre-specification.
- Credible intervals: Each prediction comes with its uncertainty.
- Probability of a probability:
- For example: Pr(Pr(Diabetes) > 0.5) > 0.9
- Translation: “We are 90% confident this person has more than 50% risk.”
- That’s clinical-grade insight.
📣 Final Thoughts
Bayesian Neural Networks let us move beyond binary thinking and embrace informed uncertainty. When the stakes are high (think medicine, finance, or policy), bnns offers a probabilistic flashlight in the black box jungle.
Ready to stop guessing your predictions? Start modeling your belief about your predictions.
💬 Like this blog? Share your thoughts and use-cases on LinkedIn and tag me!