Inteligencia Artificial 9 min de lectura 01 Mar 2026

Embeddings con Python: Introducción y Aplicación Práctica

Los embeddings son una de las ideas más poderosas de la inteligencia artificial moderna. En esencia, un embedding es una representación numérica de datos (texto, imágenes, audio) en un espacio vectorial de alta dimensión, donde las relaciones semánticas se preservan como relaciones geométricas. En este artículo aprenderás qué son los embeddings, la matemática detrás de ellos, y cómo usarlos en Python con aplicaciones prácticas como búsqueda semántica y clasificación de texto.

¿Qué es un Embedding?

Un embedding es una función que mapea un objeto discreto (una palabra, una oración, un documento) a un vector de números reales en un espacio de dimensión \( d \):

\[ f: \text{Objeto} \rightarrow \mathbb{R}^d \]

Por ejemplo, la palabra "gato" podría mapearse al vector \( [0.23, -0.45, 0.89, \ldots] \) de 1536 dimensiones. Lo fascinante es que en este espacio vectorial, las palabras con significados similares quedan cerca entre sí:

  • \( \text{embedding}(\text{"gato"}) \approx \text{embedding}(\text{"felino"}) \) — vectores cercanos
  • \( \text{embedding}(\text{"gato"}) \neq \text{embedding}(\text{"automóvil"}) \) — vectores lejanos

Esta propiedad se resume en la famosa frase de la lingüística computacional: "Conocerás una palabra por la compañía que mantiene" (J.R. Firth, 1957).

La Matemática detrás de los Embeddings

Espacios Vectoriales y Similitud

Los embeddings viven en un espacio vectorial \( \mathbb{R}^d \), donde \( d \) es la dimensionalidad del embedding (típicamente entre 100 y 3072 dimensiones). Para medir qué tan "parecidos" son dos embeddings, usamos la similitud coseno:

\[ \text{sim}(\mathbf{a}, \mathbf{b}) = \cos(\theta) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \, \|\mathbf{b}\|} = \frac{\sum_{i=1}^{d} a_i b_i}{\sqrt{\sum_{i=1}^{d} a_i^2} \cdot \sqrt{\sum_{i=1}^{d} b_i^2}} \]

El resultado es un valor entre -1 y 1:

Valor Interpretación Ejemplo
\( \approx 1 \) Muy similares (misma dirección) "perro" vs "cachorro"
\( \approx 0 \) Sin relación (ortogonales) "perro" vs "contabilidad"
\( \approx -1 \) Opuestos semánticos "bueno" vs "malo" (en algunos modelos)

Aritmética de Vectores Semánticos

Uno de los descubrimientos más sorprendentes de Word2Vec (Mikolov et al., 2013) fue que los embeddings capturan relaciones analógicas mediante operaciones vectoriales:

\[ \text{embedding}(\text{"rey"}) - \text{embedding}(\text{"hombre"}) + \text{embedding}(\text{"mujer"}) \approx \text{embedding}(\text{"reina"}) \]

Esto demuestra que los embeddings no solo capturan similitud, sino que codifican relaciones semánticas estructuradas como género, tiempo verbal, relaciones geográficas (país-capital), y más.

Tipos de Embeddings

La evolución de los embeddings ha sido rápida. Aquí un resumen de las principales técnicas:

Técnica Año Dimensiones Características
Word2Vec 2013 100-300 Embeddings por palabra, CBOW y Skip-gram
GloVe 2014 50-300 Factorización de matriz de co-ocurrencia
FastText 2016 100-300 Sub-palabras, maneja palabras desconocidas
BERT 2018 768 Contextuales, bidireccionales
Sentence-BERT 2019 384-768 Optimizados para oraciones completas
OpenAI text-embedding-3 2024 256-3072 Estado del arte, API cloud

Tip: Los embeddings modernos como los de OpenAI o Sentence-BERT generan vectores para oraciones completas, no solo palabras individuales. Esto los hace mucho más útiles para aplicaciones reales como búsqueda semántica y RAG (Retrieval-Augmented Generation).

Embeddings en Python: Implementación Práctica

Opción 1: Sentence-Transformers (Local, Gratuito)

La librería sentence-transformers permite generar embeddings de alta calidad localmente, sin depender de APIs externas:

from sentence_transformers import SentenceTransformer
import numpy as np

# Cargar modelo pre-entrenado (se descarga la primera vez ~90MB)
modelo = SentenceTransformer('all-MiniLM-L6-v2')

# Textos de ejemplo
textos = [
    "Python es un lenguaje de programación versátil",
    "La serpiente pitón es un reptil grande",
    "JavaScript se usa para desarrollo web",
    "Django es un framework web de Python",
    "Los reptiles son animales de sangre fría"
]

# Generar embeddings
embeddings = modelo.encode(textos)

print(f"Forma de los embeddings: {embeddings.shape}")
# Output: (5, 384) → 5 textos, 384 dimensiones cada uno

# Calcular similitud coseno entre todos los pares
from sklearn.metrics.pairwise import cosine_similarity

similitudes = cosine_similarity(embeddings)

print("\nMatriz de similitud:")
for i, texto_i in enumerate(textos):
    for j, texto_j in enumerate(textos):
        if j > i:
            print(f"  {similitudes[i][j]:.3f} | '{texto_i[:40]}' ↔ '{texto_j[:40]}'")

En este ejemplo verás que "Python es un lenguaje..." y "Django es un framework web de Python" tendrán alta similitud, mientras que "La serpiente pitón..." estará más cerca de "Los reptiles son animales...".

Opción 2: API de OpenAI

Si necesitas embeddings de máxima calidad y no te importa el costo (es muy económico), la API de OpenAI es excelente:

from openai import OpenAI
import numpy as np

client = OpenAI()  # Usa OPENAI_API_KEY del entorno

def obtener_embedding(texto, modelo="text-embedding-3-small"):
    """Obtiene el embedding de un texto usando la API de OpenAI."""
    respuesta = client.embeddings.create(
        input=texto,
        model=modelo
    )
    return np.array(respuesta.data[0].embedding)

# Generar embeddings
textos = [
    "¿Cómo instalar Python en Windows?",
    "Tutorial de instalación de Python para principiantes",
    "Receta de pastel de chocolate",
    "Guía para configurar un entorno de desarrollo Python"
]

embeddings = [obtener_embedding(t) for t in textos]

print(f"Dimensiones: {len(embeddings[0])}")
# Output: 1536 (text-embedding-3-small)

# Similitud coseno manual
def similitud_coseno(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# Comparar el primer texto con todos los demás
consulta = textos[0]
print(f"\nConsulta: '{consulta}'")
for i, texto in enumerate(textos[1:], 1):
    sim = similitud_coseno(embeddings[0], embeddings[i])
    print(f"  {sim:.4f} → '{texto}'")

Aplicación Práctica: Búsqueda Semántica

La aplicación más común de los embeddings es la búsqueda semántica: encontrar documentos relevantes no por coincidencia exacta de palabras, sino por significado. A diferencia de una búsqueda por keywords, la búsqueda semántica entiende que "cómo resolver errores en código" es similar a "debugging y depuración de programas".

from sentence_transformers import SentenceTransformer
import numpy as np

modelo = SentenceTransformer('all-MiniLM-L6-v2')

# Base de conocimiento (simulando artículos de un blog)
articulos = [
    {"titulo": "Guía de Pandas para análisis de datos",
     "contenido": "Pandas es la librería principal para manipulación de datos tabulares en Python. Permite leer CSV, filtrar datos y crear gráficas."},
    {"titulo": "Introducción a Machine Learning",
     "contenido": "El aprendizaje automático permite a las computadoras aprender patrones a partir de datos sin ser programadas explícitamente."},
    {"titulo": "Django REST Framework tutorial",
     "contenido": "Aprende a crear APIs REST con Django. Incluye serializers, viewsets, autenticación por tokens y permisos."},
    {"titulo": "Redes neuronales desde cero",
     "contenido": "Las redes neuronales son modelos inspirados en el cerebro humano, compuestos por capas de neuronas artificiales con pesos y sesgos."},
    {"titulo": "Web scraping con BeautifulSoup",
     "contenido": "Extrae datos de páginas web usando Python. BeautifulSoup parsea HTML y permite navegar el DOM con selectores CSS."},
    {"titulo": "Visualización de datos con Matplotlib",
     "contenido": "Crea gráficas profesionales en Python. Matplotlib permite generar gráficos de barras, líneas, dispersión y más."},
]

# Pre-calcular embeddings de los artículos
textos_articulos = [f"{a['titulo']}. {a['contenido']}" for a in articulos]
embeddings_articulos = modelo.encode(textos_articulos)

def buscar(consulta, top_k=3):
    """Búsqueda semántica: encuentra los artículos más relevantes."""
    embedding_consulta = modelo.encode([consulta])[0]

    # Calcular similitud coseno con todos los artículos
    similitudes = np.dot(embeddings_articulos, embedding_consulta) / (
        np.linalg.norm(embeddings_articulos, axis=1) * np.linalg.norm(embedding_consulta)
    )

    # Ordenar por similitud descendente
    indices = np.argsort(similitudes)[::-1][:top_k]

    print(f"Búsqueda: '{consulta}'\n")
    for idx in indices:
        print(f"  [{similitudes[idx]:.3f}] {articulos[idx]['titulo']}")
    print()

# Ejemplos de búsqueda semántica
buscar("quiero aprender a trabajar con tablas y datos")
buscar("cómo hacer inteligencia artificial")
buscar("necesito extraer información de internet")
buscar("crear un backend con Python")

Tip: En producción, no calculas similitudes comparando contra todos los vectores. Usas bases de datos vectoriales como Pinecone, ChromaDB, Qdrant o pgvector (PostgreSQL) que optimizan la búsqueda con índices como HNSW o IVF.

Aplicación Práctica: Clasificación de Texto

Otra aplicación poderosa es usar embeddings como features para clasificación. En lugar de usar TF-IDF o bag-of-words, representas cada texto como su embedding y entrenas un clasificador simple encima:

from sentence_transformers import SentenceTransformer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import numpy as np

modelo = SentenceTransformer('all-MiniLM-L6-v2')

# Dataset de ejemplo: clasificar preguntas por categoría
datos = [
    ("¿Cómo instalar NumPy?", "python"),
    ("¿Qué es un DataFrame?", "python"),
    ("¿Cómo crear una lista en Python?", "python"),
    ("¿Para qué sirve pip?", "python"),
    ("Explica las funciones lambda", "python"),
    ("¿Qué es una red neuronal?", "ia"),
    ("¿Cómo funciona GPT?", "ia"),
    ("Diferencia entre supervised y unsupervised", "ia"),
    ("¿Qué es transfer learning?", "ia"),
    ("¿Cómo entrenar un modelo de clasificación?", "ia"),
    ("¿Cómo hacer un SELECT en SQL?", "datos"),
    ("¿Qué es un JOIN?", "datos"),
    ("Diferencia entre SQL y NoSQL", "datos"),
    ("¿Cómo conectar Python a PostgreSQL?", "datos"),
    ("¿Qué es un índice en base de datos?", "datos"),
]

textos = [d[0] for d in datos]
etiquetas = [d[1] for d in datos]

# Generar embeddings
embeddings = modelo.encode(textos)

# Entrenar clasificador
X_train, X_test, y_train, y_test = train_test_split(
    embeddings, etiquetas, test_size=0.3, random_state=42
)

clf = LogisticRegression(max_iter=1000)
clf.fit(X_train, y_train)

# Evaluar
print(classification_report(y_test, clf.predict(X_test)))

# Probar con textos nuevos
nuevas_preguntas = [
    "¿Cómo usar decoradores en Python?",
    "Explica el algoritmo de backpropagation",
    "¿Cómo crear una tabla en MySQL?"
]

nuevos_embeddings = modelo.encode(nuevas_preguntas)
predicciones = clf.predict(nuevos_embeddings)

for pregunta, pred in zip(nuevas_preguntas, predicciones):
    print(f"  '{pregunta}' → {pred}")

Visualización de Embeddings

Los embeddings tienen cientos de dimensiones, pero podemos proyectarlos a 2D para visualizarlos usando técnicas como t-SNE o UMAP:

from sentence_transformers import SentenceTransformer
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
import numpy as np

modelo = SentenceTransformer('all-MiniLM-L6-v2')

# Palabras agrupadas por categoría
palabras = {
    'Programación': ['Python', 'JavaScript', 'función', 'variable', 'algoritmo', 'compilador'],
    'Cocina': ['receta', 'horno', 'ingredientes', 'sartén', 'cocinar', 'chef'],
    'Deportes': ['fútbol', 'gol', 'cancha', 'jugador', 'entrenamiento', 'torneo'],
}

textos = []
colores = []
color_map = {'Programación': 'blue', 'Cocina': 'red', 'Deportes': 'green'}

for categoria, lista in palabras.items():
    textos.extend(lista)
    colores.extend([color_map[categoria]] * len(lista))

# Generar embeddings y reducir a 2D
embeddings = modelo.encode(textos)
tsne = TSNE(n_components=2, random_state=42, perplexity=5)
coords = tsne.fit_transform(embeddings)

# Graficar
plt.figure(figsize=(10, 8))
for categoria, color in color_map.items():
    mask = [c == color for c in colores]
    plt.scatter(coords[mask, 0], coords[mask, 1], c=color, label=categoria, s=100)

for i, texto in enumerate(textos):
    plt.annotate(texto, (coords[i, 0], coords[i, 1]), fontsize=9, ha='center', va='bottom')

plt.legend(fontsize=12)
plt.title('Visualización t-SNE de Embeddings')
plt.tight_layout()
plt.savefig('embeddings_tsne.png', dpi=150)
plt.show()

En la visualización resultante verás que las palabras se agrupan naturalmente por su campo semántico: las de programación formarán un cluster, las de cocina otro, y las de deportes otro.

Consideraciones Prácticas

Al trabajar con embeddings en proyectos reales, ten en cuenta estos aspectos:

  • Dimensionalidad vs costo: Más dimensiones capturan más matices pero requieren más almacenamiento y cómputo. Para la mayoría de aplicaciones, 384 dimensiones (MiniLM) son suficientes.
  • Normalización: Muchos modelos ya devuelven embeddings normalizados (\( \|\mathbf{v}\| = 1 \)). En ese caso, la similitud coseno se simplifica a un producto punto: \( \text{sim}(\mathbf{a}, \mathbf{b}) = \mathbf{a} \cdot \mathbf{b} \)
  • Batching: Siempre genera embeddings en lotes, no uno por uno. Es significativamente más rápido.
  • Caché: Los embeddings son determinísticos para un modelo dado. Guárdalos en una base de datos para no recalcularlos.
  • Modelo según idioma: Para español, considera modelos multilingües como paraphrase-multilingual-MiniLM-L12-v2 o los embeddings de OpenAI que soportan español nativamente.

Conclusión

Los embeddings son la piedra angular de la inteligencia artificial moderna para procesamiento de lenguaje natural. Transforman texto en vectores numéricos donde la proximidad geométrica refleja similitud semántica, lo que habilita aplicaciones como búsqueda semántica, clasificación de texto, sistemas de recomendación y RAG.

En este artículo cubrimos:

  • La definición matemática de embeddings como funciones \( f: \text{Objeto} \rightarrow \mathbb{R}^d \)
  • La similitud coseno como métrica fundamental para comparar vectores
  • La evolución desde Word2Vec hasta los modelos modernos como OpenAI text-embedding-3
  • Implementación práctica con Sentence-Transformers (local y gratuito) y la API de OpenAI
  • Aplicaciones concretas: búsqueda semántica, clasificación de texto y visualización con t-SNE
  • Consideraciones prácticas sobre dimensionalidad, normalización y caché

Con estas herramientas y conceptos puedes empezar a integrar embeddings en tus proyectos de Python. Te recomendamos como siguiente paso explorar las bases de datos vectoriales (ChromaDB, pgvector) para llevar la búsqueda semántica a escala de producción.