Introducción a K-means

Fundación Universitaria Konrad Lorenz

Viviana Márquez [vivianam.penam@konradlorenz.edu.co]

Julio 24, 2020

📝 Hoy veremos...

• K-means en el contexto de Machine Learning

• Cuándo usar K-means

• El paso a paso de K-means

• Ejercicio de programación

• Errores comunes y cuando NO usar K-means

• Cómo escoger la mejor K

• ¡Recapitulando!

• En la próxima clase...

• Laboratorio

🌎 K-means en el mundo de Machine Learning


🌎 K-means en el mundo de Machine Learning


🤖 Métodos de Agrupación

Es la forma más común de aprendizaje no supervisado

Datos

• Muestras de entrenamiento $\{ x_1, \ldots, x_n\} \in \mathbb{R}^{n}$

• No necesitamos (tenemos) etiquetas $y_i$

Sirve para detectar patrones

  • Agrupar clientes para campañas de publicidad
  • Recomendaciones de resultados de busqueda
  • Segmentación de imagenes
  • y más...

Primera (?) aplicación de agrupación


• En la década de 1850, un médico de Londres llamado John Snow, graficó la ubicación de las muertes por cólera en un mapa.

• Las ubicaciones mostraron que los casos estaban agrupados cerca ciertas intersecciones donde habían pozos contaminados -- así, exponiendo tanto el problema como la solución.


Fuente: Nina Mishra HP Labs

🤖 Métodos de Agrupación


Objetivo: Agrupar ejemplares en clases de objetos similares-- "cúmulos/clusters"

¿Cuándo usarlos? Cuando no sabemos qué estamos buscando

... pero, ¡cuidado, se puede convertir en galimatías!

🌎 K-means en el mundo de Machine Learning


🔎 K-means en el mundo de Machine Learning


🔎 K-means en el mundo de Machine Learning


🔎 K-means en el mundo de Machine Learning


K-means

(También conocido como K-medias)


Modelo de Machine Learning NO supervisado de agrupación por partición



K-means un algoritmo iterativo cuyo objetivo es particionar un conjunto de $N$ observaciones
en $K$ grupos en el que cada observación pertenece al grupo cuyo valor medio es más cercano.

K-means --- Pasos

1. Inicializar

A.   Elegir un número K de cúmulos

B.   Escoger aleatoriamente K puntos como centroides

2. Repetir

A.   Los K cúmulos se crean asociando cada observación con la media más cercana

B.   El nuevo centroide de cada uno de los K cúmulos es la media de sus observaciones

K-means --- Pasos

3. Parar

A.   Repetir pasos 1 y 2

B.   El algoritmo acaba cuando ya no hay cambio en los centroides de los cúmulos, las observaciones de los cúmulos siguen siendo las mismas, o el máximo número de iteraciones es alcanzado

Referencias:

  • Definición matemática: Link

  • Visualización: Video

👮‍♀️ Punto de control


¿Cuál es el número de $K$?

¿Qué está pasando en cada paso?

👩‍💻 Manos a la obra

Problema

Tenemos que identificar tres distintas especies de la flor del género iris y sólo tenemos información sobre el tamaño de sus pétalos.

👩‍💻 Manos a la obra

Paso 1: Cargar los datos

In [2]:
import pandas as pd
import seaborn as sns

iris = sns.load_dataset("iris")
iris = iris[['petal_length', 'petal_width']]

iris.sample(5)
Out[2]:
petal_length petal_width
82 3.9 1.2
31 1.5 0.4
69 3.9 1.1
37 1.4 0.1
48 1.5 0.2
In [3]:
iris.shape
Out[3]:
(150, 2)

Recordatorio:
Para cualquier modelo, al cargar los datos siempre debemos verificar que esten correctos, lidiar con los datos faltantes, escoger las características importantes, hacer ingeniería de características (feature engineering), etc.

👩‍💻 Manos a la obra

Paso 2: Entrenar el modelo

In [4]:
from sklearn.cluster import KMeans # 🙏our savior

model = KMeans(n_clusters=3) 
model.fit(iris)
Out[4]:
KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
       n_clusters=3, n_init=10, n_jobs=None, precompute_distances='auto',
       random_state=None, tol=0.0001, verbose=0)

¡Importante! Revisar los parametros disponibles en la documentación.

👩‍💻 Trabajando con el modelo

In [5]:
# Los resultados
model.labels_
Out[5]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=int32)
In [6]:
iris['cluster'] = model.labels_
iris.sample(5)
Out[6]:
petal_length petal_width cluster
18 1.7 0.3 0
6 1.4 0.3 0
41 1.3 0.3 0
14 1.2 0.2 0
117 6.7 2.2 1
In [7]:
iris.cluster.value_counts()
Out[7]:
2    52
0    50
1    48
Name: cluster, dtype: int64

👩‍💻 Trabajando con el modelo

In [8]:
# Centroides
model.cluster_centers_
Out[8]:
array([[1.462     , 0.246     ],
       [5.59583333, 2.0375    ],
       [4.26923077, 1.34230769]])
In [9]:
df_centroides = pd.DataFrame(model.cluster_centers_)
df_centroides.columns = ['petal_length', 'petal_width']
df_centroides['cluster'] = [0,1,2]
df_centroides
Out[9]:
petal_length petal_width cluster
0 1.462000 0.246000 0
1 5.595833 2.037500 1
2 4.269231 1.342308 2

👩‍💻 Visualizar el modelo

In [10]:
def plot(r=False):
    if r == True:
        t = [f"Largo: {largo:.2f}cm<br>Ancho: {ancho:.2f}<br>Cluster: {c} - {r}" for largo,ancho,c,r in zip(iris.petal_length, iris.petal_width.values, iris.cluster.values, sns.load_dataset("iris").species.values)]
    else:
        t = [f"Largo: {largo:.2f}cm<br>Ancho: {ancho:.2f}<br>Cluster: {c}" for largo,ancho,c in zip(iris.petal_length, iris.petal_width.values, iris.cluster.values)]
    
    
    colors = {0: 'green', 1: 'red', 2: 'orange'}

    # Traza de los ejemplares
    traza_ejemplares = go.Scatter(

        x=iris.petal_length.values,
        y=iris.petal_width.values,
        text = t,
        hoverinfo='text',
        mode='markers', 
        marker = {'color': [colors[c] for c in iris.cluster.values]},
        name="Observaciones"
    )


    # Traza de los centroides
    traza_centroides = go.Scatter(

        x=df_centroides.petal_length.values,
        y=df_centroides.petal_width.values,
        text = [f"CENTROIDE<br>Largo: {largo:.2f}cm<br>Ancho: {ancho:.2f}<br>Cluster: {c}" for largo,ancho,c in zip(iris.petal_length, iris.petal_width.values, iris.cluster.values)],
        hoverinfo='text',
        mode='markers', 
        marker = {'color': [colors[c] for c in df_centroides.cluster.values],
                   'line': dict(color='yellow', width=1),
                  'symbol': 202,
                  'size': 10},
        name="Centroides",
    )


    # Layout
    layout = go.Layout(title="Iris Clustering",
                       xaxis_title="Largo del Pétalo",
                       yaxis_title="Ancho del Pétalo")

    # Figura
    fig = go.Figure(data=[traza_ejemplares, traza_centroides], layout=layout)
    iplot(fig)
In [11]:
plot()
In [12]:
# ¿Lo hizo bien?
sns.load_dataset("iris").species.values[:10]
Out[12]:
array(['setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
       'setosa', 'setosa', 'setosa', 'setosa'], dtype=object)
In [13]:
model.predict([[1,0.5]])
Out[13]:
array([0], dtype=int32)

📞 Llamada a la realidad


• Dominio del tema es importante

• Escoger, limpiar, transformar y crear nuevas variables dependientes

• No se puede visualizar en muchas dimensiones

• En un contexto de negocios, quizás es mejor usar sklearn_extra.cluster.KMedoids

Atención: Si las variables son discretas, toca cambiar la métrica (función distancia)

🙁 ¿Qué puede salir mal?

Desventajas de K-means


• Se tiene que escoger K con antelación (más de eso adelante)

• Es intensivo computacionalmente

• Cada observación pertenece a un sólo cúmulo

• Sensible a las observaciones atípicas

• No puede modelar relaciones complejas

🙁 ¿Qué puede salir mal?

Cuando NO usar K-means


🙁 ¿Qué puede salir mal?

Cuando NO usar K-means


🙁 ¿Qué puede salir mal?

Cuando NO usar K-means


¿Cómo escoger K?

Es importante escoger un buen número para K


¿Cómo escoger K?

¿Cuántos cúmulos hay aquí?


¿Cómo escoger K?

¿Cuántos cúmulos hay aquí?

¿Dos?


¿Cómo escoger K?

¿Cuántos cúmulos hay aquí?

¿Ocho?


👮‍♀️ Punto de control


• ¿Cuál es valor mínimo posible para K?

• ¿Cuál es valor máximo para K?

• ¿Cómo escoger el número óptimo para K?

¿Cómo escoger K?

Método #1: El método del codo

In [14]:
# Inercia: Suma de la distancia de las observaciones a su centroide más cercano
model.inertia_
Out[14]:
31.371358974358973
In [15]:
inercias = {}

for k in range(1, 10):
    kmeans = KMeans(n_clusters=k).fit(iris[['petal_length', 'petal_width']])
    inercias[k] = kmeans.inertia_ 
In [16]:
plt.plot(list(inercias.keys()), list(inercias.values()))
plt.xlabel("Número de cúmulos"); plt.ylabel("Inercia"); plt.title('Iris');

Recapitulando



• Los modelos de agrupación son técnicas no supervisadas de Machine Learning que buscan extraer la estructura de los datos al juntar las observaciones similares.

• K-means es el modelo de agrupación más usado

• El algoritmo es iterativo y reasigna los centroides hasta cuando ya no haya cambio en los grupos

• Como todo modelo, es importante hacer una buena selección de variables dependientes y usar conocimento del tema para evaluar e interpretar el modelo.

• Hay que considerar las limitaciones del modelo a la hora de escoger trabajar o no con él.

🤔 En la próxima clase...

Más algoritmos de agrupación

Lectura adicional: Documentación

🤓 Laboratorio

• Datos más complejos

• Método de la silueta

• Portafolio