Warning: package 'tidyverse' was built under R version 4.3.3
Warning: package 'forcats' was built under R version 4.3.2
Warning: package 'lubridate' was built under R version 4.3.3
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.3 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.4 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.0
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(factoextra)
Warning: package 'factoextra' was built under R version 4.3.3
Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(cluster)
Warning: package 'cluster' was built under R version 4.3.3
library(GGally)
Warning: package 'GGally' was built under R version 4.3.2
Registered S3 method overwritten by 'GGally':
method from
+.gg ggplot2
1.2 Leer los datos
mayoristas <-read_csv("C:/Users/MINEDUCYT/Desktop/CICLOI_2025/SeminarioI/Datos de clientes mayoristas.csv")
Rows: 440 Columns: 8
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
dbl (8): Channel, Region, Fresh, Milk, Grocery, Frozen, Detergents_Paper, De...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
En este resultado, eliminamos las columnas channel y region, las columnas restantes son de tipo dbl que son de tipo numericos.
1.6 Escalar los datos
mayoristas_scaled <-scale(mayoristas_features)
Escalamos los datos, este es un proceso en la cula transformamos los valores numericos de nuestra base de datos para que así, todas las variables estan en la misma escala.
Para nuestro grafico de las correlaciones, observanmos unas correlaciones fuertes como los son: milk y grocery con una correlacion de 0.73, milk y detergents_paper con una correlación de 0.66 y grocery con detergents_paper con una correlacion de 0.92, esta correlacion es extremadamente alta lo que nos indica que los clientes que compran muchos productos de abarrotes, tambien suelen comprar muchos productos de limpieza/papel. Las demas correlaciones son bajas.
En el eje x observamos el numero de clusters de 1 a 10, en el eje y es la suma total de los cuadrados dentro de los clusters. Ya que definimos 5 cluster que esta indicado por la línea de puntos vertical.
Observamos que se añadio una nueva columna llamada cluster, que representa lo que es la signacion de cada observacion (cliente) a uno de los 5 grupos que identificamos con k-means.
Ejemplo: fresh = 12669, milk = 9656, grocery = 7561, detergents = 2674, delicassen = 1338 y cluster = 2. Decimos que el cliente con consumos altos en casi todo pero es más en frescos y leche y a sido asignado en el cluster 2 que si observamos es el grupo mas numeroso.
En esta tabla muestra lo que son los resultados de lo que es un análisis de componentes principales (PCA) combinado con lo que es asignación de clusters.
PC1 y PC2 son las primeras 2 componentes principales extraidas de un conjunto de datos. Por ejemplo el primer registro tiene valores PC1= -0.1930708 y PC2 0.30475306 lo que representa su posicion en este nuevo espacio. Este pertenece al cluster 2.
En tu tabla hay al menos tres clústeres identificados: 1, 2, 4.
1.12 Visualización PCA
ggplot(pca_df, aes(PC1, PC2, color = cluster)) +geom_point(size =3, alpha =0.8) +theme_minimal() +labs(title ="Clústeres visualizados con PCA")
El grafico muestra puntos que estan representando observaciones del conjunto de datos, en el eje x es el primer componente principal y en el eje y es el segundo componente.
Cada punto esta coloreado segun al cluster que pertenece del 1 al 5. Los clústeres 1 (rojo), 2 (verde mostaza), y 3 (verde) parecen estar más agrupados entre sí, miestras que el clúster 4 (celeste) y el clúster 5 (morado) están más dispersos o alejados, lo que puede indicar que datos atipicos o grupos más heterogéneos o que estan menos relacionados con los otros cluster.
ggplot(perfil_largo, aes(x = Variable, y = Promedio, fill = cluster)) +geom_bar(stat ="identity", position ="dodge") +theme_minimal() +coord_flip() +labs(title ="Perfil de gasto por clúster")
En el eje y muetra las variables y en eje x muestra lo que son los promedios de gastos.
Los cluster están representados en diferentes colores para poderlos identificar.
El cluster 1 tiene un gasto muy alto en lo que es la categoria fresh.
El cluster 2 tambien destaca mucho en la categoria fresh
El cluster 3 parece tener un gasto algo balanceado y es alto en milk, grocery, detergents_paper
El cluster 4 tiene un gasto bajo en general
El cluster 5 gasta mas significativamente en casi todas las categorias especialmente en detergents_paper, grocery y milk.
library(ggplot2)library(factoextra)# Genera el gráfico (sin plotly aún)p <-fviz_cluster(kmeans_result, data = mayoristas_scaled,palette =c("#8B0000", "#006400", "#8B008B", "#00008B", "#FFA500"),ellipse.type ="euclid", star.plot =TRUE, repel =TRUE, ggtheme =theme_minimal())# carga plotlylibrary(plotly)
Warning: package 'plotly' was built under R version 4.3.3
Attaching package: 'plotly'
The following object is masked from 'package:ggplot2':
last_plot
The following object is masked from 'package:stats':
filter
The following object is masked from 'package:graphics':
layout
# Convierte el gráfico a interactivoggplotly(p)
Too few points to calculate an ellipse
Warning in geom2trace.default(dots[[1L]][[5L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
If you'd like to see this geom implemented,
Please open an issue with your example code at
https://github.com/ropensci/plotly/issues
Warning in geom2trace.default(dots[[1L]][[5L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
If you'd like to see this geom implemented,
Please open an issue with your example code at
https://github.com/ropensci/plotly/issues
Warning in geom2trace.default(dots[[1L]][[5L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
If you'd like to see this geom implemented,
Please open an issue with your example code at
https://github.com/ropensci/plotly/issues
Warning in geom2trace.default(dots[[1L]][[5L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
If you'd like to see this geom implemented,
Please open an issue with your example code at
https://github.com/ropensci/plotly/issues
Warning in geom2trace.default(dots[[1L]][[5L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
If you'd like to see this geom implemented,
Please open an issue with your example code at
https://github.com/ropensci/plotly/issues
La dimension1 explica el 44.1% de lo que es la variabilidad total.
La dimesion 2 explica el 28.4% de la variabilidad total.
Juntas las dos dimensiones capturan lo que es el 72.5% de la informacion del nuestro conjunto de datos original.
El cluster 1, 2, 3 y 4 estan agrupados mas cercamente, miestras que el cluster 5 parece tener lo que es un solo individuo y esta muy alejado del resto de clusters.
1.15 Estimacion del numero optimo de conglomerados
#Método del codo para determinar k óptimolibrary(cluster)library(factoextra)fviz_nbclust(mayoristas_scaled, pam, method ="silhouette")+theme_classic()
En el eje x observamos el numero de clusters de 1 a 10, en el eje y es la suma total de los cuadrados dentro de los clusters. Se observa que necesitamos 2 cluster que esta indicado por la línea de puntos vertical azul.
1.16 Calculo PAM clustering
#K-Means con k = 2#PAM (Partitioning Around Medoids) es un algoritmo que: Agrupa los datos en k clústeres (al igual que k-means).pam.may <-pam(mayoristas_scaled, 2)print(pam.may)
Cada fila esta representa por un cliente mayorista, y las columnas muestran su consumo en diferentes categorías de productos, junto con el grupo (cluster) al que fue asignado.
Por ejemplo el cluster 1 posee alto consumo de fresh con 12,669, milk con 9,656 y grocery con 7,561; por otro lado se observa que existe bajo consumo en frozen con 214 y delicassen con 1,338 y pertenece al cluster 1.
1.17 Accediendo a los resultados de la funcion pam()
Esta tabla muestra los centros representativos (medoides) de cada cluster.
Cluster1: tiene valores negativos en todas las variables que corresponde a clientes con bajo consumo en milk, grocery y detergents_paper que representan clientes con alto consumo en esos productos
Cluster2: Valores positivos en milk, grocery, detergents_paper y delicassen que son clientes con alto consumo en esos productos.
head(pam.may$clustering)
[1] 1 2 2 1 1 1
Esta parte muestra los clusters asignados a los primeros clientes de la base de datos por ejemplo:
1 2 2 1 1 1
Cliente 1 → Cluster 1
Cliente 2 → Cluster 2
Cliente 3 → Cluster 2
Cliente 4 → Cluster 1
Cliente 5 → Cluster 1
Cliente 6 → Cluster 1
1.18 Visualizacion PAM clusters
library(ggplot2)library(dplyr)library(cluster)library(factoextra)# Funciónreplace_null <-function(x, y, ...) {if (is.null(x)) y else x}fviz_cluster(pam.may, palette =c("#EE82EE", "#9ACD32"), ellipse.type ="t", repel =TRUE)
Se observan los ejes representados por Dim1 y Dim2 que son las primeras dos dimensiones principales generadas a partir del analisis de componentes principales que le aplicamos a la base de datos.
La Dim1 explica el 44.1% de la varibilidad y la Dim2 explica el 28.4% y en conjunto el grafico muestra casi un 72.5% de lo que es la varibilidad total de la base de datos.
import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsfrom sklearn.preprocessing import StandardScalerfrom sklearn.cluster import KMeansfrom sklearn.decomposition import PCAfrom sklearn.metrics import silhouette_score
2.2 Leer los datos
import pandas as pdmayoristas = pd.read_csv("C:/Users/MINEDUCYT/Desktop/CICLOI_2025/SeminarioI/Datos de clientes mayoristas.csv")print(mayoristas.head(10))
cor_matrix = pd.DataFrame(mayoristas_scaled, columns=mayoristas_features.columns).corr()plt.figure(figsize=(10, 8))sns.heatmap(cor_matrix, annot=True, cmap="coolwarm", fmt=".2f")plt.title("Matriz de correlación")plt.show()
2.7 Método del codo para determinar el número óptimo de clústeres
from sklearn.cluster import KMeansfrom sklearn.decomposition import PCAimport matplotlib.pyplot as plt# Paso 1: Método del codowcss = []for i inrange(1, 11): kmeans = KMeans(n_clusters=i, random_state=123) kmeans.fit(mayoristas_scaled) wcss.append(kmeans.inertia_)
KMeans(n_clusters=10, random_state=123)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
KMeans(n_clusters=10, random_state=123)
plt.figure(figsize=(8, 5))plt.plot(range(1, 11), wcss, marker="o")plt.axvline(x=2, linestyle="--", color="red") # Aquí seleccionamos 2 clústeresplt.title("Método del Codo")plt.xlabel("Número de clústeres")plt.ylabel("WCSS")plt.show()