A lo largo de esta práctica veremos como aplicar distintas técnicas no supervisadas así como algunas de sus aplicaciones reales:
Para ello vamos a necesitar las siguientes librerías:
import random
import numpy as np
import pandas as pd
from sklearn import cluster # Algoritmos de clustering.
from sklearn import datasets # Crear datasets.
from sklearn import manifold # Algoritmos de reduccion de dimensionalidad.
# Visualizacion.
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
Vamos a partir de un dataset de clientes en un negocio retail cualquiera (en el fichero pec2_1.p un DataFrame de pandas en formato pickle o pec2_1.csv en formato CSV).
Para cada cliente se cuenta con 3 variables:
avg_month_turnover: el gasto medio de un cliente al mes.
Primero se pide visualizar las variables para entender como están distribuidas y preprocesarlas para aplicar un k-means.
df = pd.read_csv("pec2_1.csv")
print("Visualizo las variables y su frecuéncia. ")
df.hist()
plt.tight_layout()
print("Primer análisis de los datos")
display(df.head())
print("Descripción de los datos")
display(df.describe())
print("El número de líneas es: " + str(df.shape[0]) + " y el número de columnas: "+ str(df.shape[1]))
print("No existe ningún null")
display(df.isnull().sum())
print("Normalizo las variables")
from sklearn.preprocessing import MinMaxScaler
#importante la copia, sino realizo las modificaciones sobre df.
datos_normalizado = df.copy()
for col in df.columns:
datos_normalizado[col] = MinMaxScaler().fit_transform( datos_normalizado[col].values.reshape(-1, 1))
display(datos_normalizado.head())
Se pide estimar el número de clusters a detectar por k-means. Una técnica para estimar k es, como se explica en la teoría:
Los criterios anteriores (minimización de distancias intra grupo o maximización de distancias inter grupo) pueden usarse para establecer un valor adecuado para el parámetro k. Valores k para los que ya no se consiguen mejoras significativas en la homogeneidad interna de los segmentos o la heterogeneidad entre segmentos distintos, deberían descartarse.
Lo que popularmente se conocer como regla del codo.
Primero es necesario calcular la suma de los errores cuadráticos (SSE) que consiste en la suma de todos los errores (distancia de cada punto a su centroide asignado) al cuadrado.
Donde K es el número de clusters a buscar por k-means,
Este procedimiento realizado para cada posible valor k, resulta en una función monótona decreciente, donde el eje x representa los distintos valores de k, y el eje y el SSE. Intuitivamente se podrá observar un significativo descenso del error, que indicará el valor idóneo de k.
Se pide realizar la representación gráfica de la regla del codo junto a su interpretación, utilizando la librería matplotlib
y la implementación en scikit-learn de k-means.
# Metodo del Codo para encontrar el numero optimo de clusters
features=['avg_month_turnover', 'n_days_per_week','n_month_purchases']
x = datos_normalizado.loc[:, features].values
from sklearn.cluster import KMeans
wcss = []
x_label = []
for i in range(1, 20):
kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
kmeans.fit(x)
wcss.append(kmeans.inertia_)
x_label.append(i)
# Grafica de la suma de las distancias
plt.plot(range(1, 20), wcss)
plt.title('The Elbow Method')
plt.xlabel('Number of clusters')
plt.xticks(x_label)
plt.ylabel('WCSS')
plt.show()
En la gráfica se observa una disminución muy importante para el valor k=4, es decir, la subdivisión en 4 clústers es la opción más acertada para resolver el problema. A partir de ese valor la disminución del error es muy poco relevante.
Utilizando otra métrica, por ejemplo, se podría utilizar una técnica para maximizar la suma de distancias entre segmentos. Utilizando una tecnica que uniera la minimización de distancias intra- grupo y la maximización de distancias intergrupo obtendríamos mejores resultados.
kmeans = KMeans(n_clusters = 4, init = 'k-means++', random_state = 42)
kmeans.fit(x)
centroids = kmeans.cluster_centers_
print(datos_normalizado.columns)
display(centroids)
Representan la siguiente tipología de clientes:
# for 3D projection to work
from mpl_toolkits.mplot3d import Axes3D
import warnings
random.seed(10)
warnings.simplefilter('ignore')
estimators = [('k_means_4', KMeans(n_clusters=4)),
]
print('Visualización del dataset en 3 dimensiones')
titles = ['4 clusters']
for name, est in estimators:
fig = plt.figure().gca(projection='3d')
est.fit(x)
labels = est.labels_
fig.scatter(datos_normalizado['n_days_per_week'], datos_normalizado['n_month_purchases'], datos_normalizado['avg_month_turnover'],
c=labels.astype(np.float), edgecolor='k')
fig.set_xlabel('n_days_per_week')
fig.set_ylabel('n_month_purchases')
fig.set_zlabel('avg_month_turnover')
fig.set_title(titles[0])
plt.tight_layout()
plt.show()