📖 Teoría

Redes Bayesianas

De los fundamentos de probabilidad al aprendizaje profundo bayesiano: teorema de Bayes, grafos dirigidos acíclicos, tablas de probabilidad condicional, inferencia exacta y aproximada, aprendizaje de estructura, BNNs, MC Dropout, Bayes by Backprop, y aplicaciones reales con código en Python (pgmpy, PyMC, PyTorch).

¿Qué es la probabilidad?

Antes de hablar de redes bayesianas necesitamos hablar de probabilidad. La probabilidad es el lenguaje que usamos para cuantificar la incertidumbre. No todo en la vida es blanco o negro: a veces llovemos, a veces no; a veces el email es spam, a veces no. La probabilidad nos da un número entre 0 y 1 para expresar cuán seguros estamos de algo.

$$P(A) \in [0, 1]$$
🎲
Frecuentista
La probabilidad es la frecuencia relativa de un evento al repetir un experimento muchas veces. P(cara) = Ncaras / Ntotal.
🧠
Bayesiana
La probabilidad es un grado de creencia. Refleja nuestra incertidumbre sobre algo, que actualizamos al observar datos.
📐
Axiomática
Kolmogorov (1933): la probabilidad es una medida sobre un espacio muestral Ω que cumple tres axiomas fundamentales.
💡 ¿Por qué «bayesiana»? — En una red bayesiana adoptamos la interpretación bayesiana: las probabilidades representan creencias que se actualizan con la evidencia. Esto es lo que hace a estos modelos tan potentes para razonar bajo incertidumbre.

La interpretación bayesiana fue propuesta por Thomas Bayes en 1763 (publicada póstumamente) y desarrollada extensamente por Pierre-Simon Laplace. Fue minoritaria durante gran parte del siglo XX frente al enfoque frecuentista, pero resurgió con fuerza en la segunda mitad del siglo gracias a avances computacionales (MCMC, Gibbs Sampling) que permitieron aplicar el método a problemas complejos. Hoy, el enfoque bayesiano es dominante en áreas como el modelado probabilístico, la robótica, la medicina y el deep learning con incertidumbre.

McGrayne, S.B. (2011). The Theory That Would Not Die. Yale University Press. — Historia fascinante de cómo el teorema de Bayes fue rechazado y reivindicado a lo largo de 250 años.
1
No negatividad: Para todo evento A, \( P(A) \geq 0 \).
2
Normalización: \( P(\Omega) = 1 \), donde Ω es el espacio muestral completo.
3
Aditividad: Si \( A \cap B = \emptyset \), entonces \( P(A \cup B) = P(A) + P(B) \).

Probabilidad conjunta y marginal

Cuando tenemos varias variables aleatorias, necesitamos describir cómo se relacionan entre sí. La probabilidad conjunta \( P(X, Y) \) nos dice la probabilidad de que ocurran simultáneamente X = x e Y = y.

$$P(X, Y) = P(X \mid Y) \cdot P(Y) = P(Y \mid X) \cdot P(X)$$

A partir de la conjunta, podemos obtener la probabilidad marginal sumando (o integrando) sobre las variables que no nos interesan:

$$P(X) = \sum_{y} P(X, Y = y)$$

🚗 Ejemplo: Lluvia y Tráfico

Imaginemos dos variables: Lluvia (sí/no) y Tráfico (alto/bajo).

Tráfico altoTráfico bajoMarginal Lluvia
Lluvia = sí0.250.050.30
Lluvia = no0.200.500.70
Marginal Tráfico0.450.551.00

Las marginales (en morado) se obtienen sumando filas o columnas. P(Lluvia=sí) = 0.25 + 0.05 = 0.30.

Probabilidad condicional

La probabilidad condicional responde a la pregunta: «dado que sé Y, ¿cómo cambia mi creencia sobre X?».

$$P(X \mid Y) = \frac{P(X, Y)}{P(Y)}, \quad P(Y) > 0$$

Del ejemplo anterior: ¿cuál es la probabilidad de tráfico alto dado que llueve?

$$P(\text{Tráfico alto} \mid \text{Lluvia}) = \frac{P(\text{Tráfico alto}, \text{Lluvia})}{P(\text{Lluvia})} = \frac{0.25}{0.30} \approx 0.833$$
🎯 Intuición: Cuando llueve, la probabilidad de tráfico alto sube de 0.45 (marginal) a 0.83 (condicional). La información «llueve» cambia nuestra creencia sobre el tráfico. ¡Esto es la esencia del razonamiento bayesiano!

La probabilidad condicional es el mecanismo fundamental de las redes bayesianas. Cada nodo en una red almacena exactamente esto: la distribución condicional de esa variable dados sus padres en el grafo. Cuando observamos nueva evidencia, las probabilidades condicionales se propagan por toda la red, actualizando nuestras creencias de forma coherente. Este flujo de información es lo que hace a las redes bayesianas tan poderosas para el razonamiento bajo incertidumbre: cada pieza de evidencia puede cambiar nuestras creencias sobre variables aparentemente lejanas en el grafo.

Independencia y dependencia condicional

Dos variables son independientes si conocer una no aporta información sobre la otra:

$$X \perp Y \iff P(X, Y) = P(X) \cdot P(Y)$$

La independencia condicional es aún más potente: X e Y son condicionalmente independientes dado Z si:

$$X \perp Y \mid Z \iff P(X, Y \mid Z) = P(X \mid Z) \cdot P(Y \mid Z)$$

🏠 Ejemplo cotidiano

Alarma de incendios (A), Incendio (I), Cocinar (C). La alarma puede sonar por un incendio o por cocinar. Si no sabes nada, A e I están correlacionadas. Pero si ya sabes que estás cocinando (C = sí), saber que la alarma sonó no te da más información sobre un incendio real: \( I \perp A \mid C \).

Este concepto es la base de las redes bayesianas: modelar qué variables son condicionalmente independientes permite factorizar distribuciones complejas.

En una red bayesiana con n variables binarias, la distribución conjunta completa requeriría \( 2^n - 1 \) parámetros. Pero si cada variable solo depende de unos pocos padres (digamos \( k \ll n \)), la factorización en condicionales locales reduce esto a \( O(n \cdot 2^k) \), que es exponencialmente más pequeño. La independencia condicional no es solo una propiedad estadística: refleja la estructura causal del mundo. Un médico sabe que los síntomas de un paciente dependen de su enfermedad, no directamente de los síntomas de otro paciente. Esta modularidad permite construir modelos enormes pieza a pieza.

El Teorema de Bayes

El teorema de Bayes es la pieza central de todo el enfoque bayesiano. Nos dice cómo actualizar nuestras creencias cuando recibimos nueva evidencia:

$$\boxed{P(\theta \mid D) = \frac{P(D \mid \theta) \cdot P(\theta)}{P(D)}}$$
Prior P(θ) × Verosimilitud P(D | θ) ÷ Evidencia P(D) = Posterior P(θ | D)
TérminoNombreSignificado
P(θ) Prior (a priori) Lo que creemos sobre θ antes de ver datos
P(D | θ) Verosimilitud (likelihood) Cuán probable es observar D si θ fuera cierto
P(D) Evidencia (marginal likelihood) Constante de normalización: P(D) = Σ P(D|θ)P(θ)
P(θ | D) Posterior (a posteriori) Lo que creemos sobre θ después de ver datos

🧮 Calculadora interactiva del Teorema de Bayes

Ejemplo clásico: test médico. Ajusta la prevalencia de la enfermedad, la sensibilidad del test y la tasa de falsos positivos.

0.10%
95%
5.0%

Distribuciones de probabilidad

Las redes bayesianas usan distribuciones de probabilidad para describir cada variable. Aquí las más importantes:

DistribuciónTipoFórmulaUso en BNs
Bernoulli Discreta \( P(X=1) = p \) Variables binarias (sí/no, spam/no-spam)
Categórica Discreta \( P(X=k) = p_k \) Variables con múltiples categorías
Gaussiana Continua \( \mathcal{N}(\mu, \sigma^2) \) Variables continuas, redes gaussianas
Beta Continua \( \text{Beta}(\alpha, \beta) \) Prior conjugado para parámetros de Bernoulli
Dirichlet Continua \( \text{Dir}(\alpha_1, \ldots, \alpha_k) \) Prior conjugado para parámetros categóricos

Un prior conjugado es una distribución previa que, al combinarse con una verosimilitud particular, produce un posterior de la misma familia. Esto hace los cálculos tratables analíticamente.

$$\text{Prior Beta}(\alpha, \beta) + \text{Verosimilitud Binomial} \Rightarrow \text{Posterior Beta}(\alpha + k, \beta + n - k)$$

Si observamos k éxitos en n ensayos, simplemente sumamos a los parámetros del prior. Elegante y computacionalmente trivial.

Regla de la cadena y factorización

La regla de la cadena nos permite descomponer cualquier distribución conjunta en un producto de condicionales:

$$P(X_1, X_2, \ldots, X_n) = \prod_{i=1}^{n} P(X_i \mid X_1, \ldots, X_{i-1})$$

¿El problema? Con n variables binarias, la tabla conjunta tiene \( 2^n \) entradas. Para n = 30 eso son más de mil millones de valores. Inviable.

💡 La clave de las redes bayesianas: En lugar de almacenar toda la distribución conjunta, asumimos independencias condicionales que nos permiten factorizar la distribución en tablas locales mucho más pequeñas. Esto es exactamente lo que el grafo dirigido acíclico (DAG) codifica.
$$P(X_1, \ldots, X_n) = \prod_{i=1}^{n} P(X_i \mid \text{Pa}(X_i))$$

Donde \( \text{Pa}(X_i) \) son los padres de \( X_i \) en el DAG. Cada nodo solo depende de sus padres directos, no de todo el historial. Pasamos de exponencial a un producto de tablas locales. ¡Esta es la magia!

📉 Reducción de complejidad

VariablesTabla completaRed Bayesiana (≤3 padres)Reducción
101,024~80~13×
201,048,576~160~6,500×
50~1015~400~1012×
100~1030~800~1027×

¿Qué es una red bayesiana?

Una red bayesiana (Bayesian Network, BN) es un modelo gráfico probabilístico que representa un conjunto de variables y sus dependencias condicionales mediante un grafo dirigido acíclico (DAG).

Nodos
Cada nodo representa una variable aleatoria (discreta o continua). Ejemplo: Lluvia, Riego, Césped mojado.
➡️
Aristas
Las flechas representan dependencias causales directas. A → B significa «A influye directamente en B».
📊
CPTs
Cada nodo tiene una tabla de probabilidad condicional (CPT) que cuantifica cómo depende de sus padres.
🔄
Acíclico
El grafo no tiene ciclos: no puedes seguir las flechas y volver al mismo nodo. Esto garantiza consistencia.
$$\text{BN} = (G, \Theta)$$

Donde \( G = (V, E) \) es el DAG (vértices y aristas) y \( \Theta \) es el conjunto de parámetros (tablas de probabilidad condicional).

Nublado (C) Riego (R) Lluvia (L) Césped mojado (M)
$$P(C, R, L, M) = P(C) \cdot P(R \mid C) \cdot P(L \mid C) \cdot P(M \mid R, L)$$
🌟 4 variables, pero solo 10 parámetros en vez de \( 2^4 - 1 = 15 \). Y la diferencia se amplifica exponencialmente con más variables. ¡Éste es el poder de la factorización!

Esta factorización es posible gracias a las independencias condicionales codificadas en el grafo. Cada nodo solo necesita conocer el estado de sus padres directos, no de toda la red. Pearl (1988) demostró que esta propiedad, conocida como la condición de Markov local, es suficiente para definir una distribución conjunta única y consistente. En la práctica, esto significa que un experto del dominio puede construir una red bayesiana especificando relaciones locales ("la lluvia depende del estado de nubosidad") sin tener que pensar en la distribución conjunta global.

Tablas de probabilidad condicional (CPTs)

Cada nodo almacena una CPT (Conditional Probability Table) que define cómo se distribuye esa variable dado el estado de sus padres. Los nodos sin padres (raíces) tienen simplemente una distribución marginal.

☁️ CPT de Nublado (nodo raíz)

CP(C)
0.50
No0.50

💧 CPT de Riego | Nublado

NubladoP(Riego=sí)P(Riego=no)
0.100.90
No0.500.50

Intuición: si está nublado, es menos probable que riegues el jardín.

🌧️ CPT de Lluvia | Nublado

NubladoP(Lluvia=sí)P(Lluvia=no)
0.800.20
No0.200.80

🌿 CPT de Césped mojado | Riego, Lluvia

RiegoLluviaP(Mojado=sí)P(Mojado=no)
NoNo0.001.00
No0.900.10
No0.900.10
0.990.01

En la práctica, las CPTs pueden especificarse de tres formas: (1) conocimiento experto: un médico estima probabilidades basadas en experiencia; (2) datos: se estiman por frecuencias relativas (MLE) o con priors bayesianos; (3) híbrido: el experto proporciona la estructura y un prior, y los datos ajustan. Para variables continuas, las CPTs se reemplazan por distribuciones condicionales paramétricas, típicamente relaciones lineales gaussianas en las redes gaussianas (GBN).

🔮 Propagación en la red del césped

Selecciona la evidencia observada y calcula las probabilidades posteriores de cada variable.

d-Separación: leyendo independencias del grafo

La d-separación (separación direccional) es la regla gráfica que nos permite leer las independencias condicionales directamente del DAG, sin calcular ninguna probabilidad.

Dados tres conjuntos de nodos X, Y, Z, decimos que X está d-separado de Y dado Z si todos los caminos entre X e Y están «bloqueados» por Z.

⛓️
Cadena
A → B → C. Si observas B, A y C quedan d-separados. La información no «fluye» a través de B observado.
🍴
Horquilla (Fork)
A ← B → C. Si observas B, A y C son independientes. B es la «causa común» que los conectaba.
🔻
Colisionador (V-structure)
A → B ← C. Si NO observas B, A y C son independientes. Pero al observar B, ¡se vuelven dependientes! (explaining away).
A B C Cadena B A C Horquilla A B C Colisionador
Explaining away — El colisionador es contra-intuitivo pero fascinante. Si ves que el césped está mojado (B), de repente «Lluvia» (A) y «Riego» (C) se vuelven dependientes: si sabes que llovió, ya no necesitas que el riego esté encendido. Uno «explica» al otro.

La d-separación es una herramienta fundamental porque permite verificar de forma puramente gráfica —sin ningún cálculo numérico— si dos variables son condicionalmente independientes. Esto tiene aplicaciones directas: en el algoritmo PC para aprendizaje de estructura, en la simplificación de consultas de inferencia, y en la validación de modelos causales. Verlet y Bareinboim (2020) extendieron estos criterios al ámbito de la inferencia causal transportable entre dominios.

Geiger, D., Verma, T. & Pearl, J. (1990). d-Separation: From Theorems to Algorithms. Machine Intelligence and Pattern Recognition, 10, 139–148.

Manta de Markov

La manta de Markov de un nodo X es el conjunto mínimo de nodos que hace a X condicionalmente independiente del resto de la red:

1
Padres de X
2
Hijos de X
3
Co-padres de los hijos de X (otros padres de los mismos hijos)
$$X \perp \{V \setminus \text{MB}(X)\} \mid \text{MB}(X)$$

🛡️ ¿Por qué importa?

  • Para hacer inferencia local: solo necesitas la manta de Markov, no toda la red.
  • En Gibbs sampling: muestrear X solo depende de su manta de Markov.
  • Para selección de features: la manta de Markov de la variable objetivo es el conjunto óptimo de predictores.

Tipos de redes bayesianas

TipoVariablesCPTsUso típico
Discreta Categóricas Tablas finitas Diagnóstico médico, spam, averías
Gaussiana (GBN) Continuas Relaciones lineales + ruido gaussiano Modelos financieros, sensores
Híbrida Mixtas CLG (Conditional Linear Gaussian) Sistemas reales complejos
Dinámica (DBN) Con tiempo CPTs entre time-slices Series temporales, tracking
Naive Bayes Categóricas Clase → features (indep. entre features) Clasificación simple, filtro de spam
TAN Categóricas Naive Bayes + 1 dependencia entre features Clasificación con dependencias

Una DBN es como una red bayesiana «desenrollada» en el tiempo. Cada time-slice contiene las variables del sistema y las aristas inter-slice modelan las dependencias temporales.

Casos especiales famosos:

  • Hidden Markov Model (HMM): un nodo oculto + un nodo observado por slice
  • Kalman Filter: DBN gaussiana lineal

Las DBN generalizan a HMMs y Kalman filters: son el marco unificador para modelos probabilísticos temporales.

Redes bayesianas vs otros modelos gráficos

PropiedadRed Bayesiana (BN)Markov Random Field (MRF)Factor Graph
Grafo Dirigido acíclico (DAG) No dirigido Bipartito (variables + factores)
Semántica Causal / generativa Correlaciones General
Parámetros CPTs (probabilidades) Potenciales (no normalizados) Factores arbitrarios
Independencias d-separación Separación por nodos Según estructura
Ejemplo famoso Diagnóstico médico Segmentación de imágenes (CRF) Decodificación LDPC
📌 Equivalencia: Toda BN puede convertirse en un MRF (moralización) y en un factor graph. Sin embargo, se pierde la información causal/direccional. La ventaja de las BNs es su interpretación causal y la facilidad de especificar CPTs.

¿Qué es la inferencia en una red bayesiana?

Inferir es la tarea central de una red bayesiana: dada evidencia (variables observadas), calcular la distribución posterior de las variables de interés (query).

$$P(\text{Query} \mid \text{Evidencia}) = \frac{P(\text{Query}, \text{Evidencia})}{P(\text{Evidencia})}$$
🔍
Posterior
Calcular P(X | e). Ejemplo: P(Enfermedad | síntomas observados).
🏆
MAP
Encontrar la asignación más probable: arg max P(X | e). El «diagnóstico más probable».
📊
Marginal
Calcular P(X) marginalizando sobre todas las demás variables. Útil para predicciones a priori.
🎯
MPE
Most Probable Explanation: la asignación completa más probable dada la evidencia.
⚠️ Complejidad: La inferencia exacta en redes bayesianas generales es NP-hard (Cooper, 1990). Por eso existen algoritmos tanto exactos (para redes pequeñas/árboles) como aproximados (para redes grandes).

Eliminación de variables

La eliminación de variables (Variable Elimination, VE) es el algoritmo exacto más directo. La idea: en vez de computar la distribución conjunta completa y luego marginalizar, vamos eliminando variables una a una, sumándolas «localmente».

1
Listar factores: Recoger todas las CPTs de la red como factores \( f_1, f_2, \ldots, f_n \).
2
Fijar evidencia: En cada factor, sustituir las variables observadas por sus valores.
3
Elegir orden de eliminación: Seleccionar qué variable oculta eliminar primero (el orden afecta la eficiencia, no el resultado).
4
Eliminar variable: Multiplicar todos los factores que contienen la variable, luego sumarla: \( \tau = \sum_{X_i} \prod_{f \ni X_i} f \).
5
Repetir hasta que solo queden las variables query. Multiplicar los factores restantes y normalizar.

Queremos calcular P(L | M = sí) en la red del césped.

Factores iniciales: P(C), P(R|C), P(L|C), P(M|R,L)

Fijar evidencia: M = sí → P(M=sí | R, L)

  1. Eliminar R: τ₁(C, L) = Σᵣ P(R|C) · P(M=sí|R,L)
  2. Eliminar C: τ₂(L) = Σ_c P(C) · P(L|C) · τ₁(C, L)
  3. Normalizar: P(L|M=sí) = τ₂(L) / Σₗ τ₂(L)

Resultado: P(L=sí | M=sí) ≈ 0.708. Si el césped está mojado, hay un 71% de probabilidad de que haya llovido.

La eficiencia de la eliminación de variables depende críticamente del orden de eliminación. Encontrar el orden óptimo es NP-hard (equivalente al problema del treewidth mínimo), pero existen heurísticas efectivas como min-degree y min-fill que funcionan bien en la práctica. La conexión entre eliminación de variables y las tensor networks de la física cuántica es un área activa de investigación: ambas se reducen a operaciones de contracción de tensores.

Koller, D. & Friedman, N. (2009). Probabilistic Graphical Models: Principles and Techniques. MIT Press. Cap. 9: Variable Elimination.

Propagación de creencias (Belief Propagation)

La propagación de creencias (BP), también llamada message passing o algoritmo de Pearl (1988), es una forma elegante de hacer inferencia exacta en árboles (poly-trees) y aproximada en grafos generales (Loopy BP).

📨 Mensajes en el grafo

Cada nodo envía «mensajes» a sus vecinos con dos tipos:

  • λ-mensaje (de hijo a padre): «aquí abajo, la evidencia sugiere que…»
  • π-mensaje (de padre a hijo): «arriba, la evidencia sugiere que…»

La creencia de un nodo X se calcula combinando todos los mensajes que recibe:

$$\text{BEL}(X) = \alpha \cdot \pi(X) \cdot \lambda(X)$$
PropiedadVariable EliminationBelief Propagation
Tipo Exacto (siempre) Exacto en árboles, aproximado en loops
Eficiencia para múltiples queries Hay que re-ejecutar por cada query Una sola pasada calcula todas las marginales
Complejidad Depende del orden de eliminación O(n · k²) para árboles con k estados
Implementación Más simple Más eficiente en práctica

Algoritmo de Junction Tree

El Junction Tree (JT) es el algoritmo exacto más general y eficiente. Transforma cualquier BN en un árbol de cliques donde se puede aplicar BP exacto.

1
Moralizar: Conectar co-padres y eliminar la dirección de las aristas.
2
Triangular: Añadir aristas para que todos los ciclos de longitud ≥ 4 tengan una cuerda.
3
Identificar cliques: Encontrar los cliques máximales del grafo triangulado.
4
Construir Junction Tree: Conectar cliques en un árbol donde los separadores satisfacen la running intersection property.
5
Message passing: Propagar mensajes entre cliques (similar a BP pero entre cliques).
📐 Complejidad: La complejidad es \( O(n \cdot k^w) \) donde \( w \) es el treewidth del grafo. Para redes con treewidth bajo (e.g., árboles, HMMs), JT es muy eficiente. Para redes densas, puede ser exponencial.

Inferencia aproximada: MCMC

Cuando la inferencia exacta es intratable (redes grandes, variables continuas), recurrimos a métodos de Monte Carlo por Cadenas de Markov (MCMC). La idea: generar muestras de la distribución posterior y estimar probabilidades contando.

🎰
Gibbs Sampling
Muestrear cada variable condicionada en el resto (su manta de Markov). Simple y muy usado en BNs.
🏃
Metropolis-Hastings
Proponer un estado, aceptar o rechazar según ratio de probabilidades. Más general que Gibbs.
HMC / NUTS
Hamiltonian MC usa gradientes para propuestas eficientes. NUTS ajusta automáticamente los parámetros. Estado del arte.
🎯
Likelihood Weighting
Muestreo por importancia: generar muestras de arriba a abajo, ponderar por evidencia. Más simple que MCMC.
1
Inicializar: Asignar valores aleatorios a las variables no observadas.
2
Para cada variable oculta \( X_i \): Muestrear un nuevo valor de \( P(X_i \mid \text{MB}(X_i)) \), su distribución condicional dada la manta de Markov.
3
Repetir los pasos 2 muchas veces (miles o millones).
4
Estimar: \( P(X = x \mid e) \approx \frac{\text{\# muestras con } X{=}x}{N_{\text{total}}} \) (descartar las primeras muestras como burn-in).

🎲 Gibbs Sampling interactivo

Ejecuta Gibbs Sampling en la red del césped para estimar P(Lluvia | Césped mojado = sí). Observa cómo converge con más muestras.

1000
10%

En la práctica, un aspecto crítico de MCMC es el diagnóstico de convergencia: ¿cómo sabemos que las muestras representan realmente la distribución posterior y no son solo ruido? Las herramientas más usadas incluyen el estadístico \( \hat{R} \) de Gelman-Rubin (compara varianza intra- e inter-cadena), el effective sample size (ESS), y la inspección visual de las trace plots. El sampler NUTS (No U-Turn Sampler), implementado en PyMC y Stan, ajusta automáticamente los parámetros de HMC y es hoy el estándar de facto para inferencia bayesiana en modelos continuos.

Hoffman, M.D. & Gelman, A. (2014). The No-U-Turn Sampler. JMLR, 15, 1593–1623. [arXiv]

Inferencia variacional

La inferencia variacional (VI) reformula la inferencia como un problema de optimización: encontrar la distribución \( q(\theta) \) más cercana al posterior real \( p(\theta \mid D) \).

$$q^* = \arg\min_{q \in \mathcal{Q}} \text{KL}\big(q(\theta) \,\|\, p(\theta \mid D)\big)$$

Como la KL no se puede computar directamente (necesitaríamos p(D)), maximizamos el ELBO (Evidence Lower Bound):

$$\text{ELBO}(q) = \mathbb{E}_{q}[\log p(D, \theta)] - \mathbb{E}_{q}[\log q(\theta)] \leq \log p(D)$$
PropiedadMCMCInferencia Variacional
Naturaleza Muestreo estocástico Optimización determinista
Convergencia Garantizada (teórica) al verdadero posterior A una aproximación (sesgo posible)
Velocidad Lenta (especialmente en alta dimensión) Rápida (aprovecha SGD, GPUs)
Escalabilidad Difícil en big data Escala bien (SVI, amortized VI)
Uso en DL MC Dropout VAE, Bayes by Backprop
🚀 ¿Por qué importa VI para deep learning? — Los VAE (Variational Autoencoders) y Bayes by Backprop usan inferencia variacional. La conexión entre BNs clásicas y redes neuronales modernas pasa por aquí.

La inferencia variacional ha experimentado una revolución con la llegada de las técnicas de amortized inference: en lugar de optimizar \( q \) para cada dato, entrenamos una red neuronal (el encoder) que directamente mapea datos a parámetros variacionales. Esto es la base del VAE y ha abierto la puerta a modelos generativos a gran escala. Variantes modernas como Normalizing Flows (Rezende & Mohamed, 2015) permiten familias variacionales mucho más expresivas que la asunción gaussiana clásica de mean-field.

Blei, D.M., Kucukelbir, A. & McAuliffe, J.D. (2017). Variational Inference: A Review for Statisticians. JASA, 112(518), 859–877. [arXiv]

Aprendizaje de parámetros

Una vez fijada la estructura (el DAG), necesitamos estimar los valores de las CPTs a partir de datos. Hay dos enfoques principales:

📈
MLE
Maximum Likelihood Estimation: estimar los parámetros que maximizan la probabilidad de los datos observados.
🧮
MAP / Bayesiano
Maximum A Posteriori: incorporar un prior sobre los parámetros. El enfoque bayesiano completo computa todo el posterior.
EM
Expectation-Maximization: para datos con variables ocultas (incompletos). Alterna entre estimar estados ocultos y actualizar parámetros.

MLE con datos completos

Si todos los datos son observados, MLE es trivial: contar frecuencias. Para un nodo \( X_i \) con padres \( \text{Pa}_i \):

$$\hat{\theta}_{x_i | \text{pa}_i} = \frac{N(x_i, \text{pa}_i)}{N(\text{pa}_i)}$$

🧮 Ejemplo numérico

Si tenemos 100 observaciones donde Nublado = sí, y en 82 de ellas Lluvia = sí:

$$\hat{P}(\text{Lluvia} = \text{sí} \mid \text{Nublado} = \text{sí}) = \frac{82}{100} = 0.82$$

Simple, rápido, pero puede sobreajustar con pocos datos (¿qué pasa si N = 5?).

Estimación bayesiana con prior de Dirichlet

Para evitar estimaciones de 0 o 1 con pocos datos, añadimos un prior de Dirichlet (el conjugado de la distribución categórica):

$$\hat{\theta}_{x_i | \text{pa}_i} = \frac{N(x_i, \text{pa}_i) + \alpha_{x_i}}{N(\text{pa}_i) + \sum_j \alpha_j}$$
💡 Suavizado de Laplace: Usar \( \alpha = 1 \) es el famoso «add-one smoothing». Con \( \alpha = 0.5 \) tenemos el estimador de Jeffreys. El prior actúa como «pseudo-observaciones» que previenen probabilidades extremas.

Aprendizaje de estructura

El problema más desafiante: ¿cómo descubrir el DAG a partir de datos? El número de DAGs posibles crece superexponencialmente con el número de variables.

NodosDAGs posibles
325
529,281
8~7.8 × 10¹¹
10~4.2 × 10¹⁸
20~2.3 × 10⁷²

Hay tres familias principales de algoritmos:

📏
Score-based
Buscar el DAG que maximice una puntuación (BIC, BDeu, BGe). Se usan heurísticas de búsqueda (hill climbing, FGES, etc.).
🔬
Constraint-based
Descubrir la estructura mediante tests de independencia condicional. Ejemplo: algoritmo PC, IC, FCI.
🤝
Híbridos
Combinar ambos: primero tests de independencia para reducir el espacio, luego optimizar un score. Ejemplo: MMHC.

Funciones de puntuación (scores)

Las funciones de puntuación evalúan cuán bien un DAG explica los datos, penalizando la complejidad para evitar sobreajuste.

ScoreFórmula (idea)Propiedades
BIC / MDL \( \text{BIC} = \log P(D \mid \hat{\theta}, G) - \frac{d}{2} \log N \) Consistente, descomponible, penaliza complejidad
BDeu \( \text{BDeu} = \log \int P(D \mid \theta, G) P(\theta \mid G) d\theta \) Bayesiano (marginal likelihood), score equivalence
BGe Versión gaussiana de BD para datos continuos Para redes gaussianas, normal-Wishart prior
K2 BDeu con prior uniforme (α=1) Históricamente popular, simple
AIC \( \text{AIC} = \log P(D \mid \hat{\theta}, G) - d \) Menos conservador que BIC, tiende a sobreajustar más

Un score es descomponible si se puede escribir como suma de scores locales, uno por nodo:

$$\text{Score}(G) = \sum_{i=1}^{n} s(X_i, \text{Pa}_G(X_i))$$

Esto es crucial para la eficiencia: al evaluar un cambio local en el grafo (añadir/eliminar/invertir una arista), solo recalculamos el score del nodo afectado, no de toda la red.

Algoritmo PC (constraint-based)

El algoritmo PC (Peter & Clark, Spirtes et al., 1993) descubre la estructura mediante tests de independencia condicional.

1
Grafo completo: Empezar con un grafo no dirigido completo (todas las aristas).
2
Eliminar aristas: Para cada par (X, Y), buscar un conjunto separador S tal que \( X \perp Y \mid S \). Si lo encontramos, eliminar la arista X — Y.
3
Orientar V-structures: Si X — Z — Y pero X e Y no están conectados y Z no está en el separador de X,Y → orientar como X → Z ← Y.
4
Propagar orientaciones: Aplicar reglas de Meek para orientar aristas restantes sin crear nuevas V-structures ni ciclos.
⚠️ Limitación: El PC asume faithfulness (que todas las independencias en los datos se reflejen en el grafo). También es sensible a errores en los tests estadísticos con pocos datos.

Un avance reciente es NOTEARS (Zheng et al., 2018), que reformula el aprendizaje de estructura como un problema de optimización continua, eliminando la restricción combinatoria de aciclicidad mediante una penalización diferenciable: \( h(W) = \text{tr}(e^{W \circ W}) - d = 0 \). Esto permite usar gradientes y escalar a redes con cientos de variables, algo impensable con métodos clásicos.

Zheng, X. et al. (2018). DAGs with NO TEARS: Continuous Optimization for Structure Learning. NeurIPS. [arXiv]

Hill Climbing (score-based)

El Hill Climbing (HC) es el algoritmo de búsqueda más usado en la práctica. Es simple pero efectivo:

1
Inicializar: Empezar con un DAG vacío (o aleatorio).
2
Generar vecinos: Considerar todos los DAGs que difieren en una operación: añadir arista, eliminar arista, invertir arista.
3
Evaluar: Calcular el score de cada vecino (solo re-evaluar el nodo afectado, gracias a descomponibilidad).
4
Seleccionar: Moverse al vecino con mejor score (si mejora el actual).
5
Repetir hasta que ningún vecino mejore el score (óptimo local).

🏗️ Score de estructura

Compara el BIC score de diferentes estructuras para un dataset con 3 variables. Selecciona las aristas presentes y observa cómo cambia el score.

500

Clases de equivalencia de Markov

Varios DAGs diferentes pueden codificar exactamente las mismas independencias condicionales. Estos DAGs forman una clase de equivalencia de Markov, representada por un CPDAG (Completed Partially Directed Acyclic Graph).

🔄 Ejemplo de DAGs equivalentes

Estos tres DAGs son equivalentes de Markov (codifican las mismas independencias):

  • A → B → C
  • A ← B → C (fork)
  • A ← B ← C

En todos los casos, A ⊥ C | B. Solo la V-structure (A → B ← C) pertenece a una clase diferente.

🎯 Implicación: Solo con datos observacionales, no podemos distinguir entre DAGs en la misma clase de equivalencia. Para identificar la dirección causal necesitamos intervenciones (do-calculus de Pearl) o supuestos adicionales.

Judea Pearl formalizó la distinción entre «ver» (condicionamiento) e «intervenir» (do-operator):

$$P(Y \mid \text{do}(X = x)) \neq P(Y \mid X = x)$$

P(Y | X=x): ¿qué observamos cuando X toma valor x? (correlación)

P(Y | do(X=x)): ¿qué pasa si forzamos X a valor x? (causalidad)

El criterio back-door y el front-door de Pearl nos dicen cuándo y cómo podemos estimar efectos causales a partir de datos observacionales usando la estructura de la BN.

Pearl, J. (2009). Causality: Models, Reasoning, and Inference. Cambridge University Press.

La distinción entre correlación y causalidad es uno de los temas más importantes en ciencia de datos moderna. Las redes bayesianas, junto con los frameworks causales de Pearl y Rubin, proporcionan las herramientas matemáticas para abordar esta cuestión de forma rigurosa. En esta web, puedes profundizar en estos conceptos en el submódulo de Aprendizaje por Refuerzo, donde las decisiones causales son fundamentales para la política del agente.

La conexión entre redes bayesianas y deep learning

Las redes neuronales clásicas producen predicciones puntuales: «este email es spam con 92% de confianza». Pero, ¿cuán fiable es ese 92%? Las redes neuronales bayesianas (BNNs) resuelven esto tratando los pesos como variables aleatorias con distribuciones, no como valores fijos.

Red clásica w = valor fijo ŷ = 0.92 Red bayesiana (BNN) w ~ N(μ, σ²) ŷ = 0.92 ± 0.08
PropiedadNN clásicaBNN (Bayesian Neural Network)
PesosValores fijos (punto)Distribuciones P(w)
Predicciónf(x; w*)∫ f(x; w) P(w|D) dw
IncertidumbreNo cuantificadaEpistémica + aleatórica
SobreajusteNecesita regularización explícitaRegularización natural (prior)
CalibraciónGeneralmente pobreGeneralmente mejor
Coste computacionalMenorMayor (muestreo / VI)

La conexión entre redes bayesianas y deep learning va más allá de una simple extensión técnica. MacKay (1992) ya propuso el tratamiento bayesiano de redes neuronales, mostrando que el weight decay (regularización L2) es equivalente a asumir un prior gaussiano sobre los pesos. Neal (1996) demostró que una BNN con una capa oculta infinitamente ancha converge a un Gaussian Process, conectando elegantemente dos mundos aparentemente distintos. Más recientemente, Wilson & Izmailov (2020) argumentaron que la perspectiva bayesiana explica por qué las redes neuronales generalizan tan bien.

Tipos de incertidumbre

🧠
Epistémica
Incertidumbre del modelo: falta de conocimiento. Se reduce con más datos. «No sé porque no he visto suficientes ejemplos».
🎲
Aleatórica
Incertidumbre de los datos: ruido inherente. NO se reduce con más datos. «Los datos son ruidosos por naturaleza».
$$\underbrace{\text{Var}[y^*]}_{\text{total}} = \underbrace{\text{Var}_w[\mathbb{E}[y^* \mid w]]}_{\text{epistémica}} + \underbrace{\mathbb{E}_w[\text{Var}[y^* \mid w]]}_{\text{aleatórica}}$$
💡 ¿Por qué importa? — En aplicaciones críticas (medicina, conducción autónoma), no basta con una predicción: necesitamos saber cuánto confiar en ella. Alta incertidumbre epistémica → «necesito más datos». Alta incertidumbre aleatórica → «los datos son inherentemente ruidosos aquí».

Distinguir entre ambos tipos de incertidumbre es crucial para tomar decisiones informadas. Por ejemplo, en un sistema de diagnóstico médico por imágenes: si la incertidumbre epistémica es alta (el modelo «no ha visto» ese tipo de imagen), la decisión correcta es derivar a un especialista humano, no dar un diagnóstico posiblemente erróneo. Si la incertidumbre aleatoria es alta (la imagen es ruidosa por naturaleza), la decisión es pedir una nueva imagen. Kendall & Gal (2017) formalizaron esta descomposición para redes neuronales profundas, mostrando cómo capturar ambas simultáneamente.

Kendall, A. & Gal, Y. (2017). What Uncertainties Do We Need in Bayesian Deep Learning for Computer Vision? NeurIPS. [arXiv]

MC Dropout: inferencia bayesiana «gratis»

MC Dropout (Gal & Ghahramani, 2016) es la forma más simple de obtener estimaciones bayesianas de una red neuronal: mantener dropout activado durante la inferencia y hacer múltiples pasadas forward.

1
Entrenar la red con dropout (como siempre).
2
En inferencia: NO desactivar dropout. Mantenerlo activo.
3
Hacer T pasadas forward con la misma entrada x. Cada pasada produce una predicción diferente (por el dropout aleatorio).
4
Predicción: \( \hat{y} = \frac{1}{T} \sum_{t=1}^{T} f(x; w_t) \)
5
Incertidumbre: \( \sigma^2 = \frac{1}{T} \sum_{t=1}^{T} (f(x; w_t) - \hat{y})^2 \)
import torch
import torch.nn as nn

class MCDropoutModel(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim, drop_rate=0.2):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Dropout(drop_rate),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Dropout(drop_rate),
            nn.Linear(hidden_dim, output_dim)
        )

    def forward(self, x):
        return self.net(x)

def mc_predict(model, x, T=100):
    """Predicción bayesiana con MC Dropout."""
    model.train()  # ← Mantener dropout activo
    preds = torch.stack([model(x) for _ in range(T)])  # (T, batch, out)

    mean = preds.mean(dim=0)         # Predicción promedio
    std = preds.std(dim=0)           # Incertidumbre
    return mean, std

# Ejemplo de uso
model = MCDropoutModel(input_dim=10, hidden_dim=64, output_dim=1)
x_test = torch.randn(1, 10)

mean, uncertainty = mc_predict(model, x_test, T=200)
print(f"Predicción: {mean.item():.3f} ± {uncertainty.item():.3f}")
# Si uncertainty es alta → el modelo no está seguro → ¡pedir más datos!
Gal, Y. & Ghahramani, Z. (2016). Dropout as a Bayesian Approximation: Representing Model Uncertainty in Deep Learning. ICML.

Bayes by Backprop

Bayes by Backprop (Blundell et al., 2015) es un método de inferencia variacional para BNNs. En vez de aprender un valor por peso, aprendemos una distribución \( q(w) = \mathcal{N}(\mu, \sigma^2) \) por cada peso.

$$\mathcal{L}(\theta) = \text{KL}\big[q_\theta(w) \,\|\, P(w)\big] - \mathbb{E}_{q_\theta(w)}\big[\log P(D \mid w)\big]$$

🔧 Truco de la reparametrización

Para poder hacer backpropagation a través de un muestreo, usamos el reparameterization trick:

$$w = \mu + \sigma \cdot \epsilon, \quad \epsilon \sim \mathcal{N}(0, 1)$$

Así, el muestreo es una operación determinista + ruido externo, y podemos calcular gradientes respecto a μ y σ. ¡El mismo truco que usa el VAE!

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

class BayesianLinear(nn.Module):
    """Capa lineal con pesos distribuidos N(μ, σ²)."""
    def __init__(self, in_features, out_features):
        super().__init__()
        # Parámetros variacionales: media y log-varianza
        self.w_mu = nn.Parameter(torch.randn(out_features, in_features) * 0.1)
        self.w_rho = nn.Parameter(torch.full((out_features, in_features), -3.0))
        self.b_mu = nn.Parameter(torch.zeros(out_features))
        self.b_rho = nn.Parameter(torch.full((out_features,), -3.0))

        # Prior: N(0, 1)
        self.prior_mu = 0.0
        self.prior_sigma = 1.0

    def forward(self, x):
        # Reparameterization trick
        w_sigma = torch.log1p(torch.exp(self.w_rho))  # softplus para σ > 0
        b_sigma = torch.log1p(torch.exp(self.b_rho))

        w = self.w_mu + w_sigma * torch.randn_like(w_sigma)
        b = self.b_mu + b_sigma * torch.randn_like(b_sigma)

        # KL divergence (vs prior gaussiano)
        self.kl = self._kl_divergence(self.w_mu, w_sigma) + \
                  self._kl_divergence(self.b_mu, b_sigma)

        return F.linear(x, w, b)

    def _kl_divergence(self, mu, sigma):
        """KL(N(mu, sigma²) || N(0, 1))"""
        return 0.5 * torch.sum(
            sigma.pow(2) + mu.pow(2) - 1 - 2 * torch.log(sigma)
        )


class BayesianNet(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.l1 = BayesianLinear(input_dim, hidden_dim)
        self.l2 = BayesianLinear(hidden_dim, output_dim)

    def forward(self, x):
        x = F.relu(self.l1(x))
        return self.l2(x)

    def kl_loss(self):
        return self.l1.kl + self.l2.kl


# Entrenamiento
model = BayesianNet(10, 64, 1)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

for epoch in range(100):
    pred = model(x_train)
    nll = F.mse_loss(pred, y_train)
    kl = model.kl_loss() / len(x_train)  # Normalizar por N
    loss = nll + kl  # ELBO = NLL + KL
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
Blundell, C. et al. (2015). Weight Uncertainty in Neural Networks. ICML.

Comparativa de métodos de Bayesian Deep Learning

MétodoIdeaCoste extraCalidadFacilidad
MC Dropout Dropout en inferencia ~T× forward passes Aproximación razonable ⭐⭐⭐⭐⭐
Bayes by Backprop VI con pesos gaussianos 2× parámetros + sampling Buena ⭐⭐⭐
Deep Ensembles Entrenar M modelos M× entrenamiento Muy buena (SOTA práctico) ⭐⭐⭐⭐
SWAG Gaussian sobre SGD trajectory Bajo (post-hoc) Buena ⭐⭐⭐⭐
Laplace Approx. Gaussiana en MAP Hessiana (aproximada) Moderada ⭐⭐⭐
HMC / NUTS MCMC con gradientes Muy alto Gold standard ⭐⭐
🏆 En la práctica: Deep Ensembles (Lakshminarayanan et al., 2017) suele ganar en benchmarks de calibración e incertidumbre. MC Dropout es el más fácil de implementar. Bayes by Backprop es el más «bayesiano puro».

Una tendencia reciente es combinar métodos: Multi-SWAG (Wilson & Izmailov, 2020) entrena un ensemble de modelos SWAG, consiguiendo lo mejor de ambos mundos. Laplace Redux (Daxberger et al., 2021) aplica una aproximación de Laplace post-hoc sobre una red ya entrenada, añadiendo incertidumbre sin reentrenar. Para aplicaciones de visión por computador con incertidumbre, puedes consultar el submódulo de Redes Convolucionales.

Daxberger, E. et al. (2021). Laplace Redux: Effortless Bayesian Deep Learning. NeurIPS. [arXiv]

📊 Explorador de incertidumbre

Simula una BNN simple con MC Dropout. Observa cómo la incertidumbre crece cuando la entrada se aleja de los datos de entrenamiento.

0.00
0.20

Modelos generativos profundos bayesianos

Las ideas bayesianas están en el corazón de varios modelos generativos profundos modernos:

🔄
VAE
Variational Autoencoder: modelo generativo latente donde el encoder aproxima el posterior q(z|x) y el decoder genera p(x|z). Entrenado maximizando ELBO.
🧩
Normalizing Flows
Transformaciones invertibles que convierten una distribución simple en una compleja. Posterior exacto tractable.
🎯
Neural Processes
Meta-learning bayesiano: aprender una distribución sobre funciones a partir de un contexto, como un Gaussian Process amortizado.

El VAE es, en esencia, una red bayesiana con dos nodos: la variable latente z y los datos x:

$$z \sim \mathcal{N}(0, I) \quad \rightarrow \quad x \sim p_\theta(x \mid z)$$

El encoder \( q_\phi(z \mid x) \) aproxima el posterior intractable \( p(z \mid x) \). El objetivo ELBO conecta directamente con la inferencia variacional que vimos en redes bayesianas clásicas.

Kingma, D.P. & Welling, M. (2014). Auto-Encoding Variational Bayes. ICLR.

Código Python: redes bayesianas con pgmpy

pgmpy es la librería de referencia en Python para redes bayesianas clásicas. Permite definir estructuras, CPTs, inferencia exacta y aproximada, y aprendizaje de estructura.

from pgmpy.models import BayesianNetwork
from pgmpy.factors.discrete import TabularCPD
from pgmpy.inference import VariableElimination

# 1. Definir la estructura (DAG)
model = BayesianNetwork([
    ('Nublado', 'Riego'),
    ('Nublado', 'Lluvia'),
    ('Riego', 'CespedMojado'),
    ('Lluvia', 'CespedMojado')
])

# 2. Definir las CPTs
cpd_nublado = TabularCPD('Nublado', 2, [[0.5], [0.5]])

cpd_riego = TabularCPD('Riego', 2,
    [[0.5, 0.9],   # P(Riego=no | Nublado)
     [0.5, 0.1]],  # P(Riego=sí | Nublado)
    evidence=['Nublado'], evidence_card=[2])

cpd_lluvia = TabularCPD('Lluvia', 2,
    [[0.8, 0.2],   # P(Lluvia=no | Nublado)
     [0.2, 0.8]],  # P(Lluvia=sí | Nublado)
    evidence=['Nublado'], evidence_card=[2])

cpd_mojado = TabularCPD('CespedMojado', 2,
    [[1.0, 0.1, 0.1, 0.01],  # P(Mojado=no | Riego, Lluvia)
     [0.0, 0.9, 0.9, 0.99]], # P(Mojado=sí | Riego, Lluvia)
    evidence=['Riego', 'Lluvia'], evidence_card=[2, 2])

model.add_cpds(cpd_nublado, cpd_riego, cpd_lluvia, cpd_mojado)
assert model.check_model()  # Verificar consistencia

# 3. Inferencia: P(Lluvia | CespedMojado = sí)
infer = VariableElimination(model)
result = infer.query(['Lluvia'], evidence={'CespedMojado': 1})
print(result)
# ╒══════════╤══════════════╕
# │ Lluvia   │   phi(Lluvia)│
# ╞══════════╪══════════════╡
# │ Lluvia_0 │       0.2921 │  ← No llueve
# │ Lluvia_1 │       0.7079 │  ← Llueve (71%!)
# ╘══════════╧══════════════╛
import pandas as pd
from pgmpy.estimators import HillClimbSearch, BicScore, BayesianEstimator

# Generar datos de ejemplo
import numpy as np
np.random.seed(42)
N = 1000
nublado = np.random.binomial(1, 0.5, N)
riego = np.random.binomial(1, np.where(nublado, 0.1, 0.5))
lluvia = np.random.binomial(1, np.where(nublado, 0.8, 0.2))
mojado = np.random.binomial(1,
    np.where(riego & lluvia, 0.99,
    np.where(riego | lluvia, 0.9, 0.0)))

data = pd.DataFrame({
    'Nublado': nublado, 'Riego': riego,
    'Lluvia': lluvia, 'CespedMojado': mojado
})

# Aprender estructura con Hill Climbing + BIC
hc = HillClimbSearch(data)
best_model = hc.estimate(scoring_method=BicScore(data))
print("Aristas descubiertas:", best_model.edges())
# [('Nublado', 'Lluvia'), ('Nublado', 'Riego'),
#  ('Riego', 'CespedMojado'), ('Lluvia', 'CespedMojado')]
# ¡Recuperó la estructura correcta!

# Aprender parámetros con estimación bayesiana
from pgmpy.models import BayesianNetwork
model = BayesianNetwork(best_model.edges())
model.fit(data, estimator=BayesianEstimator, prior_type='BDeu',
          equivalent_sample_size=10)

Código Python: inferencia bayesiana con PyMC

PyMC es la librería estrella para modelado bayesiano en Python. Usa MCMC (NUTS) y VI, ideal para modelos bayesianos complejos y BNNs.

import pymc as pm
import numpy as np
import arviz as az

# Datos sintéticos
np.random.seed(42)
X = np.random.randn(100)
y = 2.5 * X + 1.0 + np.random.randn(100) * 0.5

# Modelo bayesiano
with pm.Model() as model:
    # Priors
    alpha = pm.Normal('alpha', mu=0, sigma=10)  # intercepto
    beta = pm.Normal('beta', mu=0, sigma=10)    # pendiente
    sigma = pm.HalfNormal('sigma', sigma=1)     # ruido

    # Verosimilitud
    mu = alpha + beta * X
    y_obs = pm.Normal('y_obs', mu=mu, sigma=sigma, observed=y)

    # Inferencia MCMC (NUTS)
    trace = pm.sample(2000, tune=1000, cores=2, random_seed=42)

# Resumen del posterior
print(az.summary(trace, var_names=['alpha', 'beta', 'sigma']))
#         mean    sd  hdi_3%  hdi_97%
# alpha  1.02  0.05    0.93     1.11   ← ¡Cerca de 1.0!
# beta   2.48  0.05    2.39     2.57   ← ¡Cerca de 2.5!
# sigma  0.50  0.04    0.44     0.57   ← ¡Cerca de 0.5!

# Visualizar posteriors
az.plot_posterior(trace, var_names=['alpha', 'beta'])

Código Python: BNN completa con PyTorch

Aquí tienes un ejemplo completo de una red neuronal bayesiana entrenada con Bayes by Backprop para clasificación en el dataset Iris.

import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# ── Datos ──
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
scaler = StandardScaler().fit(X_train)
X_train = torch.tensor(scaler.transform(X_train), dtype=torch.float32)
X_test = torch.tensor(scaler.transform(X_test), dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.long)
y_test = torch.tensor(y_test, dtype=torch.long)

# ── Capa bayesiana ──
class BayesianLinear(nn.Module):
    def __init__(self, in_f, out_f):
        super().__init__()
        self.w_mu = nn.Parameter(torch.randn(out_f, in_f) * 0.1)
        self.w_rho = nn.Parameter(torch.full((out_f, in_f), -3.0))
        self.b_mu = nn.Parameter(torch.zeros(out_f))
        self.b_rho = nn.Parameter(torch.full((out_f,), -3.0))

    def forward(self, x):
        w_sig = F.softplus(self.w_rho)
        b_sig = F.softplus(self.b_rho)
        w = self.w_mu + w_sig * torch.randn_like(w_sig)
        b = self.b_mu + b_sig * torch.randn_like(b_sig)
        self.kl = 0.5 * (w_sig.pow(2) + self.w_mu.pow(2) - 1 - 2*w_sig.log()).sum() + \
                  0.5 * (b_sig.pow(2) + self.b_mu.pow(2) - 1 - 2*b_sig.log()).sum()
        return F.linear(x, w, b)

# ── Modelo ──
class BNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.l1 = BayesianLinear(4, 32)
        self.l2 = BayesianLinear(32, 16)
        self.l3 = BayesianLinear(16, 3)

    def forward(self, x):
        x = F.relu(self.l1(x))
        x = F.relu(self.l2(x))
        return self.l3(x)

    def kl(self):
        return self.l1.kl + self.l2.kl + self.l3.kl

# ── Entrenamiento ──
model = BNN()
opt = torch.optim.Adam(model.parameters(), lr=1e-3)

for epoch in range(500):
    logits = model(X_train)
    nll = F.cross_entropy(logits, y_train)
    kl = model.kl() / len(X_train)
    loss = nll + kl
    opt.zero_grad(); loss.backward(); opt.step()

# ── Predicción bayesiana (múltiples muestras) ──
T = 100
model.train()
preds = torch.stack([F.softmax(model(X_test), dim=-1) for _ in range(T)])
mean_probs = preds.mean(dim=0)
uncertainty = preds.std(dim=0).mean(dim=-1)  # Incertidumbre por muestra

predicted = mean_probs.argmax(dim=-1)
accuracy = (predicted == y_test).float().mean()
print(f"Accuracy: {accuracy:.1%}")
print(f"Incertidumbre media: {uncertainty.mean():.4f}")

Aplicaciones reales de redes bayesianas

🏥
Medicina
Diagnóstico médico, predicción de enfermedades, ensayos clínicos. BNs modelan relaciones causales entre síntomas y patologías.
🚗
Conducción autónoma
BNNs cuantifican incertidumbre en percepción. «No estoy seguro de si eso es un peatón → frenar por precaución».
🛡️
Ciberseguridad
Detección de intrusiones, análisis de riesgo. BNs modelan cadenas de ataque y propagan evidencia de alertas.
🌍
Medio ambiente
Modelado de ecosistemas, predicción de contaminación, gestión de recursos hídricos con incertidumbre.
🏭
Industria
Mantenimiento predictivo, control de calidad, análisis de fallos. BNs modelan cascadas de fallos en sistemas complejos.
💰
Finanzas
Modelado de riesgo crediticio, detección de fraude, portfolio optimization con incertidumbre bayesiana.
🧬
Genómica
Redes de regulación génica, GWAS (genome-wide association), descubrimiento de interacciones gen-gen.
🤖
Robótica
SLAM probabilístico, fusión de sensores, planificación bajo incertidumbre (POMDP como extensión de BN).

Las redes bayesianas se complementan con muchas otras técnicas de machine learning. Para aplicaciones de series temporales con componente probabilístico, las redes recurrentes (LSTM/GRU) pueden combinarse con priors bayesianos. En problemas de clasificación con datos tabulares, el Naive Bayes sigue siendo competitivo frente a métodos más complejos. Para optimización de hiperparámetros, la Optimización Bayesiana usa Gaussian Processes (una extensión continua de las BNs) para explorar el espacio de hiperparámetros de forma eficiente.

El sistema QMR-DT (Quick Medical Reference - Decision Theoretic) usaba una red bayesiana con ~600 enfermedades y ~4000 síntomas para asistir en diagnóstico médico.

¿Cómo funciona? El médico introduce los síntomas observados como evidencia. La BN calcula la probabilidad posterior de cada enfermedad. Se presenta un ranking de diagnósticos más probables.

Ventajas sobre otros enfoques:

  • Transparencia: el médico puede inspeccionar las relaciones causales
  • Incertidumbre: cuantifica la confianza en cada diagnóstico
  • Datos parciales: funciona con síntomas incompletos
Shwe, M.A. et al. (1991). Probabilistic diagnosis using a reformulation of the INTERNIST-1/QMR knowledge base. Methods of Information in Medicine.

Las BNNs son ideales para active learning: seleccionar los datos más informativos para etiquetar. La estrategia BALD (Bayesian Active Learning by Disagreement) selecciona las muestras donde el modelo tiene mayor incertidumbre epistémica.

$$\text{BALD}(x) = H[y \mid x, D] - \mathbb{E}_{p(w \mid D)}[H[y \mid x, w]]$$

Puntos con alto BALD: el modelo es incierto Y los diferentes pesos predicen cosas muy diferentes → etiquetar este punto maximiza la información ganada.

Houlsby, N. et al. (2011). Bayesian Active Learning for Classification and Preference Learning. arXiv:1112.5745.

Frameworks y herramientas

HerramientaTipoLenguajeUso principal
pgmpy BN clásica Python Definir, inferir, aprender estructura de BNs discretas
PyMC Modelado bayesiano Python MCMC (NUTS), VI, modelos jerárquicos, BNNs
NumPyro Modelado bayesiano Python (JAX) MCMC/VI ultrarrápido con aceleración JAX/GPU
Pyro Probabilístico profundo Python (PyTorch) BNNs, VAEs, modelos generativos, SVI
TF Probability Probabilístico profundo Python (TF) Capas bayesianas, VI, modelos probabilísticos en TF
bnlearn BN clásica R (y Python wrapper) Aprendizaje de estructura, referencia en investigación

Papers y recursos fundamentales

📚 Papers esenciales

  1. Pearl, J. (1988). Probabilistic Reasoning in Intelligent Systems. Morgan Kaufmann. El libro fundacional de las redes bayesianas.
  2. Pearl, J. (2009). Causality: Models, Reasoning, and Inference. Cambridge University Press. Fundamentos de causalidad y do-calculus.
  3. Koller, D. & Friedman, N. (2009). Probabilistic Graphical Models. MIT Press. El textbook definitivo de modelos gráficos (1200+ páginas).
  4. Gal, Y. & Ghahramani, Z. (2016). Dropout as a Bayesian Approximation. ICML. [arXiv] MC Dropout como inferencia bayesiana aproximada.
  5. Blundell, C. et al. (2015). Weight Uncertainty in Neural Networks. ICML. [arXiv] Bayes by Backprop: VI para BNNs.
  6. Lakshminarayanan, B. et al. (2017). Simple and Scalable Predictive Uncertainty Estimation using Deep Ensembles. NeurIPS. [arXiv] Deep Ensembles como baseline de incertidumbre.
  7. Kingma, D.P. & Welling, M. (2014). Auto-Encoding Variational Bayes. ICLR. [arXiv] El paper del VAE: inferencia variacional + deep learning.
  8. Spirtes, P. et al. (1993). Causation, Prediction, and Search. Springer. Algoritmo PC y descubrimiento causal.
  9. Heckerman, D. (1995). A Tutorial on Learning with Bayesian Networks. Microsoft Research. [arXiv] Tutorial clásico de aprendizaje en BNs.
  10. Murphy, K.P. (2012). Machine Learning: A Probabilistic Perspective. MIT Press. Textbook completo con amplia cobertura de métodos bayesianos.
  11. Wilson, A.G. & Izmailov, P. (2020). Bayesian Deep Learning and a Probabilistic Perspective of Generalization. NeurIPS. [arXiv] Perspectiva bayesiana de la generalización en deep learning.

🔗 Recursos de aprendizaje

🧰 ¿Qué herramienta bayesiana necesito?

Responde estas preguntas y te recomendaremos la herramienta adecuada.