Clustering de segmentos de clientes
Tienes una base de datos de 100,000 clientes. El equipo de marketing quiere campañas personalizadas. Una estrategia por cliente es imposible. Una estrategia para todos es un desperdicio. El punto medio es la segmentación: agrupar a los clientes en clusters que compartan comportamientos y luego adaptar tu enfoque a cada grupo.
Aquí es donde el unsupervised learning demuestra su valor. No necesitas etiquetas. El algoritmo encuentra la estructura por sí solo.
Por qué usar aprendizaje no supervisado
Los enfoques supervisados requieren que alguien defina los segmentos de antemano: "alto valor", "en riesgo", "nuevo". Eso introduce sesgos humanos y pasa por alto patrones que nadie pensó en buscar. El clustering permite que los datos hablen. Podrías encontrar un segmento que compra raramente pero gasta mucho por pedido, o un grupo que interactúa a diario pero nunca convierte. Las etiquetas predefinidas nunca mostrarían ninguno de esos casos.
K-Means: la herramienta principal
K-Means es el algoritmo al que recurro primero. Es rápido, la matemática es intuitiva y funciona bien cuando tus clusters son aproximadamente esféricos y de tamaño similar.
El ciclo es corto:
- Elegir K centroides iniciales (aleatorios o vía K-means++)
- Asignar cada punto a su centroide más cercano
- Recomputar cada centroide como la media de sus puntos asignados
- Repetir 2 y 3 hasta que nada cambie
Aquí puedes verlo funcionando con datos reales. Presiona play; esta es una ejecución real de K-Means, iniciada deliberadamente con una mala inicialización (los cuatro centroides agrupados en una esquina) para que puedas observar cómo la reasignación hace su trabajo:
Algoritmo de Lloyd en 150 puntos. Las cruces son los centroides; cada iteración los mueve a la media de sus puntos asignados y vuelve a colorear cada punto según su centroide más cercano. Nota qué tan rápido converge: 27 puntos cambian de cluster en la primera pasada, luego 11, 6, 2, y esencialmente termina en la iteración 5. La inercia (distancia total al cuadrado de los centroides) cae de 6,108 a 856 y se estabiliza. Esa estabilización es exactamente lo que busca el método del codo (elbow method) a continuación.
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# Load and prepare customer data
df = pd.read_csv('customers.csv')
features = df[['recency', 'frequency', 'monetary', 'avg_session_duration',
'support_tickets', 'days_since_signup']]
# Scaling is critical - K-Means uses Euclidean distance
scaler = StandardScaler()
X = scaler.fit_transform(features)
# Fit K-Means
kmeans = KMeans(n_clusters=5, init='k-means++', n_init=10, random_state=42)
df['cluster'] = kmeans.fit_predict(X)Un detalle que no puedes omitir: K-Means utiliza la distancia euclidiana, por lo que cada característica (feature) debe estar en la misma escala. Una columna "monetary" en dólares (rango de 0 a 10,000) aplastará a una columna "frequency" (rango de 0 a 50) a menos que estandarices primero. StandardScaler centra cada característica en cero con varianza unitaria, que es lo que necesitas.
Eligiendo K: método del codo y silhouette scores
Elegir K es la parte más difícil de K-Means. Dos métodos te ayudarán a lograrlo.
El método del codo (elbow method) grafica la suma de cuadrados dentro del cluster (inercia) frente a K. A medida que K crece, la inercia disminuye. El "codo" es el punto donde la caída se suaviza y añadir más clusters deja de valer la pena.
import matplotlib.pyplot as plt
inertias = []
K_range = range(2, 11)
for k in K_range:
km = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42)
km.fit(X)
inertias.append(km.inertia_)
plt.plot(K_range, inertias, 'bo-')
plt.xlabel('Number of Clusters (K)')
plt.ylabel('Inertia')
plt.title('Elbow Method')
plt.show()El codo suele ser ambiguo con datos reales. Cuando sea así, recurre al silhouette score. Para cada punto, el coeficiente de silueta compara qué tan similar es a su propio cluster frente al cluster vecino más cercano. Las puntuaciones van de -1 (cluster incorrecto) a 1 (bien ubicado). Promedia todos los puntos y obtendrás un número para comparar diferentes valores de K.
from sklearn.metrics import silhouette_score
for k in K_range:
km = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42)
labels = km.fit_predict(X)
score = silhouette_score(X, labels)
print(f"K={{k}}: Silhouette Score = {{score:.3f}}")En la práctica, analizo ambos y luego me pregunto si el resultado es útil operativamente. Puede que K=7 tenga una puntuación ligeramente mejor que K=5, pero si el equipo de marketing no puede ejecutar siete campañas distintas, lanza el modelo con K=5.
Feature engineering: análisis RFM
Las transacciones en bruto no están listas para el clustering. El punto de partida estándar para la segmentación de clientes es el análisis RFM:
- Recency: días desde la última compra. Mientras menor, mejor.
- Frequency: número de compras en un periodo. Mayor significa más compromiso.
- Monetary: gasto total. Tu señal de ingresos.
from datetime import datetime
snapshot_date = datetime(2025, 10, 1)
rfm = df.groupby('customer_id').agg({{
'purchase_date': lambda x: (snapshot_date - x.max()).days, # Recency
'order_id': 'nunique', # Frequency
'amount': 'sum' # Monetary
}}).rename(columns={{
'purchase_date': 'recency',
'order_id': 'frequency',
'amount': 'monetary'
}})RFM es un punto de partida, no la meta. Dependiendo del negocio, añadiré el valor promedio del pedido, el número de categorías de productos comprados, la antigüedad del cliente, tickets de soporte, tasa de apertura de correos electrónicos o duración de la sesión. Más características a veces ayudan, pero también disparan la dimensionalidad y añaden ruido. Sé deliberado.
Más allá de K-Means: DBSCAN para clusters no esféricos
K-Means asume que los clusters son convexos y de tamaño similar. Los datos reales de clientes rompen ambos supuestos constantemente. Tendrás un cluster enorme de compradores ocasionales y un cluster diminuto y compacto de usuarios avanzados. K-Means dividirá el grande o absorberá el pequeño.
DBSCAN (Density-Based Spatial Clustering of Applications with Noise) encuentra clusters de forma arbitraria basándose en la densidad de puntos. Toma dos parámetros:
- eps: radio de la vecindad alrededor de cada punto.
- min_samples: el número mínimo de puntos necesarios para considerar una región como densa.
Los puntos que no pertenecen a ninguna región densa se etiquetan como ruido, lo cual es realmente útil. No todos los clientes encajan en un segmento, y pretender que lo hacen es como terminas con "buyer personas" que no sirven para nada.
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=0.8, min_samples=10)
df['cluster'] = dbscan.fit_predict(X)
n_clusters = len(set(df['cluster'])) - (1 if -1 in df['cluster'].values else 0)
n_noise = (df['cluster'] == -1).sum()
print(f"Clusters: {{n_clusters}}, Noise points: {{n_noise}}")Ajustar eps es la parte difícil. Si es muy pequeño, todo es ruido. Si es muy grande, todo colapsa en un solo cluster. Un gráfico de k-distancia —ordenar la distancia al k-ésimo vecino más cercano para cada punto y buscar el codo— suele situarte en el rango correcto.
Interpretación y acción sobre los clusters
El clustering no es el final del trabajo, es el comienzo de la conversación con los interesados. Para cada cluster, calcula estadísticas resumidas:
summary = df.groupby('cluster')[['recency', 'frequency', 'monetary']].agg(['mean', 'median', 'std'])
print(summary)Luego, dales un nombre. Una segmentación RFM típica de 5 clusters suele verse así:
| Cluster | Recency | Frequency | Monetary | Etiqueta |
|---|---|---|---|---|
| 0 | Baja | Alta | Alta | Campeones (Champions) |
| 1 | Baja | Baja | Baja | Clientes nuevos |
| 2 | Alta | Alta | Alta | Leales en riesgo |
| 3 | Alta | Baja | Baja | Perdidos |
| 4 | Media | Media | Media | Leales potenciales |
Cada uno requiere una jugada diferente. Los Campeones reciben recompensas de lealtad y acceso anticipado. Los Leales en riesgo reciben campañas de recuperación antes de que abandonen (churn). Los Clientes nuevos entran en flujos de onboarding. Los clientes Perdidos simplemente podrían no valer el costo de re-adquisición; esa también es una respuesta válida.
Errores comunes
Olvidar escalar. El error número uno. Las características sin escalar hacen que la distancia euclidiana no tenga sentido.
Incluir demasiadas características. La maldición de la dimensionalidad hace que las métricas de distancia sean cada vez menos informativas a medida que agregas columnas. Después de 10 o 15 características, ejecuta un PCA antes del clustering.
Tratar los clusters como permanentes. El comportamiento del cliente cambia. Ejecuta el clustering mensual o trimestralmente y observa cómo los clientes migran entre segmentos; esa migración suele ser la señal más útil que tienes.
Ignorar la estabilidad. Ejecuta K-Means varias veces con diferentes semillas aleatorias. Si los clientes saltan entre clusters en cada ejecución, la segmentación no es robusta para ese valor de K.
Conclusión
La segmentación de clientes es uno de los casos más claros donde el aprendizaje no supervisado entrega valor real de negocio. Las piezas técnicas —K-Means, silhouette scores, variables RFM— están bien establecidas. La parte difícil es la capa de traducción: convertir las estadísticas de los clusters en algo que los equipos de marketing, producto y soporte puedan ejecutar. La mejor segmentación es la que cambia la forma en que la organización toma decisiones, no la que tiene el gráfico de silueta más bonito.
