#02 Clustering semántico de keywords con NLP: cómo lo aplico en proyectos reales

NLPSEOKeywordsPythonData ScienceClustering

Clustering semántico de keywords con NLP: cómo lo aplico en proyectos reales

Uno de los trabajos más tediosos del SEO clásico es el de agrupar keywords. Si alguna vez has tenido que organizar un listado de 2.000 queries en categorías temáticas a mano, sabes de lo que hablo. Acabas con los ojos cuadrados, criterios inconsistentes entre el inicio y el final de la hoja, y la sensación de haber perdido medio día en algo que debería ser más inteligente.

Hace un par de años empecé a resolver esto con clustering semántico usando NLP. No es magia, pero sí cambia bastante cómo trabajo la investigación de keywords. Te cuento el proceso que uso en proyectos reales.

Por qué el clustering por n-grams se queda corto

El enfoque más básico para agrupar keywords es buscar palabras compartidas: si dos queries tienen el mismo término principal, van al mismo grupo. Rápido, fácil, y bastante malo.

El problema es que dos keywords pueden compartir intención sin compartir ni una sola palabra:

  • “cómo bajar de peso rápido”
  • “adelgazar en poco tiempo”

Son la misma intención, pero un agrupador por n-grams las metería en grupos distintos. El NLP, en cambio, trabaja con significado, no con texto literal. Y eso lo cambia todo.

Las herramientas que uso

Para este proceso trabajo habitualmente con estas librerías:

  • sentence-transformers: para convertir cada keyword en un vector semántico (embedding)
  • scikit-learn: para el algoritmo de clustering
  • pandas: para manipular los datos antes y después
  • umap-learn (opcional): para visualizar los clusters en 2D

Si no tienes el entorno preparado, puedes instalarlas así:

pip install sentence-transformers scikit-learn pandas umap-learn

El proceso paso a paso

1. Cargar las keywords

Parto siempre de un CSV con las keywords que quiero agrupar. Puede venir de GSC, de Semrush, de Ahrefs, o de una combinación de varias fuentes. Lo importante es tener una columna con el texto de la query.

import pandas as pd

df = pd.read_csv("keywords.csv")
keywords = df["query"].tolist()

print(f"Total keywords: {len(keywords)}")

2. Generar los embeddings semánticos

Aquí es donde entra el NLP. Uso el modelo paraphrase-multilingual-MiniLM-L12-v2 porque funciona bien con español y es ligero para correr en local sin GPU.

from sentence_transformers import SentenceTransformer

model = SentenceTransformer("paraphrase-multilingual-MiniLM-L12-v2")
embeddings = model.encode(keywords, show_progress_bar=True)

print(f"Shape de embeddings: {embeddings.shape}")

Cada keyword queda representada como un vector de 384 dimensiones. A partir de ahí, el algoritmo puede calcular qué keywords son semánticamente cercanas entre sí.

3. Clustering con K-Means

Uso K-Means como algoritmo principal porque es rápido y los resultados son fáciles de interpretar. El único parámetro que hay que decidir antes es el número de clusters.

Para eso, si no tengo una referencia clara del proyecto, uso el método del codo:

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

inertias = []
rango = range(5, 50, 5)

for k in rango:
    km = KMeans(n_clusters=k, random_state=42, n_init=10)
    km.fit(embeddings)
    inertias.append(km.inertia_)

plt.plot(rango, inertias, marker="o")
plt.xlabel("Número de clusters")
plt.ylabel("Inercia")
plt.title("Método del codo")
plt.show()

Una vez elegido el número de clusters (suelo quedarme con el punto donde la curva empieza a aplanarse), lanzo el clustering definitivo:

n_clusters = 20  # ajustar según el método del codo

km = KMeans(n_clusters=n_clusters, random_state=42, n_init=10)
df["cluster"] = km.fit_predict(embeddings)

4. Etiquetar los clusters automáticamente

Esto es algo que me ahorra mucho tiempo. En lugar de revisar cada cluster manualmente para ponerle nombre, extraigo las keywords más representativas de cada grupo (las más cercanas al centroide) y las uso como etiqueta provisional.

from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

etiquetas = {}

for cluster_id in range(n_clusters):
    indices = df[df["cluster"] == cluster_id].index.tolist()
    vecs = embeddings[indices]
    centroide = km.cluster_centers_[cluster_id]
    similitudes = cosine_similarity([centroide], vecs)[0]
    top_idx = np.argsort(similitudes)[::-1][:3]
    top_keywords = [keywords[indices[i]] for i in top_idx]
    etiquetas[cluster_id] = " / ".join(top_keywords)

df["cluster_label"] = df["cluster"].map(etiquetas)

El resultado es un dataframe donde cada keyword tiene su cluster asignado y una etiqueta legible. No siempre son perfectas, pero sí dan un punto de partida muy útil para la revisión manual posterior.

5. Exportar y revisar

df.sort_values("cluster").to_csv("keywords_clusterizadas.csv", index=False)

La revisión manual sigue siendo necesaria, especialmente en los clusters fronterizos donde el modelo duda. Pero en lugar de revisar 2.000 keywords una a una, revisas 20 grupos. El tiempo baja de horas a minutos.

Cómo aplico esto en proyectos reales

El clustering semántico me resulta especialmente útil en tres momentos concretos:

  • Al arrancar un proyecto nuevo: para estructurar el universo de keywords y diseñar la arquitectura de información antes de tocar nada en la web.
  • En auditorías de contenido: para detectar si hay grupos temáticos sin cobertura o con demasiadas URLs compitiendo entre sí (canibalización potencial).
  • Al planificar el calendario editorial: los clusters se convierten directamente en pilares de contenido, con sus subtemas ya organizados dentro de cada grupo.

Lo que no hace este método

Seré directo: el clustering semántico no detecta intención de búsqueda de forma automática. Puede agrupar “comprar zapatillas running” y “zapatillas running precio” en el mismo cluster (correcto), pero no te dice si esa intención es transaccional o informacional. Eso sigue requiriendo criterio humano.

Tampoco es infalible con queries muy cortas o ambiguas. Cuanto más contexto tiene la keyword, mejor funciona el modelo.


Si quieres profundizar en cómo conecto este proceso con la priorización de URLs o con la detección de canibalización, eso lo veremos en los siguientes posts. El clustering es el primer paso; lo que haces con esos grupos después es donde está el valor real.