Algoritmo de Normalización de Vectores en Python
La normalización de vectores es una operación fundamental en ciencia de datos, aprendizaje automático y gráficos por computadora. Este artículo explica el concepto, muestra implementaciones eficientes en Python con NumPy y PyTorch, y brinda buenas prácticas para evitar errores comunes.
1. ¿Qué significa normalizar un vector?
Normalizar un vector consiste en transformarlo para que su norma (o longitud) sea 1, manteniendo su dirección original. La norma más usada es la L2 (euclídea):
\|v\|_2 = \sqrt{\sum_{i=1}^{n} v_i^2}
El vector normalizado v̂ se calcula como:
\hat{v} = \frac{v}{\|v\|_2}
Existen otras normas (L1, L∞) que se utilizan en contextos específicos; se comparan en la tabla de la sección 2.2.
2. Implementación paso a paso
2.1. Versión básica con bucle for
import math
def normalize_vector(v):
norm = math.sqrt(sum(x * x for x in v))
if norm == 0:
raise ValueError("No se puede normalizar el vector cero")
return [x / norm for x in v]
print(normalize_vector([3, 4])) # → [0.6, 0.8]
Esta versión es fácil de entender, pero poco eficiente para vectores grandes o lotes de datos.
2.2. Versión vectorizada con NumPy (recomendado)
import numpy as np
def normalize_numpy(v, eps=1e-12):
v = np.asarray(v, dtype=np.float64)
norm = np.linalg.norm(v, axis=-1, keepdims=True)
# Evita división por cero
norm = np.maximum(norm, eps)
return v / norm
# Ejemplo simple
v = np.array([3.0, 4.0])
print(normalize_numpy(v)) # → [0.6 0.8]
Usar np.linalg.norm aprovecha BLAS/LAPACK y es mucho más rápido.
2.3. Normalización de un lote (batch) de vectores
batch = np.random.rand(1000, 128) # 1000 vectores de 128 dimensiones
norm_batch = np.linalg.norm(batch, axis=1, keepdims=True)
norm_batch = np.maximum(norm_batch, 1e-12)
batch_normalized = batch / norm_batch
print(batch_normalized.shape) # (1000, 128)
3. Comparativa de normas (L1, L2, L∞)
L2 (Euclídea)
- Preserva la geometría euclídea.
- Usada en SVM, redes neuronales, k‑NN.
- Computacionalmente más costosa que L1.
L1 (Manhattan)
- Sumatoria de valores absolutos.
- Robusta a outliers, útil en regularización Lasso.
- Fácil de calcular:
np.sum(np.abs(v)).
L∞ (Máximo)
- Valor absoluto máximo del vector.
- Usada en normalización de imágenes (pixel max).
- Rápida pero menos informativa para vectores de alta dimensión.
4. Casos de uso reales
4.1. Pre‑procesamiento de datos para clustering
Antes de aplicar KMeans es habitual escalar cada punto a longitud 1, de modo que la distancia angular sea la métrica dominante.
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
X, _ = make_blobs(n_samples=500, centers=5, n_features=20, random_state=42)
X_norm = normalize_numpy(X)
model = KMeans(n_clusters=5, random_state=0).fit(X_norm)
print("Inertia:", model.inertia_)
4.2. Embeddings de palabras con spaCy o FastText
Los embeddings ya vienen normalizados, pero si se cargan sin ello, la normalización L2 permite usar similitud coseno directamente.
4.3. Redes neuronales con PyTorch
import torch
def normalize_torch(tensor, eps=1e-12):
norm = torch.norm(tensor, p=2, dim=-1, keepdim=True)
norm = torch.clamp(norm, min=eps)
return tensor / norm
x = torch.randn(32, 128) # batch de 32 vectores
x_norm = normalize_torch(x)
print(x_norm.shape) # torch.Size([32, 128])
5. Rendimiento y optimizaciones
- Vectorización: siempre prefiera
numpyotorchen lugar de bucles Python. - Uso de
float32: suficiente para la mayoría de los modelos ML y reduce el consumo de memoria. - Operaciones en‑lote: normalizar matrices completas evita overhead de llamadas repetidas.
- Paralelismo: con
numbaocupyse pueden acelerar aún más en GPU.
Ejemplo de benchmark rápido (solo para ilustrar):
import time, numpy as np
N = 10_000_000
v = np.random.rand(N)
start = time.time()
norm = np.linalg.norm(v)
res = v / max(norm, 1e-12)
print('Tiempo:', time.time() - start)
6. Troubleshooting y mejores prácticas
6.1. División por cero
El vector cero no tiene dirección; la solución típica es lanzar una excepción o devolver un vector de ceros. Utilice un eps pequeño para evitar NaNs:
norm = np.maximum(np.linalg.norm(v), 1e-12)
6.2. Propagación de NaN o Inf
Compruebe la presencia de valores no finitos antes de la normalización:
if not np.isfinite(v).all():
raise ValueError('El vector contiene NaN o Inf')
6.3. Compatibilidad de versiones
- Python ≥ 3.8
- NumPy ≥ 1.20 (para
np.linalg.normconaxisykeepdims) - PyTorch ≥ 1.9 (si se usa GPU)
7. Conclusión
La normalización de vectores es una herramienta esencial que, cuando se implementa con NumPy o PyTorch, combina precisión matemática y alto rendimiento. Siguiendo las mejores prácticas descritas —uso de epsilon, vectorización y control de valores extremos—, podrás integrar este algoritmo sin fricciones en pipelines de datos, modelos de Machine Learning y aplicaciones de gráficos por computadora.
Algoritmo de Normalización de Vectores en Python: Guía Completa con Ejemplos Prácticos