# Análisis de clustering jerárquico en Pythonimport pandas as pd# Configurar opciones de visualizaciónpd.set_option('display.max_rows', None) # Mostrar todas las filaspd.set_option('display.max_columns', None) # Mostrar todas las columnaspd.set_option('display.width', None) # Ajustar el ancho automáticamentepd.set_option('display.max_colwidth', None) # Mostrar el contenido completo de cada celda# Ejemplo con tu base de datos (o cualquier DataFrame)import pandas as pdimport matplotlib.pyplot as pltfrom scipy.cluster.hierarchy import dendrogram, linkage, fclusterfrom sklearn.preprocessing import StandardScaler# Lectura del archivodf = pd.read_csv('Mall_Customers.csv', encoding='ascii')# Mostrar las primeras filas para confirmar la lecturaprint('Primeras filas del dataframe:')print(df.head())
Primeras filas del dataframe:
CustomerID Genre Age Annual Income (k$) Spending Score (1-100)
0 1 Male 19 15 39
1 2 Male 21 15 81
2 3 Female 20 16 6
3 4 Female 23 16 77
4 5 Female 31 17 40
# Ahora realizaremos el análisis de clustering jerárquico con tres variables: Age, Annual Income y Spending Scoreimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom scipy.cluster.hierarchy import dendrogram, linkage, fclusterfrom sklearn.preprocessing import StandardScalerimport seaborn as snsfrom mpl_toolkits.mplot3d import Axes3Dimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsfrom scipy.spatial.distance import pdist, squareform# Cargar el archivodf = pd.read_csv('Mall_Customers.csv')# Extraer las variables para el análisisfeatures_ext = df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']]# Estandarizar las variablesscaler = StandardScaler()features_ext_scaled = scaler.fit_transform(features_ext)print(features_ext.head())
# Calcular la matriz de distancias euclídeasdist_matrix = squareform(pdist(features_ext_scaled , metric='euclidean'))# Mostrar la forma de la matrizprint('Forma de la matriz de distancias:', dist_matrix.shape)# Visualizar la matriz de distancias utilizando un heatmap (solo una parte para evitar visualizaciones muy densas)plt.figure(figsize=(10, 8))sns.heatmap(dist_matrix[:50, :50], cmap='viridis')plt.title('Heatmap de la Matriz de Distancias Euclídeas (Primeros 50 elementos)')plt.xlabel('Índice de muestra')plt.ylabel('Índice de muestra')plt.tight_layout()plt.show()print('Matriz de distancias calculada y visualizada (primeros 50 elementos).')print('done')
Forma de la matriz de distancias: (200, 200)
Matriz de distancias calculada y visualizada (primeros 50 elementos).
done
# Crear un dataframe con las distancias euclídeas entre algunos clientesimport pandas as pdimport numpy as npfrom scipy.spatial.distance import pdist, squareformfrom sklearn.preprocessing import StandardScaler# Cargar los datosdf = pd.read_csv('Mall_Customers.csv')# Extraer las variables para el análisisfeatures = df[['Annual Income (k$)', 'Spending Score (1-100)']]# Estandarizar las variablesscaler = StandardScaler()features_scaled = scaler.fit_transform(features)# Calcular la matriz de distancias euclídeasdist_matrix = squareform(pdist(features_scaled, metric='euclidean'))# Crear un dataframe con las distancias# Seleccionamos los primeros 10 clientes para una visualización más claran_samples =10dist_df = pd.DataFrame(dist_matrix[:n_samples, :n_samples])# Añadir etiquetas para identificar a los clientescustomer_labels = [f"Cliente {i+1}"for i inrange(n_samples)]dist_df.index = customer_labelsdist_df.columns = customer_labels# Mostrar el dataframe de distanciasprint("Matriz de distancias euclídeas entre los primeros 10 clientes:")print(dist_df)# Mostrar también los datos originales de estos clientes para contextoprint("\Datos originales de los primeros 10 clientes:")customer_data = df[['CustomerID', 'Age', 'Annual Income (k$)', 'Spending Score (1-100)']].head(n_samples)print(customer_data)# Visualizar la matriz de distancias como un heatmapimport matplotlib.pyplot as pltimport seaborn as snsplt.figure(figsize=(10, 8))sns.heatmap(dist_df, annot=True, cmap='viridis', fmt='.2f')plt.title('Matriz de Distancias Euclídeas entre los primeros 10 clientes')plt.tight_layout()plt.show()# Calcular algunas estadísticas de las distanciasprint("\Estadísticas de las distancias en toda la matriz:")all_distances = dist_matrix[np.triu_indices(dist_matrix.shape[0], k=1)] # Solo el triángulo superior sin la diagonalprint(f"Distancia mínima: {all_distances.min():.4f}")print(f"Distancia máxima: {all_distances.max():.4f}")print(f"Distancia media: {all_distances.mean():.4f}")print(f"Desviación estándar: {all_distances.std():.4f}")# Identificar los pares de clientes con la distancia mínima y máximamin_dist_idx = np.unravel_index(np.argmin(dist_matrix + np.eye(dist_matrix.shape[0]) * np.inf), dist_matrix.shape)max_dist_idx = np.unravel_index(np.argmax(dist_matrix), dist_matrix.shape)print("\Par de clientes con la distancia mínima:")print(f"Cliente {min_dist_idx[0]+1} y Cliente {min_dist_idx[1]+1}: {dist_matrix[min_dist_idx]:.4f}")print(df.iloc[[min_dist_idx[0], min_dist_idx[1]]][['CustomerID', 'Age', 'Annual Income (k$)', 'Spending Score (1-100)']])print("\Par de clientes con la distancia máxima:")print(f"Cliente {max_dist_idx[0]+1} y Cliente {max_dist_idx[1]+1}: {dist_matrix[max_dist_idx]:.4f}")print(df.iloc[[max_dist_idx[0], max_dist_idx[1]]][['CustomerID', 'Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
Estadísticas de las distancias en toda la matriz:
Distancia mínima: 0.0000
Distancia máxima: 5.5015
Distancia media: 1.7554
Desviación estándar: 0.9688
Par de clientes con la distancia mínima:
Cliente 1 y Cliente 2: 1.6305
CustomerID Age Annual Income (k$) Spending Score (1-100)
0 1 19 15 39
1 2 21 15 81
Par de clientes con la distancia máxima:
Cliente 3 y Cliente 200: 5.5015
CustomerID Age Annual Income (k$) Spending Score (1-100)
2 3 20 16 6
199 200 30 137 83
C:\Users\MINEDUCYT\AppData\Local\Temp\ipykernel_10384\586378680.py:60: RuntimeWarning: invalid value encountered in multiply
min_dist_idx = np.unravel_index(np.argmin(dist_matrix + np.eye(dist_matrix.shape[0]) * np.inf), dist_matrix.shape)
# Determinar número óptimo de clustersplt.figure(figsize=(10, 6))last = linked_ext[-10:, 2]last_rev = last[::-1]idxs = np.arange(1, len(last) +1)plt.plot(idxs, last_rev)plt.title('Método del codo para determinar número óptimo de clusters (Variables extendidas)')plt.xlabel('Número de clusters')plt.ylabel('Distancia de enlace')plt.tight_layout()plt.show()
# Basado en el método del codo, elegimos 5 clustersnum_clusters =5clusters_ext = fcluster(linked_ext, num_clusters, criterion='maxclust')
# Agregar los clusters al dataframe originaldf['Cluster_ext'] = clusters_ext# Visualizar los clusters en 3Dfig = plt.figure(figsize=(12, 10))ax = fig.add_subplot(111, projection='3d')scatter = ax.scatter(df['Age'], df['Annual Income (k$)'], df['Spending Score (1-100)'], c=df['Cluster_ext'], cmap='viridis', s=50, alpha=0.8)plt.colorbar(scatter, label='Cluster')ax.set_title(f'Clustering Jerárquico 3D con {num_clusters} clusters')ax.set_xlabel('Age')ax.set_ylabel('Annual Income (k$)')ax.set_zlabel('Spending Score (1-100)')plt.tight_layout()plt.show()
# Estadísticas por clustercluster_ext_stats = df.groupby('Cluster_ext')[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']].agg(['mean', 'std', 'min', 'max'])print("Estadísticas por cluster (Variables extendidas):")print(cluster_ext_stats)
Estadísticas por cluster (Variables extendidas):
Age Annual Income (k$) \
mean std min max mean std min
Cluster_ext
1 43.892857 8.337063 32 59 91.285714 16.915601 71
2 44.318182 12.800247 19 67 25.772727 7.646548 15
3 56.400000 8.373117 43 70 55.288889 9.834129 38
4 32.692308 3.728650 27 40 86.538462 16.312485 69
5 26.560606 7.043008 18 45 47.363636 18.328319 15
Spending Score (1-100)
max mean std min max
Cluster_ext
1 137 16.678571 8.973432 1 39
2 39 20.272727 12.947446 3 40
3 79 48.355556 6.869417 35 60
4 137 82.128205 9.364489 63 97
5 81 56.787879 20.628222 5 99
# Mostrar las primeras filas con la asignación de clustersprint("Asignación de clusters (Variables extendidas):")print(df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)', 'Cluster_ext']].head())print("Análisis de clustering jerárquico con variables extendidas completado.")
Asignación de clusters (Variables extendidas):
Age Annual Income (k$) Spending Score (1-100) Cluster_ext
0 19 15 39 2
1 21 15 81 5
2 20 16 6 2
3 23 16 77 5
4 31 17 40 2
Análisis de clustering jerárquico con variables extendidas completado.
# Cargar los datosimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeansfrom sklearn.preprocessing import StandardScalerimport seaborn as sns# Cargar los datosdf = pd.read_csv('Mall_Customers.csv')# Extraer las variables para el análisisfeatures = df[['Annual Income (k$)', 'Spending Score (1-100)']]# Estandarizar las variablesscaler = StandardScaler()features_scaled = scaler.fit_transform(features)# Aplicar K-means con 5 clusterskmeans = KMeans(n_clusters=5, random_state=42)df['Cluster'] = kmeans.fit_predict(features_scaled)# Contar cuántos individuos hay en cada clustercluster_counts = df['Cluster'].value_counts().sort_index()print("Número de individuos por cluster:")print(cluster_counts)# Crear una tabla con información detallada de cada clustercluster_info = pd.DataFrame()# Para cada cluster, mostrar estadísticasfor cluster insorted(df['Cluster'].unique()): cluster_data = df[df['Cluster'] == cluster]# Calcular estadísticas stats = {'Cluster': cluster,'Número de clientes': len(cluster_data),'Edad promedio': round(cluster_data['Age'].mean(), 2),'Ingreso anual promedio (k$)': round(cluster_data['Annual Income (k$)'].mean(), 2),'Puntuación de gasto promedio': round(cluster_data['Spending Score (1-100)'].mean(), 2),'Edad mínima': cluster_data['Age'].min(),'Edad máxima': cluster_data['Age'].max(),'Ingreso mínimo (k$)': cluster_data['Annual Income (k$)'].min(),'Ingreso máximo (k$)': cluster_data['Annual Income (k$)'].max(),'Gasto mínimo': cluster_data['Spending Score (1-100)'].min(),'Gasto máximo': cluster_data['Spending Score (1-100)'].max() }# Añadir a la tabla de información cluster_info = pd.concat([cluster_info, pd.DataFrame([stats])], ignore_index=True)# Mostrar la tabla de información de clustersprint("\Información detallada de cada cluster:")print(cluster_info[['Cluster', 'Número de clientes', 'Edad promedio', 'Ingreso anual promedio (k$)', 'Puntuación de gasto promedio']])print("\Rangos de valores por cluster:")print(cluster_info[['Cluster', 'Edad mínima', 'Edad máxima', 'Ingreso mínimo (k$)', 'Ingreso máximo (k$)', 'Gasto mínimo', 'Gasto máximo']])# Visualizar los clustersplt.figure(figsize=(10, 8))scatter = plt.scatter(df['Annual Income (k$)'], df['Spending Score (1-100)'], c=df['Cluster'], cmap='viridis', s=100, alpha=0.7)plt.xlabel('Ingreso Anual (k$)')plt.ylabel('Puntuación de Gasto (1-100)')plt.title('Segmentación de Clientes con K-means')plt.colorbar(scatter, label='Cluster')plt.grid(True, linestyle='--', alpha=0.7)plt.tight_layout()plt.show()# Mostrar algunos ejemplos de clientes de cada clusterprint("\Ejemplos de clientes por cluster:")for cluster insorted(df['Cluster'].unique()):print(f"\Cluster {cluster}:") sample_customers = df[df['Cluster'] == cluster].sample(min(5, len(df[df['Cluster'] == cluster])), random_state=42)print(sample_customers[['CustomerID', 'Age', 'Annual Income (k$)', 'Spending Score (1-100)']])
# Supongamos que el nuevo individuo tiene: nuevo_individuo = [[50, 60]] # Estandarizamos usando el mismo objeto scaler entrenado anteriormente: nuevo_individuo_escalado = scaler.transform(nuevo_individuo) # Prediciendo el cl\u00faster cluster_nuevo = kmeans.predict(nuevo_individuo_escalado) print("El nuevo individuo pertenece al cl\u00faster:", cluster_nuevo[0])
El nuevo individuo pertenece al clúster: 0
C:\Users\MINEDUCYT\AppData\Local\Programs\Python\Python312\Lib\site-packages\sklearn\utils\validation.py:2739: UserWarning: X does not have valid feature names, but StandardScaler was fitted with feature names
warnings.warn(
# Cargar los datos y preparar el modeloimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeansfrom sklearn.preprocessing import StandardScalerimport seaborn as sns# Cargar los datosdf = pd.read_csv('Mall_Customers.csv')# Extraer las variables para el análisisfeatures = df[['Annual Income (k$)', 'Spending Score (1-100)']]# Estandarizar las variablesscaler = StandardScaler()features_scaled = scaler.fit_transform(features)# Aplicar K-means con 5 clusterskmeans = KMeans(n_clusters=5, random_state=42)kmeans.fit(features_scaled)df['Cluster'] = kmeans.labels_# Función para predecir el cluster de nuevos individuosdef predecir_cluster(nuevos_individuos, scaler, modelo):""" Predice el cluster al que pertenecen nuevos individuos. Parámetros: nuevos_individuos -- DataFrame con las columnas 'Annual Income (k$)' y 'Spending Score (1-100)' scaler -- objeto StandardScaler ya entrenado modelo -- modelo KMeans ya entrenado Retorna: DataFrame con los datos originales y la columna 'Cluster_Predicho' """# Extraer características features_nuevos = nuevos_individuos[['Annual Income (k$)', 'Spending Score (1-100)']]# Estandarizar features_nuevos_scaled = scaler.transform(features_nuevos)# Predecir clusters_predichos = modelo.predict(features_nuevos_scaled)# Añadir predicciones al DataFrame nuevos_individuos_con_cluster = nuevos_individuos.copy() nuevos_individuos_con_cluster['Cluster_Predicho'] = clusters_predichosreturn nuevos_individuos_con_cluster# Ejemplo: Crear un conjunto de nuevos individuosnuevos_individuos = pd.DataFrame({'ID': range(1, 11),'Age': [25, 30, 45, 22, 50, 35, 28, 40, 55, 33],'Annual Income (k$)': [30, 70, 50, 20, 90, 40, 25, 85, 35, 75],'Spending Score (1-100)': [70, 80, 50, 90, 20, 60, 75, 30, 10, 85]})# Predecir clusters para los nuevos individuosnuevos_con_cluster = predecir_cluster(nuevos_individuos, scaler, kmeans)# Mostrar resultadosprint("Nuevos individuos con sus clusters predichos:")print(nuevos_con_cluster)# Visualizar los nuevos individuos en el espacio de características junto con los clusters existentesplt.figure(figsize=(12, 8))# Graficar los datos originalesscatter_orig = plt.scatter(df['Annual Income (k$)'], df['Spending Score (1-100)'], c=df['Cluster'], cmap='viridis', s=80, alpha=0.5, label='Datos originales')# Graficar los nuevos individuosscatter_new = plt.scatter(nuevos_con_cluster['Annual Income (k$)'], nuevos_con_cluster['Spending Score (1-100)'], c=nuevos_con_cluster['Cluster_Predicho'], cmap='viridis', s=150, alpha=1.0, edgecolors='black', linewidth=1.5, marker='*', label='Nuevos individuos')# Añadir etiquetas de ID a los nuevos individuosfor i, txt inenumerate(nuevos_con_cluster['ID']): plt.annotate(txt, (nuevos_con_cluster['Annual Income (k$)'].iloc[i], nuevos_con_cluster['Spending Score (1-100)'].iloc[i]), xytext=(5, 5), textcoords='offset points')plt.xlabel('Ingreso Anual (k$)')plt.ylabel('Puntuación de Gasto (1-100)')plt.title('Predicción de Clusters para Nuevos Individuos')plt.colorbar(scatter_orig, label='Cluster')plt.grid(True, linestyle='--', alpha=0.7)plt.legend()plt.tight_layout()plt.show()# Crear una función para predecir clusters de forma interactivadef predecir_cluster_interactivo(ingresos, gastos, scaler, modelo):""" Predice el cluster para un conjunto de ingresos y gastos. Parámetros: ingresos -- lista de ingresos anuales en k$ gastos -- lista de puntuaciones de gasto (1-100) scaler -- objeto StandardScaler ya entrenado modelo -- modelo KMeans ya entrenado Retorna: DataFrame con los datos y sus clusters predichos """# Crear DataFrame datos = pd.DataFrame({'ID': range(1, len(ingresos) +1),'Annual Income (k$)': ingresos,'Spending Score (1-100)': gastos })# Extraer características features = datos[['Annual Income (k$)', 'Spending Score (1-100)']]# Estandarizar features_scaled = scaler.transform(features)# Predecir clusters = modelo.predict(features_scaled)# Añadir predicciones datos['Cluster_Predicho'] = clustersreturn datos# Ejemplo de uso de la función interactivaingresos_ejemplo = [45, 65, 30, 80, 25]gastos_ejemplo = [55, 75, 85, 25, 35]resultado_interactivo = predecir_cluster_interactivo(ingresos_ejemplo, gastos_ejemplo, scaler, kmeans)print("\Ejemplo de predicción interactiva:")print(resultado_interactivo)# Mostrar características de cada cluster para interpretaciónprint("\Características de cada cluster:")for cluster insorted(df['Cluster'].unique()): cluster_data = df[df['Cluster'] == cluster]print(f"\Cluster {cluster}:")print(f" Ingreso anual promedio: {cluster_data['Annual Income (k$)'].mean():.2f} k$")print(f" Puntuación de gasto promedio: {cluster_data['Spending Score (1-100)'].mean():.2f}")print(f" Número de clientes: {len(cluster_data)}")# Crear una función para guardar el modelo y el scalerdef guardar_modelo_clustering(modelo, scaler, nombre_archivo="modelo_clustering.pkl"):""" Guarda el modelo de clustering y el scaler para uso futuro. Parámetros: modelo -- modelo KMeans entrenado scaler -- objeto StandardScaler entrenado nombre_archivo -- nombre del archivo para guardar """import pickle# Crear un diccionario con el modelo y el scaler modelo_completo = {'modelo': modelo,'scaler': scaler }# Guardar en un archivowithopen(nombre_archivo, 'wb') as archivo: pickle.dump(modelo_completo, archivo)print(f"Modelo guardado como '{nombre_archivo}'")# Instrucciones para cargar el modeloprint("\Para cargar y usar el modelo en el futuro:")print("import pickle")print(f"with open('{nombre_archivo}', 'rb') as archivo:")print(" modelo_cargado = pickle.load(archivo)")print("scaler_cargado = modelo_cargado['scaler']")print("kmeans_cargado = modelo_cargado['modelo']")print("# Luego puedes usar scaler_cargado.transform() y kmeans_cargado.predict()")# Guardar el modeloguardar_modelo_clustering(kmeans, scaler)
Ejemplo de predicción interactiva:
ID Annual Income (k$) Spending Score (1-100) Cluster_Predicho
0 1 45 55 0
1 2 65 75 1
2 3 30 85 2
3 4 80 25 3
4 5 25 35 4
Características de cada cluster:
Cluster 0:
Ingreso anual promedio: 55.30 k$
Puntuación de gasto promedio: 49.52
Número de clientes: 81
Cluster 1:
Ingreso anual promedio: 86.54 k$
Puntuación de gasto promedio: 82.13
Número de clientes: 39
Cluster 2:
Ingreso anual promedio: 25.73 k$
Puntuación de gasto promedio: 79.36
Número de clientes: 22
Cluster 3:
Ingreso anual promedio: 88.20 k$
Puntuación de gasto promedio: 17.11
Número de clientes: 35
Cluster 4:
Ingreso anual promedio: 26.30 k$
Puntuación de gasto promedio: 20.91
Número de clientes: 23
Modelo guardado como 'modelo_clustering.pkl'
Para cargar y usar el modelo en el futuro:
import pickle
with open('modelo_clustering.pkl', 'rb') as archivo:
modelo_cargado = pickle.load(archivo)
scaler_cargado = modelo_cargado['scaler']
kmeans_cargado = modelo_cargado['modelo']
# Luego puedes usar scaler_cargado.transform() y kmeans_cargado.predict()
# Cargar datos con header inferido del archivoimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsfrom sklearn.cluster import AgglomerativeClusteringfrom sklearn.preprocessing import StandardScalerfrom scipy.cluster.hierarchy import dendrogram, linkage# Verificar la versión de scikit-learnimport sklearnprint(f"Versión de scikit-learn: {sklearn.__version__}")# Leer CSV asumiendo que el archivo tiene headermall_df = pd.read_csv('Mall_Customers.csv')# Mostrar primeros registrosprint('Dataframe original:')print(mall_df.head())# Revisar infoprint('\Información del DataFrame:')print(mall_df.info())# Convertir columnas numéricas si es necesarionumeric_cols = ['Age', 'Annual Income (k$)', 'Spending Score (1-100)']for col in numeric_cols: mall_df[col] = pd.to_numeric(mall_df[col], errors='coerce')# Seleccionar características para clusteringfeatures = numeric_colsx = mall_df[features].values# Estandarizarscaler = StandardScaler()x_scaled = scaler.fit_transform(x)# Dendrograma para inspección del número óptimo de clusterslinked = linkage(x_scaled, method='ward')plt.figure(figsize=(10,7))dendrogram(linked, truncate_mode='lastp', p=20)plt.title('Dendrograma - Método Ward')plt.xlabel('Observaciones')plt.ylabel('Distancia')plt.show()# Corregir los parámetros de AgglomerativeClustering# Verificar los parámetros disponiblesprint("\Parámetros disponibles para AgglomerativeClustering:")print(AgglomerativeClustering.__init__.__code__.co_varnames)# Seleccionar número de clusters basado en observación, por ejemplo 5n_clusters =5# Usar los parámetros correctos según la versióntry:# Intentar con los parámetros corregidos cluster_model = AgglomerativeClustering(n_clusters=n_clusters, metric='euclidean', linkage='ward')exceptTypeError:# Si falla, intentar con menos parámetros cluster_model = AgglomerativeClustering(n_clusters=n_clusters)cluster_labels = cluster_model.fit_predict(x_scaled)mall_df['Cluster'] = cluster_labels# Mostrar la cantidad de individuos por clusterprint('Cantidad de individuos por cluster:')print(mall_df['Cluster'].value_counts().sort_index())# Mostrar tabla de individuos y sus clustersprint('\Ejemplo de tabla con clusters:')print(mall_df[['CustomerID','Age','Annual Income (k$)', 'Spending Score (1-100)', 'Cluster']].head(10))# Graficar los clusters: Ingreso vs Puntuación de Gastoplt.figure(figsize=(8,6))sns.scatterplot(data=mall_df, x='Annual Income (k$)', y='Spending Score (1-100)', hue='Cluster', palette='Set1', s=80)plt.title('Clusters: Ingreso vs Puntuación de Gasto')plt.show()# Graficar: Edad vs Puntuación de Gastoplt.figure(figsize=(8,6))sns.scatterplot(data=mall_df, x='Age', y='Spending Score (1-100)', hue='Cluster', palette='Set2', s=80)plt.title('Clusters: Edad vs Puntuación de Gasto')plt.show()# Función para predecir el cluster de nuevos individuos# Nota: AgglomerativeClustering no tiene método 'predict'. Calculamos centroides a partir de los datos escalados.centroids = []for i inrange(n_clusters): cent = x_scaled[mall_df['Cluster'] == i].mean(axis=0) centroids.append(cent)centroids = np.array(centroids)from scipy.spatial.distance import cdistdef predecir_cluster(nuevos_datos):''' nuevos_datos: array-like de forma (n_ejemplos, 3) en el orden: Age, Annual Income (k$), Spending Score (1-100) '''# Estandarizar nuevos datos con el scaler previamente calculado nuevos_scaled = scaler.transform(nuevos_datos)# Calcular la distancia a cada centroide dists = cdist(nuevos_scaled, centroids, metric='euclidean')# El índice del centroide más cercano es el cluster asignadoreturn np.argmin(dists, axis=1)# Ejemplo de predicción para dos nuevos individuosnuevos = np.array([[25, 40, 60], [40, 70, 20]])predicciones = predecir_cluster(nuevos)print('\Predicción de clusters para nuevos individuos:')print(predicciones)print('done')
Versión de scikit-learn: 1.6.1
Dataframe original:
CustomerID Genre Age Annual Income (k$) Spending Score (1-100)
0 1 Male 19 15 39
1 2 Male 21 15 81
2 3 Female 20 16 6
3 4 Female 23 16 77
4 5 Female 31 17 40
Información del DataFrame:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 CustomerID 200 non-null int64
1 Genre 200 non-null object
2 Age 200 non-null int64
3 Annual Income (k$) 200 non-null int64
4 Spending Score (1-100) 200 non-null int64
dtypes: int64(4), object(1)
memory usage: 7.9+ KB
None
Predicción de clusters para nuevos individuos:
[0 3]
done
import matplotlib.pyplot as pltimport seaborn as snsimport numpy as np# Creamos el scatter plot base para 'Annual Income (k$)' vs 'Spending Score (1-100)'plt.figure(figsize=(8,6))sns.scatterplot(data=mall_df, x='Annual Income (k$)', y='Spending Score (1-100)', hue='Cluster', palette='Set1', s=80, legend='brief')# Nuevos individuosnuevos = np.array([[25, 40, 60], [40, 70, 20]])predicciones = predecir_cluster(nuevos)# Para asignar colores, obtendremos las paletas de colores para clusterspalette = sns.color_palette('Set1', n_colors=5)# Graficar los nuevos individuos usando marcas de estrella y el color correspondientefor i, (p, cluster) inenumerate(zip(nuevos, predicciones)):# p tiene el formato: [Age, Annual Income (k$), Spending Score (1-100)]# Queremos graficar Ingreso vs Score, que son las columnas 1 y 2 respectivamente plt.scatter(p[1], p[2], s=200, marker='*', color=palette[cluster], edgecolor='black', label='Nuevo individuo '+str(i+1) if i==0else"")plt.title('Clusters: Ingreso vs Puntuación de Gasto(incluyendo nuevosindividuos)')plt.xlabel('Annual Income (k$)')plt.ylabel('Spending Score (1-100)')plt.legend()plt.show()print('done')
done
UNA FORMA MAS ORDENADA
# Import necessary librariesimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsfrom sklearn.cluster import KMeans, AgglomerativeClusteringfrom scipy.cluster.hierarchy import dendrogram, linkagefrom sklearn.metrics import silhouette_score
# Cargar el datasetfile_path ='Mall_Customers.csv'df = pd.read_csv(file_path, encoding='ascii')# Revisar head del datasetprint('Primeras filas del dataset:')print(df.head())
Primeras filas del dataset:
CustomerID Genre Age Annual Income (k$) Spending Score (1-100)
0 1 Male 19 15 39
1 2 Male 21 15 81
2 3 Female 20 16 6
3 4 Female 23 16 77
4 5 Female 31 17 40
# Voy a usar las siguientes columnas para clustering: 'Annual Income (k$)' y 'Spending Score (1-100)'.# Estos dos son populares para analizar clusters en el dataset Mall CustomersX = df[['Annual Income (k$)', 'Spending Score (1-100)']].values# Escalado (opcional, pero aquí las variables tienen rangos similares, así que lo omitiremos)# ------------------------------# Clustering Jerárquico# ------------------------------# Cálculo del linkage matrix usando WardZ = linkage(X, method='ward')
# Usando AgglomerativeClustering para asignar clusters (corregido)# Usamos 5 clusters como ejemplo, que es usual en Mall Customersagg_model = AgglomerativeClustering(n_clusters=5, metric='euclidean', linkage='ward')clusters_hier = agg_model.fit_predict(X)# Añadir la asignación al DFdf['Cluster_Hier'] = clusters_hier# Tabla de conteo por clustertable_hier = df['Cluster_Hier'].value_counts().sort_index()print('Conteo de individuos por cluster - Clustering Jerárquico:')print(table_hier)
# ------------------------------# Clustering K-means# ------------------------------# El método del codo para seleccionar k óptimoinertias = []k_vals =range(1, 11)for k in k_vals: kmeans_temp = KMeans(n_clusters=k, random_state=42) kmeans_temp.fit(X) inertias.append(kmeans_temp.inertia_)plt.figure(figsize=(8,5))plt.plot(k_vals, inertias, 'bo-')plt.xlabel('Número de clusters (k)')plt.ylabel('Inercia')plt.title('Método del Codo para K-means')plt.show()
# Seleccionar k=5 basado en el dendrograma y el método del codok_opt =5kmeans = KMeans(n_clusters=k_opt, random_state=42)clusters_km = kmeans.fit_predict(X)
# Agregar clusters K-means al DFdf['Cluster_Kmeans'] = clusters_km# Tabla de conteo por clustertable_km = df['Cluster_Kmeans'].value_counts().sort_index()print('Conteo de individuos por cluster - K-means:')print(table_km)
# Calcular la "precisión" del modelo en términos de la puntuación de silhouettesilhouette_km = silhouette_score(X, clusters_km)silhouette_hier = silhouette_score(X, clusters_hier)print('Silhouette Score para K-means: '+str(round(silhouette_km,4)))print('Silhouette Score para Clustering Jerárquico: '+str(round(silhouette_hier,4)))
Silhouette Score para K-means: 0.5539
Silhouette Score para Clustering Jerárquico: 0.553
# Visualización de clusters - K-meansplt.figure(figsize=(8,6))sns.scatterplot(x=df['Annual Income (k$)'], y=df['Spending Score (1-100)'], hue=df['Cluster_Kmeans'], palette='Set1', s=100, legend='full')plt.scatter(kmeans.cluster_centers_[:,0], kmeans.cluster_centers_[:,1], s=300, c='black', marker='X', label='Centroides')plt.title('Clusters con K-means')plt.xlabel('Annual Income (k$)')plt.ylabel('Spending Score (1-100)')plt.legend()plt.show()
# Visualización de clusters - Jerárquicoplt.figure(figsize=(8,6))sns.scatterplot(x=df['Annual Income (k$)'], y=df['Spending Score (1-100)'], hue=df['Cluster_Hier'], palette='Set2', s=100, legend='full')plt.title('Clusters con Clustering Jerárquico')plt.xlabel('Annual Income (k$)')plt.ylabel('Spending Score (1-100)')plt.legend()plt.show()
# Mostrar la tabla con la asignación de clusters para K-means (individuales)cluster_assignments = df[['CustomerID', 'Cluster_Kmeans']]print('Asignación de cada individuo a clusters (K-means):')print(cluster_assignments.head(10))
# Función de predicción para nuevos individuos usando el modelo kmeansdef predecir_cluster(annual_income, spending_score): datos = np.array([[annual_income, spending_score]]) cluster_pred = kmeans.predict(datos)return cluster_pred[0]# Ejemplo de predicción para un nuevo individuonuevo_individuo = {'Annual Income (k$)': 70, 'Spending Score (1-100)': 40}pred_cluster = predecir_cluster(nuevo_individuo['Annual Income (k$)'], nuevo_individuo['Spending Score (1-100)'])print('El nuevo individuo se asigna al cluster (K-means): '+str(pred_cluster))
El nuevo individuo se asigna al cluster (K-means): 0
# Visualización mejorada con factoextra styleplt.figure(figsize=(10,8))# Crear un gráfico de dispersión con colores por clusterax = sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)', hue='Cluster_Kmeans', data=df, palette='viridis', s=100, alpha=0.8)# Añadir centroidesplt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=200, c='red', marker='X', edgecolor='black', linewidth=1.5, label='Centroides')# Añadir etiquetas para cada centroidefor i, centroid inenumerate(kmeans.cluster_centers_): plt.annotate(f'Cluster {i}', xy=(centroid[0], centroid[1]), xytext=(centroid[0]+2, centroid[1]+2), fontsize=12, fontweight='bold')# Personalizar el gráficoplt.title('Análisis de Clusters K-means con Estilo Factoextra', fontsize=16, fontweight='bold')plt.xlabel('Ingreso Anual (k$)', fontsize=14)plt.ylabel('Puntuación de Gasto (1-100)', fontsize=14)plt.grid(True, linestyle='--', alpha=0.7)plt.legend(title='Clusters', fontsize=12, title_fontsize=13)# Añadir un recuadro alrededor del gráficoax.spines['top'].set_visible(True)ax.spines['right'].set_visible(True)ax.spines['bottom'].set_visible(True)ax.spines['left'].set_visible(True)for spine in ax.spines.values(): spine.set_linewidth(1.5)plt.tight_layout()plt.show()
# Crear una tabla más detallada con información de los clusterscluster_summary = df.groupby('Cluster_Kmeans').agg({'CustomerID': 'count','Annual Income (k$)': ['mean', 'min', 'max'],'Spending Score (1-100)': ['mean', 'min', 'max']}).round(2)cluster_summary.columns = ['Cantidad', 'Ingreso Promedio', 'Ingreso Mínimo', 'Ingreso Máximo', 'Gasto Promedio', 'Gasto Mínimo', 'Gasto Máximo']print("Resumen estadístico por cluster (K-means):")print(cluster_summary)
# Crear una visualización de la distribución de clustersplt.figure(figsize=(12, 5))# Gráfico de barras para el conteo de individuos por clusterplt.subplot(1, 2, 1)sns.countplot(x='Cluster_Kmeans', data=df, palette='viridis')plt.title('Número de Clientes por Cluster')plt.xlabel('Cluster')plt.ylabel('Cantidad de Clientes')
C:\Users\MINEDUCYT\AppData\Local\Temp\ipykernel_10384\1395649029.py:6: FutureWarning:
Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect.
sns.countplot(x='Cluster_Kmeans', data=df, palette='viridis')
Text(0, 0.5, 'Cantidad de Clientes')
# Gráfico de pastel para la proporción de clustersplt.subplot(1, 2, 2)df['Cluster_Kmeans'].value_counts().plot.pie(autopct='%1.1f%%', colors=sns.color_palette('viridis', n_colors=5), wedgeprops={'linewidth': 1, 'edgecolor': 'white'})plt.title('Proporción de Clientes por Cluster')plt.ylabel('')plt.tight_layout()plt.show()