Algoritmos para Resolver Sistemas Subdeterminados y Sobredeterminados en Python
Introducción
En el análisis numérico, los sistemas lineales pueden presentarse con distintas relaciones entre el número de ecuaciones (m) y el número de incógnitas (n) :
- Sobredeterminados (m > n): más ecuaciones que variables.
- Subdeterminados (m < n): menos ecuaciones que variables.
Ambos casos requieren técnicas específicas para obtener soluciones útiles, ya sea una solución exacta, una solución de mínimos cuadrados o una familia de soluciones infinitas.
Comparativa rápida
Sobredeterminados (m > n)
- Generalmente no tienen solución exacta.
- Se busca la solución de mínimos cuadrados que minimiza \(\|Ax-b\|_2\).
- Se utilizan métodos como
numpy.linalg.lstsq, descomposición QR o SVD. - Aplicaciones: regresión lineal, ajuste de datos, calibración de sensores.
Subdeterminados (m < n)
- Infinitas soluciones exactas (espacio nulo no trivial).
- Se busca la solución de norma mínima (pseudoinversa de Moore‑Penrose).
- Se emplean
numpy.linalg.pinvo SVD para obtener la solución más “simple”. - Aplicaciones: compresión de datos, problemas de interpolación, redes neuronales con menos muestras que parámetros.
Métodos numéricos recomendados
Los siguientes algoritmos cubren tanto casos sobredeterminados como subdeterminados y son compatibles con numpy y scipy:
- Least Squares (Mínimos cuadrados) –
numpy.linalg.lstsqoscipy.linalg.lstsq. - Pseudoinversa (Moore‑Penrose) –
numpy.linalg.pinv. - Descomposición QR – estable y eficiente para m ≥ n.
- Descomposición SVD – la más robusta frente a matrices mal condicionadas; también permite truncamiento para regularización.
En entornos de alta performance, scipy.sparse.linalg ofrece versiones esparcidas de estos algoritmos.
Ejemplos prácticos en Python
1️⃣ Sistema sobredeterminado – regresión lineal simple
import numpy as np
# Datos (m=6 ecuaciones, n=2 incógnitas)
A = np.array([[1, 1],
[1, 2],
[1, 3],
[1, 4],
[1, 5],
[1, 6]], dtype=float)
b = np.array([2, 3, 5, 7, 11, 13], dtype=float) # valores observados
# Solución de mínimos cuadrados
x, residuals, rank, s = np.linalg.lstsq(A, b, rcond=None)
print('Coeficientes (intercepto, pendiente):', x)
print('Residuos:', residuals)
Salida típica:
Coeficientes (intercepto, pendiente): [0.42857143 2.05714286] Residuos: [0.85714286]
2️⃣ Sistema subdeterminados – interpolación lineal con más variables que ecuaciones
import numpy as np
# Matriz 2x4 (m=2, n=4)
A = np.array([[1, 0, 2, -1],
[0, 1, -1, 2]], dtype=float)
b = np.array([3, 4], dtype=float)
# Solución de norma mínima usando pseudoinversa
x = np.linalg.pinv(A) @ b
print('Solución de norma mínima:', x)
Resultado (una de infinitas soluciones):
Solución de norma mínima: [ 2.2 4.8 -0.2 0.6]
3️⃣ Uso de SVD para regularización (Tikhonov) en sistemas mal condicionados
import numpy as np
from numpy.linalg import svd
A = np.array([[1, 1], [1, 1.0001]])
b = np.array([2, 2.0001])
U, s, VT = svd(A, full_matrices=False)
# Truncamiento de valores singulares pequeños (ej. < 1e-4)
threshold = 1e-4
s_inv = np.array([1/si if si > threshold else 0 for si in s])
A_pinv = VT.T @ np.diag(s_inv) @ U.T
x = A_pinv @ b
print('Solución regularizada:', x)
Este enfoque evita la explosión de errores numéricos cuando A es casi singular.
Buenas prácticas y optimización
- Escalado de columnas: normalizar las columnas de
Areduce la condición numérica. - Elección del algoritmo:
- Para m ≈ n y matrices bien condicionadas,
lstsqes suficiente. - Para matrices esparcidas, use
scipy.sparse.linalg.lsmrolsqr. - Cuando la precisión es crítica, prefiera SVD con truncamiento.
- Para m ≈ n y matrices bien condicionadas,
- Control de tolerancia: ajuste
rcondenlstsqpara evitar que valores singulares menores a la tolerancia sean descartados. - Validación de resultados: siempre compruebe
np.allclose(A @ x, b)o analice los residuos.
Ejemplo de validación:
assert np.allclose(A @ x, b, atol=1e-8), "La solución no satisface el sistema"
Resolución de problemas comunes
| Problema | Causa típica | Solución recomendada |
|---|---|---|
| Residuos muy altos | Modelo no lineal o datos con ruido excesivo | Considerar regresión polinómica o regularización (Ridge, Lasso) |
| SingularMatrixError | Colinealidad fuerte entre columnas | Eliminar columnas redundantes o usar SVD con truncamiento |
| Resultado NaN/Inf | Escala de datos muy dispar | Normalizar/estandarizar antes de la solución |
| Rendimiento lento con matrices grandes | Uso de algoritmos densos | Convertir a scipy.sparse.csr_matrix y usar lsmr o cg |
Compatibilidad, rendimiento y escalabilidad
Los métodos presentados son compatibles con:
- Python 3.9+ (recomendado 3.11).
- NumPy ≥ 1.24 y SciPy ≥ 1.10.
- Entornos de CPU multi‑core (BLAS/MKL acelera
lstsqy SVD). - GPU: bibliotecas como
cupyreplican la API de NumPy y permitencupy.linalg.lstsqen GPUs NVIDIA.
Para sistemas con millones de ecuaciones, la estrategia típica es:
- Convertir
Aa formato esparcido (csr_matrix). - Aplicar
scipy.sparse.linalg.lsmrocgcon precondicionador. - Dividir el problema en bloques y usar
dask.arraypara paralelismo distribuido.
Conclusión
Los sistemas subdeterminados y sobredeterminados son omnipresentes en ciencia de datos, ingeniería y aprendizaje automático. Elegir el algoritmo adecuado – least squares, pseudoinversa, QR o SVD – impacta directamente en la precisión, la estabilidad numérica y el rendimiento.
Con las herramientas de NumPy y SciPy junto a buenas prácticas de escalado, validación y manejo de errores, es posible construir soluciones robustas, escalables y listas para producción.
Algoritmos para Resolver Sistemas Subdeterminados y Sobredeterminados en Python