Saltar al contenido

# aprendizaje-automatico-no-supervisado-con-python

Aprendizaje Automático No Supervisado con Python

Volver a la portada del curso
Notebook

Notebook: Clustering con Scikit-learn

Sección 2 · Clustering con Python

Notebook: clustering con scikit-learn

En los videos viste cómo trabaja K-means y cómo se arma un dendrograma. En este notebook lo haces tú, de principio a fin, con las 1500 sesiones de PyShop: preparas los datos, agrupas con K-means, eliges k, pones nombre a cada grupo, clasificas sesiones nuevas y comparas con el clustering jerárquico. Esta guía acompaña al notebook clustering-con-scikit-learn y te dice qué buscar en cada sección y qué resultados debes obtener.

Objetivos

  • Escalar las 8 columnas de comportamiento y entender por qué.
  • Ajustar KMeans y leer labels_, cluster_centers_ e inertia_.
  • Elegir k con el codo de la inercia y con silhouette.
  • Traducir los centros a unidades originales y nombrar los grupos.
  • Comparar K-means con AgglomerativeClustering usando el índice de Rand ajustado (ARI).

1. Datos y escalado

La primera celda define generar_sesiones() y la lista COLUMNAS; el notebook es autocontenido. Se separa X = df[COLUMNAS] (sin dispositivo, que es contexto) y se escala:

from sklearn.preprocessing import StandardScaler

df = generar_sesiones()
X = df[COLUMNAS]
sc = StandardScaler()
Xs = sc.fit_transform(X)
print(X.var().round(1).tail(2))

Mira las varianzas: monto_carrito_mxn tiene 3,722,205 y pct_ofertas 0.1. El notebook ajusta K-means con y sin escalar para que veas la diferencia: sin escalar, los tamaños son [1051, 132, 281, 36] y los centros solo se separan por monto; escalado, [310, 617, 375, 198].

2. K-means con cuatro grupos

import numpy as np
from sklearn.cluster import KMeans

km = KMeans(n_clusters=4, n_init=10, random_state=42).fit(Xs)
print(np.bincount(km.labels_))      # [310 617 375 198]
print(round(km.inertia_, 1), km.n_iter_)   # 3513.2 9

labels_ tiene el grupo de cada sesión; inertia_ es la suma de distancias al cuadrado de cada sesión a su centro (3513.2); el algoritmo convergió en 9 iteraciones. n_init=10 repite el ajuste con 10 inicios distintos y se queda con el de menor inercia.

3. Elegir k: codo y silhouette

El notebook recorre k de 2 a 8 y grafica la inercia y el silhouette promedio. El silhouette de una sesión compara $a$, la distancia media a su propio grupo, con $b$, la distancia media al grupo vecino más cercano:

$$s = \frac{b - a}{\max(a, b)}$$

Vale entre −1 y 1; cerca de 1, la sesión está bien metida en su grupo. Resultados esperados:

kInerciaSilhouette
26983.20.456
35063.00.414
43513.20.479
53190.40.449
62900.50.401
82477.50.385

La inercia siempre baja al aumentar k; lo que importa es dónde deja de bajar mucho. De 3 a 4 cae 1549.8; de 4 a 5, solo 322.8. El codo y el máximo de silhouette coinciden en 4.

4. Nombrar los grupos

Los centros están en unidades escaladas. sc.inverse_transform(km.cluster_centers_) los devuelve a páginas, minutos y pesos. Debes obtener estos perfiles:

  • Grupo 0, cazadores de ofertas (310): 11.2 páginas, 9.1 minutos, 70 % de páginas de ofertas, 731 MXN en el carrito.
  • Grupo 1, visitas rápidas (617): 2.6 páginas, 2.5 minutos, 1.0 productos vistos.
  • Grupo 2, comparadores (375): 24.4 páginas, 19.5 minutos, 14.5 productos, 6.6 reseñas leídas.
  • Grupo 3, compradores decididos (198): 5.8 páginas, 3.7 productos al carrito, 5158 MXN.

Los nombres los pones tú, mirando estas cifras; el algoritmo solo entrega números.

5. Clasificar sesiones nuevas

Una sesión nueva se escala con el mismo sc (transform, nunca fit_transform) y se pasa a predict. El notebook prueba tres: 3 páginas en 1.5 minutos sin carrito da el grupo 1; 30 páginas, 25 minutos y 9 reseñas da el 2; 12 páginas con 80 % de ofertas y 2400 MXN en el carrito da el 0.

6. Clustering jerárquico

from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics import adjusted_rand_score

ward = AgglomerativeClustering(n_clusters=4, linkage="ward")
lab_w = ward.fit_predict(Xs)
print(np.bincount(lab_w))                        # [679 379 305 137]
print(round(adjusted_rand_score(km.labels_, lab_w), 3))   # 0.89

El ARI mide cuánto coinciden dos particiones sin importar cómo se numeren los grupos: 1 es coincidencia total y cerca de 0 es azar. Ward y K-means coinciden en 0.890. El notebook también dibuja el dendrograma de una muestra de 30 sesiones y calcula el completo con scipy.cluster.hierarchy.linkage(Xs, "ward"): sus últimas fusiones ocurren a 26.6, 55.5, 60.4 y 100.1, así que cortar a altura 40 con fcluster deja 4 grupos. Con linkage="single", en cambio, sale [1497, 1, 1, 1]: el enlace importa.

7. Comprobación final

La última sección genera los datos con con_tipo=True y cruza los grupos con el tipo real, que en un problema real no existiría. ARI de K-means: 0.849. Los curiosos caen todos en el grupo 1 y los comparadores casi todos en el 2, pero 88 compradores decididos que agregaron poco al carrito quedan en «visitas rápidas».

Qué debes obtener

Tamaños [310, 617, 375, 198], inercia 3513.2, silhouette 0.479 y los cuatro perfiles de arriba. Si tus números difieren, revisa la semilla de los datos, random_state=42 y que dispositivo no haya entrado en X. Como práctica, repite el ajuste con k=5 y describe qué grupo se parte en dos.

Recursos