MAT281

Laboratorio Aplicaciones de la Matemática en la Ingeniería

Clustering

INSTRUCCIONES

  • Anoten su nombre y rol en la celda siguiente.
  • Desarrollen los problemas de manera secuencial.
  • Guarden constantemente con Ctr-S para evitar sorpresas.
  • Reemplacen en las celdas de código donde diga #FIX_ME por el código correspondiente.
  • Ejecuten cada celda de código utilizando Ctr-Enter

In [2]:
# Configuracion para recargar módulos y librerías 
%reload_ext autoreload
%autoreload 2

%matplotlib inline

from IPython.core.display import HTML

HTML(open("style/mat281.css", "r").read())


Out[2]:

In [3]:
from mat281_code.lab import greetings
alumno_1 = ("Sebastian Flores", "2004001-7")
alumno_2 = ("Maria Jose Vargas", "2004007-8")

HTML(greetings(alumno_1, alumno_2))


Out[3]:
Alumno: Sebastian Flores rol: 2004001-7
Alumno: Maria Jose Vargas rol: 2004007-8
Good luck!

Observación

Este laboratorio utiliza la librería sklearn (oficialmente llamada scikit learn), puesto que buscamos aplicar la técnica del clustering a datos tal como se haría en una aplicación real. El código a proveer en este laboratorio es reducido, y la nota se basará mayoritariamente en la calidad de las respuestas entregadas en los comentarios.

Problema: Wine Dataset

Los datos del Wine Dataset son un conjunto de datos clásicos para verificar los algoritmos de clustering.

Los datos corresponden a 3 cultivos diferentes de vinos de la misma región de Italia, y que han sido identificados con las etiquetas 1, 2 y 3. Para cada tipo de vino se realizado 13 análisis químicos:

  1. Alcohol
  2. Malic acid
  3. Ash
  4. Alcalinity of ash
  5. Magnesium
  6. Total phenols
  7. Flavanoids
  8. Nonflavanoid phenols
  9. Proanthocyanins
  10. Color intensity
  11. Hue
  12. OD280/OD315 of diluted wines
  13. Proline

La base de datos contiene 178 muestras distintas en total.

1. Lectura de datos

Esta vez los datos del wine dataset ya se encuentan en la carpeta Lab04/data/.

Existen 2 archivos de interés:

  • wine_data.txt : Datos de interés.
  • wine_names.txt : Explicación de los datos.

In [ ]:
%%bash
head data/wine_data.txt

Desafío 1 (10%)

El siguiente código permite leer los datos desde el archivo data/wine_data.txt y cargarlos en un numpy.array. Complete la preparación de los datos, separando los datos en el arreglo X (datos a utilizar para clustering) y true_labels (etiquetas verdaderas para cada dato de X).

OBS: Las etiquetas verdaderas deben modificarse para que sean 0, 1 y 2 (en vez de 1, 2 y 3 como vienen en el archivo).


In [ ]:
import numpy as np
data = np.loadtxt("data/wine_data.txt", delimiter=",")
names = ["Alcohol", "Malic acid", "Ash", "Alcalinity of ash", "Magnesium", "Total phenols",
         "Flavanoids", "Nonflavanoid phenols", "Proanthocyanins", "Color intensity",
         "Hue", "OD280/OD315", "Proline",
        ]
X = data[:,:] # FIX ME ¿que columnas tomar?
true_labels = data[:,:] # FIX ME ¿que columna tomar?

Desafío 2 (10%)

Utilizando el vector true_labels definido anteriormente, complete el código para conocer cuántas muestras son de tipo 0, de tipo 1 y de tipo 2.


In [ ]:
tipo_0 = len(true_labels[:]) # FIX ME. ¿Como seleccionar una clase en particular?
tipo_1 = 42 # FIX ME ¿Como seleccionar una clase en particular?
tipo_2 = 0 # FIX ME ¿Como seleccionar una clase en particular?
print "Hay %d muestras de tipo 0" %tipo_0
print "Hay %d muestras de tipo 1" %tipo_1
print "Hay %d muestras de tipo 2" %tipo_2
esta_correcto = ( tipo_0+tipo_1+tipo_2==len(true_labels) )
print "Check: %d + %d + %d = %d? %s" %(tipo_0, tipo_1, tipo_2, len(true_labels), esta_correcto)

2. Exploración de valores

Antes de realizar el clustering, deseamos revisar los datos. El siguiente código permite conocer la distribución de las mediciones para las muestras.


In [ ]:
from matplotlib import pyplot as plt
rows, cols = 5, 3
fig, axes = plt.subplots(rows, cols, figsize=(16,16))
for i in range(rows):
    for  j in range(cols):
        n = i*cols + j
        if n<13:
            ax = axes[i][j]
            ax.hist(X[:,n], alpha=0.75)
            ax.set_title(names[n])
fig.tight_layout()
plt.show()

Desafío 3 (10%)

En base a la exploración de valores, ¿que resulta más razonable? ¿Porqué?

  1. Aplicar el algoritmo de clustering directamente.
  2. Realizar algún tipo de normalización a los datos, y luego aplicar el algoritmo de clustering.

Justifique su respuesta: piense en cómo funciona K-Means.

Respuesta

FIX ME. (Editar con doble click, y luego mostrar con Ctrl+Enter)

3. Clustering Directo

A continuación se provee el código para realizar el clustering de los datos de manera directa (sin normalizar).


In [ ]:
from sklearn.cluster import KMeans
from sklearn.metrics import confusion_matrix

# Parameters
n_clusters = 3

# Running the algorithm
kmeans = KMeans(n_clusters)
kmeans.fit(X)
pred_labels = kmeans.labels_

cm = confusion_matrix(true_labels, pred_labels)
print cm

Desafío 4 (10%)

Ejecute el código anterior y comente los resultados. ¿Permite el clustering recobrar el agrupamiento natural de los datos? ¿Si no, porqué?

Respuesta

FIX ME. (Editar con doble click, y luego mostrar con Ctrl+Enter)

3. Normalización de los datos

Sabemos que los algoritmos suelen funcionar mejor con los datos normalizados, como se explicó en la clase de Regresión Lineal.

Note que en el caso de los algoritmos de clustering, sólo es necesario normalizar la matrix X, ¡las etiquetas no necesitan normalizarse!

Desafío 5 (20%)

  • Normalice los datos utilizando para obtener una nueva matriz X_mod_1, cuyas columnas tengan sus datos en el rango [0,1].
  • ¿Porqué normalizamos por columna y no por fila?
  • Reutilice el código anteriormente provisto para realizar el clustering en los datos normalizados y comente los resultados obtenidos.

In [ ]:
X_mod_1 = X # FIX ME
# AGREGAR CODIGO PARA REALIZAR CLUSTERING EN X_mod_1

Comentario a los resultados obtenidos.

Respuesta

FIX ME. (Editar con doble click, y luego mostrar con Ctrl+Enter)

Desafío 6 (20%)

  • Estandarice los datos para obtener una nueva matriz X_mod_2, de manera que X_mod_2 posea media 0 y desviación estándar 1 para cada una de sus columnas.
  • Reutilice el código anteriormente provisto para realizar el clustering en los datos estandarizados y comente los resultados obtenidos.

In [ ]:
X_mod_2 = X # FIX ME
# AGREGAR CODIGO PARA REALIZAR CLUSTERING EN X_mod_1

Comentario a los resultados obtenidos.

Respuesta

FIX ME. (Editar con doble click, y luego mostrar con Ctrl+Enter)

Desafío 7 (10%)

¿Cuál de las 3 versiones aplicadas de clustering funcionó mejor? ¿Porqué cree que sea así?

Respuesta

FIX ME. (Editar con doble click, y luego mostrar con Ctrl+Enter)

Bonus Track: Regla del codo

En todos los casos hemos utilizado que el número de clusters es igual a 3. En caso que no conociéramos este dato, deberíamos graficar la suma de las distancias a los clusters para cada punto, en función del número de clusters. A continuación se provee el código para el caso de clustering sobre los datos estandarizados, leídos directamente de un archivo preparado especialmente.


In [ ]:
from sklearn.cluster import KMeans

X_mod = np.loadtxt("data/X_estandarized.txt")

clusters = range(2,20)
total_distance = []
for n_clusters in clusters:
    kmeans = KMeans(n_clusters)
    kmeans.fit(X_mod)
    pred_labels = kmeans.labels_
    centroids = kmeans.cluster_centers_
    # Get the distances
    distance_for_n = 0
    for k in range(n_clusters):
        points = X_mod[pred_labels==k]
        aux = (points - centroids[k,:])**2
        distance_for_n += (aux.sum(axis=1)**0.5).sum()
    total_distance.append(distance_for_n)

In [ ]:
fig = plt.figure(figsize=(16,8))
plt.plot(clusters, total_distance, 'rs')
plt.xlim(min(clusters)-1, max(clusters)+1)
#plt.ylim(0, max(total_distance)*1.1)
plt.show()