datos1<- read.csv("C:/Users/marco/Documents/Rscripts/consumo_clientes.csv")
datos2<- read.csv("C:/Users/marco/Documents/Rscripts/consumo_clientes_2.csv")
En el primer archivo: Todas las variables son de tipo entero (int).
En el segundo archivo: Las variables son de tipo numérico (num). Los datos se encuentran normalizados
# Verificar la estructura de los datos
str(datos1)
## 'data.frame': 32 obs. of 7 variables:
## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Fresh : int 12669 7057 6353 13265 22615 9413 12126 7579 5963 6006 ...
## $ Milk : int 9656 9810 8808 1196 5410 8259 3199 4956 3648 11093 ...
## $ Grocery : int 7561 9568 7684 4221 7198 5126 6975 9426 6192 18881 ...
## $ Frozen : int 214 1762 2405 6404 3915 666 480 1669 425 1159 ...
## $ Detergents_Paper: int 2674 3293 3516 507 1777 1795 3140 3321 1716 7425 ...
## $ Delicassen : int 1338 1776 7844 1788 5185 1451 545 2566 750 2098 ...
str(datos2)
## 'data.frame': 33 obs. of 7 variables:
## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Fresh : num -0.2472 0.4641 0.0107 0.3655 -0.3145 ...
## $ Milk : num -0.617 -0.27 -0.417 -0.792 -0.881 ...
## $ Grocery : num -0.675 -0.386 -0.66 -0.561 -0.193 ...
## $ Frozen : num -0.1426 2.5361 0.2419 -0.0289 0.0362 ...
## $ Detergents_Paper: num -0.6104 -0.1015 0.0639 -0.6931 -0.437 ...
## $ Delicassen : num 0.738 1.948 0.64 0.304 -0.444 ...
# Mostrar las primeras filas
head(datos1)
## X Fresh Milk Grocery Frozen Detergents_Paper Delicassen
## 1 1 12669 9656 7561 214 2674 1338
## 2 2 7057 9810 9568 1762 3293 1776
## 3 3 6353 8808 7684 2405 3516 7844
## 4 4 13265 1196 4221 6404 507 1788
## 5 5 22615 5410 7198 3915 1777 5185
## 6 6 9413 8259 5126 666 1795 1451
head(datos2)
## X Fresh Milk Grocery Frozen Detergents_Paper Delicassen
## 1 1 -0.24716064 -0.6167425 -0.67450893 -0.14255660 -0.61043983 0.7382564
## 2 2 0.46411094 -0.2699829 -0.38625002 2.53605371 -0.10147801 1.9480556
## 3 3 0.01066055 -0.4167840 -0.66000299 0.24190563 0.06385354 0.6401954
## 4 4 0.36550909 -0.7922857 -0.56069315 -0.02892846 -0.69310560 0.3038233
## 5 5 -0.31446968 -0.8809845 -0.19320955 0.03623463 -0.43700379 -0.4441770
## 6 6 -0.31063189 -0.3469376 -0.05670501 -0.45167402 -0.38189328 -0.8865918
Para combinar los datos se debe normalizar las observaciones del primer conjunto de datos (datos1). Al combinarse los datos en la columna X aparecen NA, por lo que deben sobreescribirse este indicador.
# Calcular medias y desviaciones estándar (excluyendo el índice)
medias <- colMeans(datos1[,-1]) # Excluye la primera columna (Unnamed: 0)
desviaciones <- apply(datos1[,-1], 2, sd) # Calcula desviaciones estándar
# Aplicar normalización (z-score)
datos1_normalizado <- as.data.frame(scale(datos1[,-1], center = medias, scale = desviaciones))
# Añadir de nuevo el índice
datos1_normalizado$Unnamed.0 <- datos1$Unnamed.0
# Unir los datos
datos_combinados <- bind_rows(datos1_normalizado, datos2)
# Sobrescribir la columna "X" con una secuencia de 1 a la cantidad de filas
datos_combinados$X <- seq_len(nrow(datos_combinados))
head(datos_combinados)
## Fresh Milk Grocery Frozen Detergents_Paper Delicassen X
## 1 -0.1383067 0.92027590 -0.11506546 -0.81324576 -0.06159416 -0.4056681 1
## 2 -0.7172866 0.95554094 0.25985028 -0.04532845 0.22082648 -0.1756024 2
## 3 -0.7899170 0.72608918 -0.09208856 0.27364495 0.32257091 3.0117006 3
## 4 -0.0768184 -1.01701146 -0.73899102 2.25743132 -1.05029455 -0.1692992 4
## 5 0.8878043 -0.05203168 -0.18287534 1.02271157 -0.47085316 1.6150232 5
## 6 -0.4742223 0.60037159 -0.56993335 -0.58902184 -0.46264060 -0.3463132 6
# Escalar los datos
datos_numericos <- datos_combinados[, sapply(datos_combinados, is.numeric)]
datos_escalados <- scale(datos_numericos)
# Fijar la semilla
set.seed(123)
# Iterar sobre varios valores de k
k_min <- 2 # Mínimo número de clusters
k_max <- 10 # Máximo número de clusters
resultados <- data.frame(
k = k_min:k_max,
tot_withinss = numeric(k_max - k_min + 1),
betweenss = numeric(k_max - k_min + 1)
)
for (k in k_min:k_max) {
agrupamientos <- kmeans(x = datos_escalados, centers = k, nstart = 25)
resultados$tot_withinss[k - k_min + 1] <- agrupamientos$tot.withinss
resultados$betweenss[k - k_min + 1] <- agrupamientos$betweenss
}
# Visualizar los resultados
library(ggplot2)
# Gráfico para elegir el mejor número de clusters (Método del codo)
ggplot(resultados, aes(x = k, y = tot_withinss)) +
geom_line(color = "blue") +
geom_point(color = "red") +
labs(
title = "Metodo del Codo Seleccion del numero optimo de Clusters",
x = "Numero de Clusters",
y = "Suma de Cuadrados Totales Dentro de los Clusters"
) +
theme_minimal()
.
OBS: Se determina visualmente que el número de Clusters óptimo es k=3, debido a que aquí se produce el “codo”.
k <- 3 # Ajusta según el número de clusters elegido
agrupamientos <- kmeans(x = datos_escalados, centers = k, nstart = 25)
# Reducir la dimensionalidad con PCA para graficar en 2D
pca <- prcomp(datos_escalados) # Realiza PCA sobre los datos escalados
pca_data <- data.frame(pca$x[, 1:2]) # Tomar las dos primeras componentes principales
# Agregar los grupos de los clusters a los datos PCA
pca_data$Cluster <- as.factor(agrupamientos$cluster)
# Graficar los agrupamientos
library(ggplot2)
ggplot(pca_data, aes(x = PC1, y = PC2, color = Cluster)) +
geom_point(size = 3, alpha = 0.7) +
labs(
title = paste("Agrupamientos K-Means con k =", k),
x = "Componente Principal 1",
y = "Componente Principal 2"
) +
scale_color_manual(values = c("red", "green", "blue")) + # Colores personalizados
theme_minimal() +
theme(legend.title = element_blank())
.
OBS: Aqui se puede ver 3 grupos (K=3), de los cuales 2 son relativamente
homogeneos (verde y rojo) y el tercero se encuentra disperso (azul)
# Fijar la semilla
set.seed(123)
# Crear el agrupamiento jerárquico (hclust)
agrup_jerar <- hclust(d = dist(x = datos_escalados, method = "euclidean"), method = "complete")
# Asignar cada observación a un agrupamiento (k = número de clusters)
k <- 3
clusters <- cutree(agrup_jerar, k = k)
# Convertir el dendrograma a objeto 'dendrogram'
dendro <- as.dendrogram(agrup_jerar)
# Colorear las ramas de acuerdo con los clusters
dendro <- color_branches(dendro, k = k)
# Mejorar etiquetas
dendro <- set(dendro, "labels_cex", 0.7) # Tamaño de las etiquetas
# Graficar el dendrograma mejorado
plot(
dendro,
main = paste("Dendrograma - Bottom-Up Clustering (k =", k, ")"),
ylab = "Distancia",
xlab = "Observaciones",
sub = "",
cex.main = 1.5, # Tamaño del título
cex.lab = 1.2 # Tamaño de etiquetas de ejes
)
. .
OBS: En este caso se realizan agrupamientos mucho mas pequeños.
# Fijar la semilla
set.seed(123)
# Generar la matriz de distancias
mat_dist <- dist(x = datos_escalados, method = "euclidean")
# Crear el agrupamiento jerárquico (diana)
agrup_jerar_td <- diana(x = mat_dist, diss = TRUE, stand = FALSE)
# Convertir el resultado en un objeto 'dendrogram'
dendro_td <- as.dendrogram(agrup_jerar_td)
# Asignar colores a las ramas
k <- 3 # Número de clusters
dendro_td <- color_branches(dendro_td, k = k)
# Ajustar etiquetas
dendro_td <- set(dendro_td, "labels_cex", 0.7)
# Graficar el dendrograma mejorado
plot(
dendro_td,
main = paste("Dendrograma - Top-Down Clustering (k =", k, ")"),
ylab = "Distancia",
xlab = "Observaciones",
sub = "",
cex.main = 1.5, # Tamaño del título
cex.lab = 1.2 # Tamaño de etiquetas de ejes
)
.
.
OBS: El dendograma Top-Down es mas pertinente con un Custering del orden de 3/4. Por ende es conveniente quedarse con este. Sin embargo a simple vista se observan al menos 5 grupos.
# Calcular la matriz de covarianza de los datos escalados
cov.mat <- cov(datos_escalados)
# Calcular los autovalores y autovectores de la matriz de covarianza
auto.val <- eigen(cov.mat) # Descomposición en autovalores y autovectores
# Calcular la varianza explicada
varianza_explicada <- auto.val$values / sum(auto.val$values) * 100 # Porcentaje de varianza explicada
# Crear un data frame con los componentes y la varianza explicada
df_varianza <- data.frame(
Componente = paste0("PC", seq_along(varianza_explicada)),
Varianza = varianza_explicada
)
# Graficar la varianza explicada para todas las componentes
library(ggplot2)
ggplot(df_varianza, aes(x = Componente, y = Varianza)) +
geom_bar(stat = "identity", fill = "lightblue") +
labs(
title = "Varianza Explicada por Componentes Principales",
x = "Componentes Principales",
y = "Varianza Explicada (%)"
) +
theme_minimal()
. .
OBS: Se puede ver como el PC1 explica aproximadamente el 37% de la
varianza y el PC2 un 20%. Sumando entre ambas un 57%.
# Calcular la matriz de covarianza de los datos escalados
cov.mat <- cov(datos_escalados)
# Calcular los autovalores y autovectores de la matriz de covarianza
auto.val <- eigen(cov.mat)
# Transformar los datos originales en el nuevo espacio (PCA)
datos_pca <- as.matrix(datos_escalados) %*% auto.val$vectors # Nuevas coordenadas en el espacio PCA
# Crear un data frame con las primeras dos componentes principales
df_pca <- data.frame(PC1 = datos_pca[, 1], PC2 = datos_pca[, 2])
# Graficar las primeras dos componentes principales
library(ggplot2)
ggplot(df_pca, aes(x = PC1, y = PC2)) +
geom_point(color = "blue", alpha = 0.7) +
labs(
title = "Gráfico de las Primeras Dos Componentes Principales",
x = "Componente Principal 1 (PC1)",
y = "Componente Principal 2 (PC2)"
) +
theme_minimal()
##
10. Cargas de las Componentes principales
# Los autovectores contienen las cargas de cada variable en las componentes principales
# Vamos a extraer las cargas del primer y segundo componente principal para las primeras variables
cargas <- auto.val$vectors # Las cargas de cada variable para cada componente
# Para ver qué variables más aportan a PC1 y PC2, podemos examinar las cargas de las primeras dos columnas:
cargas_primer_componente <- cargas[, 1] # Cargas para el primer componente principal
cargas_segundo_componente <- cargas[, 2] # Cargas para el segundo componente principal
# Mostrar las variables que más aportan a los primeros dos componentes
cargas_primer_componente
## [1] 0.03151499 -0.54778656 -0.57802670 0.12120759 -0.53777618 -0.24568015
## [7] -0.02384518
cargas_segundo_componente
## [1] 0.536112476 -0.081903212 -0.011274135 0.602295584 0.006447934
## [6] 0.572780273 -0.121940078
. . OBS: Aqui podemos ver que en PC1, las variables que tienen las cargas más altas en valor absoluto (en este caso, las más altas son -0.57802670 y -0.54778656) son las variables 3 y 2 respectivamente. Es decir, la variable 3 explica en un 58% la PC1 y la variable 2 un 55%. En PC2, las variables que tienen las cargas más altas en valor absoluto son 0.602295584 y 0.572780273, que corresponden a las variables 4 y 6. Es decir, la variable 4 explica un 60% de la PC2 y la variable 6 un 57%.
# Realizar PCA con los datos escalados
PCA <- prcomp(datos_escalados)
# Graficar el biplot con scale=0
biplot(PCA, scale = 0)
Agrupamientos K-Means y Jerárquicos:
Se utilizó el método del codo para determinar que el número óptimo de clusters es k=3.
Los resultados de K-Means se visualizan claramente en el espacio reducido de las dos primeras componentes principales, lo que refleja una buena separación de los grupos. Los métodos jerárquicos Bottom-Up y Top-Down muestran diferencias significativas. Aunque el dendrograma Bottom-Up generó agrupamientos más pequeños, el análisis visual del dendrograma Top-Down sugiere que este último es más consistente al identificar grupos estructurados, idealmente entre 3 y 5 clusters.
Análisis de Componentes Principales (PCA):
El PCA mostró que las dos primeras componentes principales explican conjuntamente el 57% de la varianza, con el PC1 y PC2 aportando el 37% y 20%, respectivamente. Las variables que más contribuyen al PC1 son las variables 3 y 2, mientras que en el PC2 destacan las variables 4 y 6. Estas contribuciones reflejan la importancia relativa de estas variables en la variabilidad general de los datos. Proyecciones de las Variables:
El biplot permitió analizar cómo las variables originales se proyectan sobre las componentes principales. Las variables con cargas altas en valor absoluto en las primeras componentes son aquellas que más influyen en la formación de los clusters.
En este trabajo práctico se aplicaron diversas técnicas de análisis exploratorio y de clasificación sobre un conjunto de datos de consumo de clientes, combinando dos bases de datos iniciales mediante normalización para garantizar la coherencia en la escala de las variables.