WhatsApp

  

Algoritmo de Matrices Estocásticas en Python: Conceptos, Implementación y Casos Prácticos

Guía completa sobre matrices estocásticas, su teoría, algoritmo de generación y verificación, y ejemplos reales en Python con NumPy y SciPy.

Algoritmo de Matrices Estocásticas en Python

Introducción

Una matriz estocástica (también llamada matriz de probabilidad de transición) es una matriz cuadrada cuyas filas son vectores de probabilidad: todos sus elementos son no negativos y la suma de cada fila es 1. Estas matrices son la base matemática de cadenas de Markov, algoritmos de PageRank, procesos de decisión de Markov y muchos modelos de machine learning.

En este artículo aprenderás:

  • Definiciones y propiedades clave.
  • Cómo generar y validar una matriz estocástica mediante un algoritmo robusto.
  • Ejemplos prácticos en Python usando numpy y scipy.
  • Comparativas con matrices no estocásticas y mejores prácticas de rendimiento.

Definición formal y propiedades esenciales

Sea \(P \in \mathbb{R}^{n\times n}\). Decimos que \(P\) es una matriz estocástica de fila si:

  1. \(p_{ij} \ge 0\) para todo \(i,j\).
  2. \(\sum_{j=1}^{n} p_{ij}=1\) para cada fila \(i\).

Propiedades que se derivan directamente:

  • Conservación de probabilidad: el vector de distribución de probabilidad \(\pi\) satisface \(\pi P = \pi\).
  • Espectro limitado: el valor propio dominante siempre es \(1\) y está asociado a un autovector no negativo.
  • Irreducibilidad y aperiodicidad: garantizan convergencia a una distribución estacionaria única.

Algoritmo para generar y validar matrices estocásticas

El algoritmo siguiente asegura que la matriz resultante cumpla ambas condiciones (no‑negatividad y suma de fila = 1) y permite incluir restricciones opcionales como sparsidad o diagonal dominante.

import numpy as np
def generar_matriz_estocastica(n, sparsity=0.0, seed=None):
    """Genera una matriz estocástica de fila de tamaño *n*.
    Parámetros
    ----------
    n : int
        Dimensión de la matriz cuadrada.
    sparsity : float, opcional (default=0.0)
        Fracción de ceros a introducir (0 = densa, 1 = totalmente cero).
    seed : int, opcional
        Semilla para reproducibilidad.
    """
    rng = np.random.default_rng(seed)
    # Paso 1: generar valores positivos aleatorios
    mat = rng.random((n, n))
    # Paso 2: aplicar sparsity (opcional)
    if sparsity > 0:
        mask = rng.random((n, n)) < sparsity
        mat[mask] = 0.0
    # Paso 3: normalizar filas para que sumen 1
    row_sums = mat.sum(axis=1, keepdims=True)
    # Evitar división por cero (filas totalmente cero)
    row_sums[row_sums == 0] = 1.0
    mat = mat / row_sums
    return mat
def es_estocastica(P, atol=1e-8):
    """Valida que *P* sea una matriz estocástica de fila.
    Devuelve ``True`` si cumple:
    1) todos los elementos >= 0
    2) la suma de cada fila ≈ 1 (tolerancia *atol*)
    """
    if np.any(P < -atol):
        return False
    row_sums = P.sum(axis=1)
    return np.all(np.abs(row_sums - 1) <= atol)

El algoritmo está pensado para escalar a matrices de varios miles de filas, aprovechando numpy y evitando bucles Python.

Comparativa: Matrices Estocásticas vs. Matrices Arbitrarias

Matriz Estocástica
  • Filas suman 1 → conserva probabilidad.
  • Valores no negativos → interpretación como probabilidades.
  • Valor propio dominante = 1 → garantiza existencia de distribución estacionaria.
  • Uso típico: cadenas de Markov, PageRank, modelado de procesos estocásticos.
Matriz Arbitraria
  • Sin restricción de suma de filas → no representa transiciones probabilísticas.
  • Puede contener valores negativos → no interpretable como probabilidad.
  • Valores propios arbitrarios → no hay garantía de convergencia.
  • Aplicaciones genéricas: transformaciones lineales, sistemas de ecuaciones, etc.

Ejemplo 1: Cadena de Markov de 3 estados

Supongamos un proceso que modela el clima: Soleado (S), Nublado (N) y Lluvioso (L). La matriz de transición es:

P = np.array([
    [0.6, 0.3, 0.1],  # S -> S,N,L
    [0.2, 0.5, 0.3],  # N -> S,N,L
    [0.1, 0.4, 0.5]   # L -> S,N,L
])

Calculemos la distribución estacionaria resolviendo \(\pi P = \pi\):

import scipy.linalg as la
# Resolución del sistema (P.T - I) * pi = 0 con condición suma(pi)=1
A = np.vstack([P.T - np.eye(3), np.ones(3)])
b = np.append(np.zeros(3), 1)
pi = la.lstsq(A, b)[0]
print("Distribución estacionaria:", pi)

Resultado típico:

Distribución estacionaria: [0.357, 0.357, 0.286]

Esto indica que, a largo plazo, el 35.7 % de los días será soleado, 35.7 % nublado y 28.6 % lluvioso.

Ejemplo 2: Algoritmo PageRank simplificado

PageRank se basa en una matriz estocástica de transición de un grafo dirigido. A continuación, una versión mínima con 4 páginas:

import numpy as np
def pagerank(P, alpha=0.85, tol=1e-8, max_iter=100):
    n = P.shape[0]
    # Matriz de teletransportación
    E = np.ones((n, n)) / n
    M = alpha * P + (1 - alpha) * E
    r = np.ones(n) / n  # vector de ranking inicial
    for _ in range(max_iter):
        r_next = M.T @ r
        if np.linalg.norm(r_next - r, 1) < tol:
            break
        r = r_next
    return r
# Matriz de enlaces (filas = página origen, columnas = destino)
L = np.array([
    [0, 1, 1, 0],  # Página A enlaza a B y C
    [1, 0, 0, 1],  # Página B enlaza a A y D
    [1, 0, 0, 1],  # Página C enlaza a A y D
    [0, 1, 0, 0]   # Página D enlaza a B
], dtype=float)
# Normalizar filas para que sumen 1 (manejo de dangling nodes opcional)
P = L / L.sum(axis=1, keepdims=True)
rank = pagerank(P)
print("PageRank:", rank)

El vector rank muestra la importancia relativa de cada página según el modelo de salto aleatorio.

Buenas prácticas, seguridad y optimización

  • Validación de entrada: siempre aplicar es_estocastica antes de usar la matriz en algoritmos críticos.
  • Sparsity: para grafos grandes, almacena la matriz en formato CSR/CSC usando scipy.sparse y evita conversiones a densa.
  • Precisión numérica: en matrices muy grandes, la suma de fila puede desviarse ligeramente de 1 por error de punto flotante; usa tolerancias (atol=1e-12) y renormaliza si es necesario.
  • Parallelismo: operaciones de multiplicación matriz‑vector (M.T @ r) pueden paralelizarse con numba o cupy para GPUs.
  • Seguridad: si la matriz proviene de fuentes externas (p. ej., archivos CSV), sanitiza los valores para evitar NaN, inf o negativos que romperían la lógica de probabilidad.

Resolución de problemas comunes

ProblemaCausa típicaSolución recomendada
Filas que no suman 1División por cero al normalizar filas vacíasReemplazar filas cero por distribución uniforme antes de la normalización.
Valores negativosLectura de datos corruptos o uso de funciones que generan números aleatorios con distribución normalAplicar np.clip(P, 0, None) y volver a normalizar.
Convergencia lenta en PageRankValor de alpha demasiado cercano a 1 o matriz muy esparsaReducir alpha (p. ej., 0.85 → 0.80) o usar aceleración de potencia (extrapolación de Anderson).
Desbordamiento de memoriaMatrices densas de > 10⁴ × 10⁴Utilizar scipy.sparse.csr_matrix y operaciones esparsas.

Conclusión

Las matrices estocásticas son una herramienta esencial para modelar procesos probabilísticos. Con el algoritmo presentado puedes generar, validar y emplear estas matrices de forma segura y eficiente en Python, abriendo la puerta a aplicaciones que van desde la simulación de cadenas de Markov hasta algoritmos de ranking web y modelos de aprendizaje automático.

Recuerda siempre validar los datos de entrada, aprovechar estructuras esparsas para escalabilidad y considerar la tolerancia numérica para evitar desviaciones sutiles pero críticas.



Algoritmo de Matrices Estocásticas en Python: Conceptos, Implementación y Casos Prácticos
ASIMOV Ingeniería S. de R.L. de C.V., Emiliano Nava 13 noviembre, 2025
Compartir
Iniciar sesión dejar un comentario

  
Algoritmo de Formas Cuadráticas en Python: Teoría, Implementación y Buenas Prácticas
Guía completa sobre el algoritmo de formas cuadráticas, su base matemática, implementación en Python y casos de uso reales, con ejemplos, comparativas y mejores prácticas.