El gráfico generado con md.pattern() del paquete mice en R muestra el patrón de datos faltantes en el dataset vivienda_num. Se observa que la mayoría de las variables tienen datos completos, representados en azul, mientras que algunas presentan valores faltantes, indicados en rosa. Existen distintos patrones de ausencia de datos, con un grupo significativo de observaciones que carecen de información en variables específicas. La última columna a la derecha indica la cantidad de registros que siguen cada patrón de completitud o ausencia de datos. Este análisis es clave para decidir estrategias de manejo de datos faltantes, como imputación o eliminación de registros con información incompleta.
# veridicamos datos faltes
library(mice)
md.pattern(vivienda_num)
## preciom id estrato areaconst banios habitaciones longitud latitud
## 6717 1 1 1 1 1 1 1 1
## 1602 1 1 1 1 1 1 1 1
## 1 1 0 0 0 0 0 0 0
## 2 0 0 0 0 0 0 0 0
## 2 3 3 3 3 3 3 3
## parqueaderos
## 6717 1 0
## 1602 0 1
## 1 0 8
## 2 0 9
## 1605 1628
Para el tratamiento de estos datos faltantes, se eliminan los registros con pocos datos en las variables y los parqueaderos vacios se pasan a cero
#Según el resultado, hay 1 registro que solo tiene una variable, 2 que no tienen ninguna, 1602 que no tienen información del parqueadero.
# se eliminarán las filas con pocas variables, se imputará el núero de parqueaderos a "0"
# Ver cuántos valores faltantes tiene cada fila
num_na_por_fila <- rowSums(is.na(vivienda_num))
# Filtrar el dataset: conservar solo las filas con al menos 2 valores no NA
vivienda_num_limpio <- vivienda_num[num_na_por_fila < (ncol(vivienda_num) - 1), ]
#pasamos los parqueaderos vacios a cero
vivienda_num_limpio$parqueaderos[is.na(vivienda_num_limpio$parqueaderos)] <- 0
# se verifica
md.pattern(vivienda_num_limpio)
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## id estrato preciom areaconst parqueaderos banios habitaciones longitud
## 8319 1 1 1 1 1 1 1 1
## 0 0 0 0 0 0 0 0
## latitud
## 8319 1 0
## 0 0
El gráfico generado tras reemplazar los valores faltantes en la variable “parqueaderos” por 0 muestra que el dataset vivienda_num_limpio ya no contiene datos faltantes. La función md.pattern() del paquete mice confirma que todas las variables tienen valores completos, lo que se evidencia en el mensaje “No need for mice. This data set is completely observed”. Además, el gráfico indica que en las 8319 observaciones, todas las columnas están completamente llenas (representadas en azul), sin ninguna celda en rosa. Esto significa que ya no es necesario aplicar técnicas de imputación para manejar valores faltantes.
Realizamos el escalado de las variables numericas
#eliminasmos las columnas id, longitud y latitud ya que su estandarización no nos dan información relevante sobre el dataset
viviendaZ= scale(vivienda_num_limpio[,2:7])
head(viviendaZ) # primeros 6 registros
## estrato preciom areaconst parqueaderos banios habitaciones
## [1,] -1.5872276 -0.5595498 -0.7339949 -0.3875522 -0.07793773 1.6406840
## [2,] -1.5872276 -0.3465670 -0.3842568 -0.3875522 -0.77811479 -0.4147626
## [3,] -1.5872276 -0.2552886 0.3152194 0.4168506 -0.77811479 0.2703863
## [4,] -0.6156201 -0.1031580 0.7349051 1.2212534 1.32241640 -0.4147626
## [5,] 0.3559875 -0.5291236 -0.5940997 -0.3875522 -0.77811479 -0.4147626
## [6,] 0.3559875 -0.5899759 -0.6150839 -0.3875522 -0.07793773 -0.4147626
se aplica el analisis de componentes princiales
#se aplica el Análisis de componentes principales
prcomp(viviendaZ)
## Standard deviations (1, .., p=6):
## [1] 1.8480703 1.1222455 0.6779600 0.6592367 0.4909833 0.4357909
##
## Rotation (n x k) = (6 x 6):
## PC1 PC2 PC3 PC4 PC5 PC6
## estrato 0.3306904 -0.5816950 0.5551021 0.07749341 0.46143880 -0.1587620
## preciom 0.4781754 -0.1883533 -0.0359721 -0.36062553 -0.21967777 0.7458339
## areaconst 0.4417250 0.2388377 -0.2878930 -0.61783592 0.27859384 -0.4534506
## parqueaderos 0.4096354 -0.2607395 -0.6565763 0.57091588 0.04760414 -0.0700729
## banios 0.4668745 0.1921461 0.3633148 0.18500105 -0.67876421 -0.3437503
## habitaciones 0.2847775 0.6813261 0.2111757 0.34936005 0.44521273 0.2997240
#elección del número de componentes principales
library(factoextra)
res.pca <- prcomp(viviendaZ)
fviz_eig(res.pca, addlabels = TRUE)
El Scree Plot presentado muestra el porcentaje de varianza explicada por cada componente principal en un Análisis de Componentes Principales (PCA) aplicado al conjunto de datos de viviendas. En el gráfico, se observa que el primer componente principal (PC1) explica el 56.9% de la variabilidad, mientras que el segundo componente (PC2) explica un 21% adicional, sumando un 78% de varianza explicada con solo dos dimensiones. A partir del tercer componente, la contribución a la varianza es significativamente menor (7.7% en PC3 y 7.2% en PC4), lo que sugiere que estos componentes aportan información marginal. El punto de codo en el gráfico indica que dos componentes son suficientes para capturar la mayor parte de la estructura de los datos, lo que permite reducir la dimensionalidad sin perder demasiada información.
se genral el graífco de coordenadas
#según el gráfico de el PC1 y PC2 explican el 77.9% de la variabilidad total, por lo que se elegirán estos componentes para reducir la dimencionalidad a solo 2 componentes
fviz_pca_var(res.pca,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#FF7F00", "#034D94"),
repel = TRUE # Avoid text overlapping
)
El gráfico de variables del Análisis de Componentes Principales (PCA) muestra la relación entre las variables originales y los dos primeros componentes principales, que explican el 77.9% de la variabilidad total de los datos. Se observa que el primer componente principal (PC1), que representa el 56.9% de la varianza, está fuertemente influenciado por el precio del metro cuadrado (preciom), el estrato socioeconómico (estrato), el número de parqueaderos (parqueaderos) y el área construida (areaconst), lo que sugiere que este componente refleja principalmente el tamaño y nivel socioeconómico de las viviendas. Por otro lado, el segundo componente principal (PC2), que explica el 21% de la varianza, está dominado por la variable habitaciones, indicando que este factor también es diferenciador en la clasificación de las viviendas. Además, se observa una fuerte correlación entre precio, área construida y número de baños, lo que indica que las viviendas más grandes y con más baños tienden a ser más costosas. Dado que estos dos componentes capturan la mayor parte de la información del conjunto de datos, se justifica la reducción de la dimensionalidad a solo dos dimensiones para facilitar el análisis y la visualización sin perder información relevante.
se buscan los valores mas altos y bajos en PC1 y PC2
pca_coords <- res.pca$x # Obtener coordenadas de los individuos en los PCs
# Identificar los valores más altos y más bajos en PC1 y PC2
vivienda_max_PC1 <- which.max(pca_coords[, 1]) # Mayor en PC1
vivienda_min_PC1 <- which.min(pca_coords[, 1]) # Menor en PC1
vivienda_max_PC2 <- which.max(pca_coords[, 2]) # Mayor en PC2
vivienda_min_PC2 <- which.min(pca_coords[, 2]) # Menor en PC2
# Obtener los índices de los clientes extremos
vivienda_extremos <- c(vivienda_max_PC1, vivienda_min_PC1, vivienda_max_PC2, vivienda_min_PC2)
vivienda_extremos
## [1] 1762 4480 8073 2926
#Para explicar el sentido de los ejes, se escogen 4 casos extremos
datos<- rbind(vivienda_num_limpio[1762,],
vivienda_num_limpio[4480,],
vivienda_num_limpio[8073,],
vivienda_num_limpio[2926,])
datos <- as.data.frame(datos)
rownames(datos) = c("vivienda 1762","vivienda 4480","vivienda 8073","vivienda 2926")
datos
## id estrato preciom areaconst parqueaderos banios habitaciones
## vivienda 1762 5684 6 1800 1586 10 4 5
## vivienda 4480 7522 3 148 87 0 0 0
## vivienda 8073 534 3 370 1440 1 4 10
## vivienda 2926 5908 5 950 280 10 0 0
## longitud latitud
## vivienda 1762 -76.53798 3.35961
## vivienda 4480 -76.55000 3.37500
## vivienda 8073 -76.49815 3.46343
## vivienda 2926 -76.53932 3.39698
casos1 <- rbind(res.pca$x[1762,1:2],res.pca$x[4480,1:2]) # CP1
rownames(casos1) = c("1762","4480")
casos1 <- as.data.frame(casos1)
casos2 <- rbind(res.pca$x[8073,1:2], res.pca$x[2926,1:2]) # CP2
rownames(casos2) = c("8073","2926")
casos2 <- as.data.frame(casos2)
se ubican los extremos de los componentes en el gráfico de componentes principales
fviz_pca_ind(res.pca, col.ind = "#DEDEDE", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
geom_point(data = casos1, aes(x = PC1, y = PC2), color = "red", size = 3) +
geom_point(data = casos2, aes(x = PC1, y = PC2), color = "blue", size = 3)
vivienda_num_limpio[c(1762, 4480, 8073, 2926), ]
## # A tibble: 4 × 9
## id estrato preciom areaconst parqueaderos banios habitaciones longitud
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 5684 6 1800 1586 10 4 5 -76.5
## 2 7522 3 148 87 0 0 0 -76.6
## 3 534 3 370 1440 1 4 10 -76.5
## 4 5908 5 950 280 10 0 0 -76.5
## # ℹ 1 more variable: latitud <dbl>
#PC1 representa precio, área, parqueaderos y baños, mientras que PC2 represneta estrato y habitaciones.
res.pca
## Standard deviations (1, .., p=6):
## [1] 1.8480703 1.1222455 0.6779600 0.6592367 0.4909833 0.4357909
##
## Rotation (n x k) = (6 x 6):
## PC1 PC2 PC3 PC4 PC5 PC6
## estrato 0.3306904 -0.5816950 0.5551021 0.07749341 0.46143880 -0.1587620
## preciom 0.4781754 -0.1883533 -0.0359721 -0.36062553 -0.21967777 0.7458339
## areaconst 0.4417250 0.2388377 -0.2878930 -0.61783592 0.27859384 -0.4534506
## parqueaderos 0.4096354 -0.2607395 -0.6565763 0.57091588 0.04760414 -0.0700729
## banios 0.4668745 0.1921461 0.3633148 0.18500105 -0.67876421 -0.3437503
## habitaciones 0.2847775 0.6813261 0.2111757 0.34936005 0.44521273 0.2997240
El gráfico muestra la distribución de las viviendas en el espacio definido por los dos primeros componentes principales (PCA), que explican el 77.9% de la variabilidad total de los datos. Cada punto representa una vivienda proyectada en este nuevo espacio, donde la mayoría se agrupa en una región central, indicando que comparten características similares. Sin embargo, se destacan algunos casos extremos en rojo y azul, que corresponden a viviendas con características significativamente diferentes del resto. La Dimensión 1 (56.9%) parece estar relacionada con factores como el precio, el área construida y el estrato, mientras que la Dimensión 2 (21%) parece diferenciar las viviendas en función del número de habitaciones y otras características secundarias. La vivienda ubicada en el extremo derecho (1762) sugiere una propiedad con un alto impacto en las variables asociadas a Dim 1, mientras que las viviendas en los extremos superior (8073) e inferior (2926) en Dim 2 podrían diferenciarse por su distribución en términos de número de habitaciones o estructura interna.
Para este análisis se vueve a generar la limpieza y escalamietno de la base de datos, ahora incluyendo variables categóricas
library(paqueteMODELOS)
data("vivienda")
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<externalptr>
vivienda$longitud <- as.character(vivienda$longitud)
vivienda$latitud <- as.character(vivienda$latitud)
vivienda$id <- as.character(vivienda$id)
# Seleccionar solo las columnas numéricas
vivienda_num <- vivienda[sapply(vivienda, is.numeric)]
# Escalar solo las variables numéricas
vivienda_num_scaled <- as.data.frame(scale(vivienda_num))
# Unir las variables categóricas con las numéricas escaladas
vivienda_scaled <- cbind(vivienda_num_scaled, vivienda[sapply(vivienda, is.character)])
vivienda_scaled$longitud <- as.numeric(vivienda_scaled$longitud)
vivienda_scaled$latitud <- as.numeric(vivienda_scaled$latitud)
str(vivienda_scaled)
## 'data.frame': 8322 obs. of 13 variables:
## $ estrato : num -1.587 -1.587 -1.587 -0.616 0.356 ...
## $ preciom : num -0.56 -0.347 -0.255 -0.103 -0.529 ...
## $ areaconst : num -0.734 -0.384 0.315 0.735 -0.594 ...
## $ parqueaderos: num -0.742 -0.742 0.147 1.035 -0.742 ...
## $ banios : num -0.0779 -0.7781 -0.7781 1.3224 -0.7781 ...
## $ habitaciones: num 1.641 -0.415 0.27 -0.415 -0.415 ...
## $ id : chr "1147" "1169" "1350" "5992" ...
## $ zona : chr "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr NA NA NA "02" ...
## $ tipo : chr "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num 3.43 3.43 3.44 3.44 3.46 ...
# verificamos datos faltes
library(mice)
md.pattern(vivienda_scaled)
## preciom estrato areaconst banios habitaciones id zona tipo barrio longitud
## 4808 1 1 1 1 1 1 1 1 1 1
## 1909 1 1 1 1 1 1 1 1 1 1
## 876 1 1 1 1 1 1 1 1 1 1
## 726 1 1 1 1 1 1 1 1 1 1
## 1 1 0 0 0 0 0 0 0 0 0
## 2 0 0 0 0 0 0 0 0 0 0
## 2 3 3 3 3 3 3 3 3 3
## latitud parqueaderos piso
## 4808 1 1 1 0
## 1909 1 1 0 1
## 876 1 0 1 1
## 726 1 0 0 2
## 1 0 0 0 12
## 2 0 0 0 13
## 3 1605 2638 4275
#Según el resultado, hay 1 registro que solo tiene una variable, 2 que no tienen ninguna, 1602 que no tienen información del parqueadero.
# se eliminarán las filas con pocas variables, se imputará el núero de parqueaderos a "0"
# Ver cuántos valores faltantes tiene cada fila
num_na_por_fila <- rowSums(is.na(vivienda_scaled))
# Filtrar el dataset: conservar solo las filas con al menos 2 valores no NA
vivienda_scaled_limpio <- vivienda_scaled[num_na_por_fila < (ncol(vivienda_scaled) - 1), ]
#pasamos los parqueaderos vacios a cero
vivienda_scaled_limpio$parqueaderos[is.na(vivienda_scaled_limpio$parqueaderos)] <- 0
vivienda_scaled_limpio$piso[is.na(vivienda_scaled_limpio$piso)] <- 1
# se verifica
md.pattern(vivienda_scaled_limpio)
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## estrato preciom areaconst parqueaderos banios habitaciones id zona piso
## 8319 1 1 1 1 1 1 1 1 1
## 0 0 0 0 0 0 0 0 0
## tipo barrio longitud latitud
## 8319 1 1 1 1 0
## 0 0 0 0 0
head(vivienda_scaled_limpio) # primeros 6 registros
## estrato preciom areaconst parqueaderos banios habitaciones id
## 1 -1.5872276 -0.5595420 -0.7339949 -0.7424551 -0.07793773 1.6406840 1147
## 2 -1.5872276 -0.3465477 -0.3842568 -0.7424551 -0.77811479 -0.4147626 1169
## 3 -1.5872276 -0.2552644 0.3152194 0.1465058 -0.77811479 0.2703863 1350
## 4 -0.6156201 -0.1031256 0.7349051 1.0354668 1.32241640 -0.4147626 5992
## 5 0.3559875 -0.5291143 -0.5940997 -0.7424551 -0.77811479 -0.4147626 1212
## 6 0.3559875 -0.5899698 -0.6150839 -0.7424551 -0.07793773 -0.4147626 1724
## zona piso tipo barrio longitud latitud
## 1 Zona Oriente 1 Casa 20 de julio -76.51168 3.43382
## 2 Zona Oriente 1 Casa 20 de julio -76.51237 3.43369
## 3 Zona Oriente 1 Casa 20 de julio -76.51537 3.43566
## 4 Zona Sur 02 Casa 3 de julio -76.54000 3.43500
## 5 Zona Norte 01 Apartamento acopi -76.51350 3.45891
## 6 Zona Norte 01 Apartamento acopi -76.51700 3.36971
#distribución de individuos por distancias
library(tidyverse)
# distancia euclidiana
dist_viv <- dist(vivienda_scaled_limpio, method = 'euclidean')
# Clúster jerárquico con el método complete
hc_viv <- hclust(dist_viv, method = 'complete')
# Determinamos a dónde pertenece cada observación
cluster_assigments <- cutree(hc_viv, k = 4)
assigned_cluster<-cluster_assigments
# asignamos los clusters
assigned_cluster <- vivienda_scaled_limpio %>% mutate(cluster = as.factor(cluster_assigments))
media_estrato <- mean(vivienda$estrato, na.rm = TRUE)
sd_estrato <- sd(vivienda$estrato, na.rm = TRUE)
assigned_cluster$estrato_original <- (assigned_cluster$estrato * sd_estrato) + media_estrato
# gráfico de puntos
ggplot(assigned_cluster, aes(x = zona, y = preciom, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()
# gráfico de puntos
ggplot(assigned_cluster, aes(x = estrato_original, y = preciom, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()
# gráfico de puntos
ggplot(assigned_cluster, aes(x = estrato_original, y = zona, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()
plot(hc_viv, cex = 0.6, main = "Dendograma de viviendas", las=1,
ylab = "Distancia euclidiana", xlab = "Grupos")
rect.hclust(hc_viv, k = 4, border = 2:5)
#medias de clusteres para entender mejor la relación de colores
assigned_cluster %>%
group_by(cluster) %>%
summarise(
promedio_precio = mean(preciom, na.rm = TRUE),
promedio_areaconst = mean(areaconst, na.rm = TRUE),
promedio_parqueaderos = mean(parqueaderos, na.rm = TRUE),
promedio_banios = mean(banios, na.rm = TRUE),
promedio_habitaciones = mean(habitaciones, na.rm = TRUE)
)
## # A tibble: 4 × 6
## cluster promedio_precio promedio_areaconst promedio_parqueaderos
## <fct> <dbl> <dbl> <dbl>
## 1 1 -0.478 -0.295 -0.261
## 2 2 0.461 0.346 0.340
## 3 3 0.0554 0.0861 0.0264
## 4 4 0.379 0.0920 0.123
## # ℹ 2 more variables: promedio_banios <dbl>, promedio_habitaciones <dbl>
#dendograma
plot(hc_viv, cex = 0.6, main = "Dendograma de viviendas", las=1,
ylab = "Distancia euclidiana", xlab = "Grupos")
rect.hclust(hc_viv, k = 4, border = 2:5)
Gracias a los valores médios de precio, area construida, parqueaderos, nuemro de baños y número de habitaciones de cada uno de los clusteres generados, es posible observar que el cluster 1 es que el que esta albergando las viviendas de menos precio, menor área construida, menos parqueaderos y menos cantidad de baños; el cluster 2 representa a las más costosas y con maypr área; el cluster numero 3 representa a las que estan muy cerca de la media en las distribuciones de cada variable, y por último, el cluster 4 representa viviendas con alto precio pero poca área construida, pocos baños, parqueaderos y habitaciones.
De esta manera, podemos acercarnos a análisis como: * en la zona sur de la ciudad estan las viviendas más costosas y más grandes (cluster 2). * en la zona oriente encontramos las mas pequeñas y económicas. * en la zona oeste estan las viviendas con características especiales que tienen un alto valor comercial pero baja cantidad de área, habitaciones, baños y parqueaderos. * en la zona norte se encuentran la mayoría de viviendas con características promedio y algúnas de las más económicas. * en la zona centro se encuentran viviendas de los clusteres 1, 2 y 3 pero con costos más bajos.
Adicionalmente, segúin la gráfica que nos relaciona los clusteres con los estratos y el precio, se obtiene la siguiente información:
library(paqueteMODELOS)
data("vivienda")
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=
## .. cols(
## .. id = col_double(),
## .. zona = col_character(),
## .. piso = col_character(),
## .. estrato = col_double(),
## .. preciom = col_double(),
## .. areaconst = col_double(),
## .. parqueaderos = col_double(),
## .. banios = col_double(),
## .. habitaciones = col_double(),
## .. tipo = col_character(),
## .. barrio = col_character(),
## .. longitud = col_double(),
## .. latitud = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
vivienda$longitud <- as.character(vivienda$longitud)
vivienda$latitud <- as.character(vivienda$latitud)
vivienda$id <- as.character(vivienda$id)
# Seleccionar solo las columnas numéricas
vivienda_num <- vivienda[sapply(vivienda, is.numeric)]
# Escalar solo las variables numéricas
vivienda_num_scaled <- as.data.frame(scale(vivienda_num))
# Unir las variables categóricas con las numéricas escaladas
vivienda_scaled <- cbind(vivienda_num_scaled, vivienda[sapply(vivienda, is.character)])
vivienda_scaled$longitud <- as.numeric(vivienda_scaled$longitud)
vivienda_scaled$latitud <- as.numeric(vivienda_scaled$latitud)
str(vivienda_scaled)
## 'data.frame': 8322 obs. of 13 variables:
## $ estrato : num -1.587 -1.587 -1.587 -0.616 0.356 ...
## $ preciom : num -0.56 -0.347 -0.255 -0.103 -0.529 ...
## $ areaconst : num -0.734 -0.384 0.315 0.735 -0.594 ...
## $ parqueaderos: num -0.742 -0.742 0.147 1.035 -0.742 ...
## $ banios : num -0.0779 -0.7781 -0.7781 1.3224 -0.7781 ...
## $ habitaciones: num 1.641 -0.415 0.27 -0.415 -0.415 ...
## $ id : chr "1147" "1169" "1350" "5992" ...
## $ zona : chr "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr NA NA NA "02" ...
## $ tipo : chr "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num 3.43 3.43 3.44 3.44 3.46 ...
# verificamos datos faltes
library(mice)
md.pattern(vivienda_scaled)
## preciom estrato areaconst banios habitaciones id zona tipo barrio longitud
## 4808 1 1 1 1 1 1 1 1 1 1
## 1909 1 1 1 1 1 1 1 1 1 1
## 876 1 1 1 1 1 1 1 1 1 1
## 726 1 1 1 1 1 1 1 1 1 1
## 1 1 0 0 0 0 0 0 0 0 0
## 2 0 0 0 0 0 0 0 0 0 0
## 2 3 3 3 3 3 3 3 3 3
## latitud parqueaderos piso
## 4808 1 1 1 0
## 1909 1 1 0 1
## 876 1 0 1 1
## 726 1 0 0 2
## 1 0 0 0 12
## 2 0 0 0 13
## 3 1605 2638 4275
#Según el resultado, hay 1 registro que solo tiene una variable, 2 que no tienen ninguna, 1602 que no tienen información del parqueadero.
# se eliminarán las filas con pocas variables, se imputará el núero de parqueaderos a "0"
# Ver cuántos valores faltantes tiene cada fila
num_na_por_fila <- rowSums(is.na(vivienda_scaled))
# Filtrar el dataset: conservar solo las filas con al menos 2 valores no NA
vivienda_scaled_limpio <- vivienda_scaled[num_na_por_fila < (ncol(vivienda_scaled) - 1), ]
#pasamos los parqueaderos vacios a cero
vivienda_scaled_limpio$parqueaderos[is.na(vivienda_scaled_limpio$parqueaderos)] <- 0
vivienda_scaled_limpio$piso[is.na(vivienda_scaled_limpio$piso)] <- 1
media_estrato <- mean(vivienda$estrato, na.rm = TRUE)
sd_estrato <- sd(vivienda$estrato, na.rm = TRUE)
vivienda_scaled_limpio$estrato_original <- (vivienda_scaled_limpio$estrato * sd_estrato) + media_estrato
# se verifica
md.pattern(vivienda_scaled_limpio)
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## estrato preciom areaconst parqueaderos banios habitaciones id zona piso
## 8319 1 1 1 1 1 1 1 1 1
## 0 0 0 0 0 0 0 0 0
## tipo barrio longitud latitud estrato_original
## 8319 1 1 1 1 1 0
## 0 0 0 0 0 0
head(vivienda_scaled_limpio) # primeros 6 registros
## estrato preciom areaconst parqueaderos banios habitaciones id
## 1 -1.5872276 -0.5595420 -0.7339949 -0.7424551 -0.07793773 1.6406840 1147
## 2 -1.5872276 -0.3465477 -0.3842568 -0.7424551 -0.77811479 -0.4147626 1169
## 3 -1.5872276 -0.2552644 0.3152194 0.1465058 -0.77811479 0.2703863 1350
## 4 -0.6156201 -0.1031256 0.7349051 1.0354668 1.32241640 -0.4147626 5992
## 5 0.3559875 -0.5291143 -0.5940997 -0.7424551 -0.77811479 -0.4147626 1212
## 6 0.3559875 -0.5899698 -0.6150839 -0.7424551 -0.07793773 -0.4147626 1724
## zona piso tipo barrio longitud latitud estrato_original
## 1 Zona Oriente 1 Casa 20 de julio -76.51168 3.43382 3
## 2 Zona Oriente 1 Casa 20 de julio -76.51237 3.43369 3
## 3 Zona Oriente 1 Casa 20 de julio -76.51537 3.43566 3
## 4 Zona Sur 02 Casa 3 de julio -76.54000 3.43500 4
## 5 Zona Norte 01 Apartamento acopi -76.51350 3.45891 5
## 6 Zona Norte 01 Apartamento acopi -76.51700 3.36971 5
library(FactoMineR)
tabla_zona_estrato<-table(vivienda_scaled_limpio$zona, vivienda_scaled_limpio$estrato_original)
tabla_zona_estrato
##
## 3 4 5 6
## Zona Centro 105 14 4 1
## Zona Norte 572 407 769 172
## Zona Oeste 54 84 290 770
## Zona Oriente 340 8 2 1
## Zona Sur 382 1616 1685 1043
chisq.test(tabla_zona_estrato)
##
## Pearson's Chi-squared test
##
## data: tabla_zona_estrato
## X-squared = 3830.4, df = 12, p-value < 2.2e-16
library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_ac <- CA(tabla_zona_estrato)
El análisis de correspondecia resalata lo que se concluyó en los
análisis de clusteres: