Bayesian Networks
Advanced Statistical Methods
Reasoning Under Uncertainty With Graphical Models
Bayesian networks compactly represent joint probability distributions using directed acyclic graphs, encoding conditional independencies that enable efficient inference. D-separation provides the graphical criterion for independence.
- Medical diagnosis β Combine symptom observations to infer disease probabilities
- Risk assessment β Model cascading failures in complex engineering systems
- Fraud detection β Combine transaction patterns to flag suspicious activities with explainable reasoning
Bayesian networks turn complex dependency structures into tractable probabilistic reasoning.
D-Separation and Conditional Independence
Parameter Estimation
Structure Learning
Inference in Bayesian Networks
import numpy as np
from itertools import product
class BayesianNetwork:
def __init__(self, n_vars, card, parents):
self.n = n_vars
self.card = card
self.parents = parents
self.cpd = [None] * n_vars
def randomεε§ε(self, seed=42):
rng = np.random.RandomState(seed)
for i in range(self.n):
parent_card = np.prod([self.card[p] for p in self.parents[i]]) if self.parents[i] else 1
self.cpd[i] = rng.dirichlet(np.ones(self.card[i]), size=parent_card)
def sample(self, n_samples=1, rng=None):
if rng is None:
rng = np.random.RandomState()
data = np.zeros((n_samples, self.n), dtype=int)
for i in range(self.n):
if not self.parents[i]:
data[:, i] = rng.choice(self.card[i], size=n_samples, p=self.cpd[i])
else:
for idx in range(n_samples):
parent_config = tuple(data[idx, p] for p in self.parents[i])
flat_idx = np.ravel_multi_index(parent_config, [self.card[p] for p in self.parents[i]])
data[idx, i] = rng.choice(self.card[i], p=self.cpd[i][flat_idx])
return data
def log_likelihood(self, data):
ll = 0.0
for i in range(self.n):
for row in data:
if self.parents[i]:
parent_config = tuple(row[p] for p in self.parents[i])
flat_idx = np.ravel_multi_index(parent_config, [self.card[p] for p in self.parents[i]])
else:
flat_idx = 0
ll += np.log(self.cpd[i][flat_idx, row[i]] + 1e-10)
return ll
def variable_elimination(self, evidence, query):
factors = [self.cpd[i].copy() for i in range(self.n)]
observed = set(evidence.keys())
hidden = [i for i in range(self.n) if i not in observed and i not in query]
for var in hidden:
product_factor = np.ones([self.card[v] if v in [var] + self.parents[v] else 1
for v in range(self.n)])
# Simplified VE: sum out variable
factors = [f for f in factors] # placeholder
return factors