Introducción
El Laplaciano de un grafo es una matriz que captura la conectividad estructural de una red. Se utiliza en áreas como clustering espectral, segmentación de imágenes, optimización de redes y machine learning sobre grafos. En este artículo explicaremos su definición matemática, propiedades clave y cómo calcularlo de forma eficiente en Python.
Definiciones fundamentales
- Matriz de adyacencia (A):
A_{ij}=1si existe una arista entre los vértices i y j, 0 en caso contrario. - Matriz de grado (D): matriz diagonal donde
D_{ii}=\sum_j A_{ij}, es decir, el grado del vértice i. - Laplaciano no normalizado (L):
L = D - A. - Laplaciano normalizado (L_{sym}):
L_{sym}= I - D^{-1/2} A D^{-1/2}. - Laplaciano de paseo aleatorio (L_{rw}):
L_{rw}= I - D^{-1} A.
Propiedades clave
- Es simétrica y semidefinida positiva (para grafos no dirigidos).
- El menor valor propio es siempre
0. La multiplicidad del 0 corresponde al número de componentes conexos. - Los vectores propios asociados a los valores propios más pequeños revelan la estructura de comunidad del grafo.
Cálculo del Laplaciano en Python
Utilizaremos NetworkX para generar grafos y NumPy/SciPy para operar con matrices densas o esparcidas.
Ejemplo 1: Grafo pequeño (matriz densa)
import networkx as nx
import numpy as np
# Crear un grafo no dirigido simple
G = nx.Graph()
G.add_edges_from([(0,1), (1,2), (2,3), (3,0), (0,2)])
# Matriz de adyacencia y de grado
A = nx.adjacency_matrix(G).todense()
D = np.diag([d for n,d in G.degree()])
# Laplaciano no normalizado
L = D - A
print('Laplaciano L:\n', L)
Ejemplo 2: Grafo grande (matriz esparcida) y Laplaciano normalizado
import networkx as nx
import scipy.sparse as sp
# Generar un grafo aleatorio de Erdos‑Renyi con 10,000 nodos y p=0.001
n = 10000
p = 0.001
G = nx.erdos_renyi_graph(n, p, seed=42)
# Matriz de adyacencia esparcida
A = nx.adjacency_matrix(G) # formato CSR
# Grados como vector
deg = A.sum(axis=1).A1
D_inv_sqrt = sp.diags(1.0/np.sqrt(deg))
# Laplaciano normalizado L_sym = I - D^{-1/2} A D^{-1/2}
I = sp.identity(n, format='csr')
L_sym = I - D_inv_sqrt @ A @ D_inv_sqrt
print('Laplaciano normalizado (esparcido) creado. Shape:', L_sym.shape)
Comparativa de variantes del Laplaciano
Laplaciano no normalizado (L)
- Fácil de interpretar.
- Requiere la matriz de grado completa.
- Escala con el grado máximo del grafo.
- Uso típico en teoría espectral básica.
Laplaciano normalizado (Lsym y Lrw)
- Elimina la dependencia del tamaño del grado.
- Más estable numéricamente para grafos heterogéneos.
- Lsym es simétrico → eigen‑descomposición directa.
- Lrw se interpreta como operador de paseo aleatorio.
Aplicaciones típicas
- Clustering espectral: usar los k menores vectores propios de Lsym como embeddings y aplicar k‑means.
- Detección de comunidades: el valor propio algebraico (Fiedler) indica cuán “cortable” es el grafo.
- Reducción de dimensionalidad en grafos de alta dimensión.
- Simulación de procesos de difusión (p. ej., propagación de información).
Rendimiento y escalabilidad
El cálculo directo de eigen‑valores con matrices densas tiene complejidad O(n³), lo cual es inviable para grafos con millones de nodos. Las estrategias recomendadas son:
- Utilizar matrices esparcidas (SciPy
csr_matrix). - Aplicar algoritmos iterativos como
scipy.sparse.linalg.eigsholobpcgque solo requieren multiplicaciones matriciales. - Emplear GPU con cuGraph para grafos extremadamente grandes.
- Dividir el grafo en sub‑componentes y procesarlos en paralelo (p. ej., con Dask o Ray).
Resolución de problemas comunes (troubleshooting)
- Errores de división por cero al normalizar grados cero. Solución: eliminar nodos aislados o añadir un pequeño epsilon (
1e-10) al denominador. - Memoria insuficiente al convertir una matriz esparcida a densa. Solución: mantener siempre el formato
csry usar funciones esparcidas para eigen‑descomposición. - Convergencia lenta de eigsh. Solución: proporcionar un buen vector de inicio (
v0) o usarwhich='SM'para los menores valores propios.
Buenas prácticas y recomendaciones
- Siempre validar que el grafo sea no dirigido antes de usar el Laplaciano simétrico.
- Preferir el Laplaciano normalizado cuando los grados varían mucho.
- Documentar versiones de librerías (
networkx>=3.0,numpy>=1.26,scipy>=1.12) para reproducibilidad. - Usar tipos de datos
float32en GPUs para reducir consumo de memoria sin perder precisión significativa.