ANÁLISIS PRELIMINAR DEL DATASET

#se carga el paquete y se visualiza preliminarmente
library(paqueteDAT)
data("vivienda")
head(vivienda,5)
##     id         zona piso estrato preciom areaconst parqueaderos banios
## 1 1147 Zona Oriente <NA>       3     250        70            1      3
## 2 1169 Zona Oriente <NA>       3     320       120            1      2
## 3 1350 Zona Oriente <NA>       3     350       220            2      2
## 4 5992     Zona Sur   02       4     400       280            3      5
## 5 1212   Zona Norte   01       5     260        90            1      2
##   habitaciones        tipo      barrio  longitud latitud
## 1            6        Casa 20 de julio -76.51168 3.43382
## 2            3        Casa 20 de julio -76.51237 3.43369
## 3            4        Casa 20 de julio -76.51537 3.43566
## 4            3        Casa  3 de julio -76.54000 3.43500
## 5            3 Apartamento       acopi -76.51350 3.45891
#ahora, se analiza que tipo de datos contienen cada una de las columnas del
#dataset vivienda
class(vivienda$zona)
## [1] "character"
class(vivienda$piso)
## [1] "character"
class(vivienda$estrato)
## [1] "numeric"
class(vivienda$preciom)
## [1] "numeric"
class(vivienda$areaconst)
## [1] "numeric"
class(vivienda$parqueaderos)
## [1] "numeric"
class(vivienda$banios)
## [1] "numeric"
class(vivienda$habitaciones)
## [1] "numeric"
class(vivienda$tipo)
## [1] "character"
class(vivienda$barrio)
## [1] "character"
class(vivienda$longitud)
## [1] "numeric"
class(vivienda$latitud)
## [1] "numeric"
#se observan, que hay 4 variables de tipo texto, y el resto de variables son numéricas
#así mismo, se miran datos faltantes
sum(is.na(vivienda$zona))
## [1] 3
sum(is.na(vivienda$piso))
## [1] 2638
sum(is.na(vivienda$estrato))
## [1] 3
sum(is.na(vivienda$preciom))
## [1] 2
sum(is.na(vivienda$areaconst))
## [1] 3
sum(is.na(vivienda$parqueaderos))
## [1] 1605
sum(is.na(vivienda$banios))
## [1] 3
sum(is.na(vivienda$habitaciones))
## [1] 3
sum(is.na(vivienda$tipo))
## [1] 3
sum(is.na(vivienda$barrio))
## [1] 3
sum(is.na(vivienda$longitud))
## [1] 3
sum(is.na(vivienda$latitud))
## [1] 3
#en este punto se observa que hay muy pocos datos faltantes, excepto en las variables
#piso y parqueaderos, por ende, se deciden eliminar estas dos variables en el análisis.
#tienen 2638 y 1605 datos faltantes, mientras que las otras variables solo 3 datos faltantes
borrar <- c("piso","parqueaderos","barrio")
vivienda <- vivienda[ ,!(names(vivienda) %in% borrar)]
head(vivienda,5)
##     id         zona estrato preciom areaconst banios habitaciones        tipo
## 1 1147 Zona Oriente       3     250        70      3            6        Casa
## 2 1169 Zona Oriente       3     320       120      2            3        Casa
## 3 1350 Zona Oriente       3     350       220      2            4        Casa
## 4 5992     Zona Sur       4     400       280      5            3        Casa
## 5 1212   Zona Norte       5     260        90      2            3 Apartamento
##    longitud latitud
## 1 -76.51168 3.43382
## 2 -76.51237 3.43369
## 3 -76.51537 3.43566
## 4 -76.54000 3.43500
## 5 -76.51350 3.45891
#se recodifican algunas columnas que son categoricas
#se observa que hay dos variables que son categóricas, como lo son "zona" y "tipo", ya que zona los
#clasifica segun zona centro, norte, oeste y oriente, y en tipo se clasifica como casa y apartamento.
#con la recodificación estas categorias quedan numéricas.
library(dplyr) 
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
vivienda <- vivienda %>% mutate(zona = replace(zona, 
                                               zona == "Zona Centro", 1))
vivienda <- vivienda %>% mutate(zona = replace(zona, 
                                               zona == "Zona Norte", 2))
vivienda <- vivienda %>% mutate(zona = replace(zona, 
                                               zona == "Zona Oeste", 3))
vivienda <- vivienda %>% mutate(zona = replace(zona, 
                                               zona == "Zona Oriente",
                                               4))
vivienda <- vivienda %>% mutate(zona = replace(zona, 
                                               zona == "Zona Sur", 5))
vivienda$zona <- as.numeric(vivienda$zona)

# Tipo                         
vivienda <- vivienda %>% mutate(tipo = replace(tipo, 
                                               tipo == "Casa", 1))
vivienda <- vivienda %>% mutate(tipo = replace(tipo, 
                                               tipo == "Apartamento", 2))
vivienda$tipo <- as.numeric(vivienda$tipo)

head(vivienda,5)
## # A tibble: 5 × 10
##      id  zona estrato preciom areaconst banios habitacio…¹  tipo longi…² latitud
##   <dbl> <dbl>   <dbl>   <dbl>     <dbl>  <dbl>       <dbl> <dbl>   <dbl>   <dbl>
## 1  1147     4       3     250        70      3           6     1   -76.5    3.43
## 2  1169     4       3     320       120      2           3     1   -76.5    3.43
## 3  1350     4       3     350       220      2           4     1   -76.5    3.44
## 4  5992     5       4     400       280      5           3     1   -76.5    3.44
## 5  1212     2       5     260        90      2           3     2   -76.5    3.46
## # … with abbreviated variable names ¹​habitaciones, ²​longitud
#ahora, generamos una matriz de correlación, que nos permite analizar la incidencia entre sí de los datos
options(repos = c(CRAN = "https://cloud.r-project.org"))
install.packages("psych")
## Installing package into 'C:/Users/CARLOS/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## package 'psych' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\CARLOS\AppData\Local\Temp\RtmpKY5A03\downloaded_packages
install.packages("corrplot")
## Installing package into 'C:/Users/CARLOS/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## package 'corrplot' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\CARLOS\AppData\Local\Temp\RtmpKY5A03\downloaded_packages
library(psych)
## Warning: package 'psych' was built under R version 4.2.3
library(corrplot)
## Warning: package 'corrplot' was built under R version 4.2.3
## corrplot 0.92 loaded
correlacion <- cor(vivienda, use = "complete.obs")
corrplot(correlacion, method = "number")

Correlación positiva (0.6): A medida que el estrato de la vivienda aumenta, también lo hace su precio. (mayor estrato, mayor precio).

Correlación positiva (0.7): Existe una relación positiva entre el precio de la vivienda y el área construida. Las viviendas con un área mayor tienden a tener un precio mayor.

Correlación positiva (0.7): Las viviendas con un mayor número de baños tienden a tener un precio más alto.

Correlación positiva (0.6): Se observa una correlación positiva entre la cantidad de baños y el área construida. Las viviendas más grandes tienden a tener más baños.

Correlación positiva (0.5): Existe una relación positiva entre la cantidad de habitaciones y el área construida. Las viviendas más grandes suelen tener más habitaciones.

Correlación negativa (-0.5): Después de la recodificación, se nota que las casas (identificadas con 1) tienden a tener un área mucho mayor que los apartamentos (identificados con 2).

Correlación positiva (0.6): Existe una relación positiva entre el número de habitaciones y la cantidad de baños en una vivienda. Cuantas más habitaciones, suele haber más baños.

Correlación negativa (-0.5): Con la recodificación, se observa que las casas (identificadas con 1) tienden a tener más habitaciones en comparación con los apartamentos (identificados con 2).

ANÁLISIS DE COMPONENTES PRINCIPALES

#se empieza con el cálculo de la varianza de las variables cuantitativas
vivienda_2 <- vivienda[1:8319,3:7]
apply(X = vivienda_2, MARGIN = 2, FUN = var)
##      estrato      preciom    areaconst       banios habitaciones 
## 1.059298e+00 1.080207e+05 2.043874e+04 2.039784e+00 2.130248e+00
#se observa que la varianza es cercana a 0, y por ende, los datos no se encuentran tan dispersos
#se buscan ahora las 2 primeras componentes y se muestran
pca <- prcomp(vivienda_2, scale = TRUE)
library(factoextra)
## Warning: package 'factoextra' was built under R version 4.2.3
## Loading required package: ggplot2
## 
## Attaching package: 'ggplot2'
## The following objects are masked from 'package:psych':
## 
##     %+%, alpha
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
fviz_pca_ind(pca, geom.ind = "point", 
             col.ind = "#CD0BBC", 
             axes = c(1, 2), 
             pointsize = 1.5)

# No se aprecian agrupaciones notables que indiquen la existencia de conjuntos
# de registros con características semejantes en el gráfico inicial.
# Ahora, repetiremos el proceso gráfico, pero utilizando "zona" como la variable
# para etiquetar las viviendas.
colores <- function(vec){
  col <- rainbow(length(unique(vec)))
  return(col[as.numeric(as.factor(vec))])}
plot(pca$x[,1:2], col = colores(vivienda$zona), 
     pch = 19, 
     xlab = "Z1", 
     ylab = "Z2")

#no hay una agrupación de datos claramente definida en el plano.
#ahora, se toman 5 componentes principales y se 
#observa la varianza explicada por cada una de ellas,
prop_varianza <- pca$sdev^2/sum(pca$sdev^2)
round(prop_varianza*100, 2)
## [1] 58.66 23.77  8.91  4.83  3.83
fviz_screeplot(pca, addlabels = TRUE, ylim = c(0, 100))

#La primera dimensión captura el 58.7% de la variabilidad total en los datos, 
#superando la mitad de la variabilidad total.
#Posteriormente, creamos dos representaciones gráficas para discernir qué 
#componentes tienen un impacto más pronunciado en las direcciones de PC1 y PC2.
fviz_contrib(pca, choice = "var", axes = 1, top = 10) 

fviz_contrib(pca, choice = "var", axes = 2, top = 10)

get_pca_var(pca)$contrib[,1:2]
##                 Dim.1     Dim.2
## estrato      10.89021 45.486434
## preciom      25.69187  7.882934
## areaconst    24.40828  2.683486
## banios       26.93215  1.194279
## habitaciones 12.07750 42.752867

Es evidente que la cantidad de baños es la característica que tiene la mayor influencia en la primera componente, con el precio de la vivienda y el estrato siguiendo de cerca en cuanto a su impacto. En contraste, en la segunda componente, son el estrato y la cantidad de habitaciones las que muestran una influencia más significativa.

#ahora se genera un gráfico adicional para el analisis considerando los cuatro cuadrantes
fviz_pca_var(pca,
             col.var = "contrib",
             gradient.cols = c("#FF7F00",  "#034D94"),
             repel = TRUE)

las variables que están sobre el primer cuadrante corresponden a características asociadas a la infraestructura del inmueble, mientras que las variables en el cuarto cuadrante del plano, corresponden a otro tipo de características. ahora calculamos la varianza explicada acumulada

prop_varianza_acum <- cumsum(prop_varianza)
round(prop_varianza_acum*100, 2)
## [1]  58.66  82.43  91.34  96.17 100.00
## [1]  58.66  82.43  91.34  96.17 100.00
ggplot(data = data.frame(prop_varianza_acum, pc = 1:5),
       aes(x = pc, y = prop_varianza_acum, group = 1)) +
  geom_point() +
  geom_line() +
  theme_bw() +
  labs(x = "Componente principal",
       y = "Prop. varianza explicada acumulada")

A partir del Análisis de Componentes Principales PCA, podemos inferir lo siguiente:

En términos de la representación bidimensional de los datos, no es posible distinguir de manera clara un patrón o comportamiento específico de las viviendas en relación con sus zonas.

La primera componente explica el 58.7% de la variabilidad total de los datos, mientras que la segunda componente abarca el 23.8%. En conjunto, estas dos componentes logran explicar el 82.43% de la variabilidad total, lo que indica que ambas componentes retienen la mayor parte de la información contenida en las cinco variables originales.

En la primera componente, las variables de número de baños, precio de la vivienda y área construida son las que ejercen una mayor influencia, respectivamente. En la segunda componente, las variables de estrato y cantidad de habitaciones son las que presentan una mayor influencia, respectivamente. De acuerdo con el análisis de la matriz de correlaciones realizado al principio, se observa que las variables más influyentes en la primera componente están fuertemente correlacionadas entre sí, lo que sugiere que esta componente podría estar relacionada con variables altamente correlacionadas.

Si se busca aplicar un modelo de regresión simple, es factible utilizar las dos componentes resultantes del PCA. Sin embargo, para un modelo de regresión múltiple, es recomendable emplear las cinco variables originales. Posteriormente, es válido comparar el ajuste y las predicciones de ambos modelos.

ANÁLISIS DE CLUSTER NO JERÁRQUICO

#se toman las siguientes variables: estrato, preciom, areacons, banios, habitaciones y zona.
vivienda_3 <- vivienda[1:8319,2:7]
vivienda_3_est <- scale(vivienda_3)
vivienda_3_est <- as.data.frame(vivienda_3_est)
head(vivienda_3_est,5)
##          zona    estrato    preciom  areaconst      banios habitaciones
## 1  0.06192582 -1.5872276 -0.5595498 -0.7339949 -0.07793773    1.6406840
## 2  0.06192582 -1.5872276 -0.3465670 -0.3842568 -0.77811479   -0.4147626
## 3  0.06192582 -1.5872276 -0.2552886  0.3152194 -0.77811479    0.2703863
## 4  0.81508501 -0.6156201 -0.1031580  0.7349051  1.32241640   -0.4147626
## 5 -1.44439256  0.3559875 -0.5291236 -0.5940997 -0.77811479   -0.4147626
scv <- (nrow(vivienda_3_est) - 1) * sum(apply(vivienda_3_est, 2, var))
for (i in 2:15) scv[i] <- sum(kmeans(vivienda_3_est,
                                     centers = i)$withinss)
plot(1:15, scv, 
     type = "b", 
     xlab = "Cantidad de Clusters",
     ylab="Suma de cuadrados dentro de grupos")

set.seed(0)
modelo_kmeans <- kmeans(vivienda_3_est, 3)
vivienda_3_est <- data.frame(vivienda_3_est,
                             modelo_kmeans$cluster) 
aggregate(vivienda_3,
          by = list(vivienda_3_est$modelo_kmeans.cluster),
          FUN = median) 
##   Group.1 zona estrato preciom areaconst banios habitaciones
## 1       1    5       4     230        84      2            3
## 2       2    5       5     690       375      5            5
## 3       3    3       6     525       172      4            3
table(vivienda_3_est$modelo_kmeans.cluster)
## 
##    1    2    3 
## 4493 1268 2558
fviz_cluster(list(data = vivienda_3_est[,1:6], 
                  cluster = vivienda_3_est$modelo_kmeans.cluster),
             palette = c("BLUE",  "YELLOW", "RED"),
             ellipse.type = "convex",repel = F, 
             show.clust.cent = FALSE, ggtheme = theme_minimal())

Estas medidas nos proporcionan una comprensión de la estructura interna inherente a cada conjunto:

El “cluster 1” se distingue por incluir viviendas con precios, áreas y estratos más bajos. De hecho, las medianas del número de baños y habitaciones concuerdan con estas características.

En contraposición, las viviendas vinculadas al “cluster 2” son aquellas con los precios y áreas más elevados. Esto se alinea con las medianas correspondientes al número de baños y habitaciones en este grupo.

La característica destacada en el “cluster 3” es que abarca viviendas con un estrato 6, el cual es el más alto. A pesar de que estas propiedades no tienen un área muy amplia, su valor comercial se acerca mucho al de las viviendas del “cluster 2”.

ANÁLISIS DE CLUSTER JERÁRQUICO

#se emplea un método jerárquico de agrupación.
#con el objetivo de seleccionar el número adecuado de clusters se emplea el coeficiente de Silhouette
#El valor indicado para k es el más cercano a 1
set.seed(0)
dist_eu <- dist(vivienda_3_est[,1:6],method = "euclidean")
modelo_jer <- hclust(dist_eu, method = "ward.D") 
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ tibble  3.1.8     ✔ purrr   1.0.1
## ✔ tidyr   1.3.0     ✔ stringr 1.5.0
## ✔ readr   2.1.3     ✔ forcats 0.5.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ ggplot2::%+%()   masks psych::%+%()
## ✖ ggplot2::alpha() masks psych::alpha()
## ✖ dplyr::filter()  masks stats::filter()
## ✖ dplyr::lag()     masks stats::lag()
library(cluster)

cluster_assigments_k2 <- cutree(modelo_jer, k = 2) # Cluster
sil_1_k2 <- silhouette(cluster_assigments_k2, dist(vivienda_3_est[,1:6]))
sil_1_avg_k2 <- mean(sil_1_k2[,3])
cat("Coeficiente de Silhouette promedio k=2 : ", sil_1_avg_k2)
## Coeficiente de Silhouette promedio k=2 :  0.2907282
cluster_assigments_k3 <- cutree(modelo_jer, k = 3) # Cluster
sil_1_k3 <- silhouette(cluster_assigments_k3, dist(vivienda_3_est[,1:6]))
sil_1_avg_k3 <- mean(sil_1_k3[,3])
cat("Coeficiente de Silhouette promedio k=3 : ", sil_1_avg_k3)
## Coeficiente de Silhouette promedio k=3 :  0.2521172
cluster_assigments_k4 <- cutree(modelo_jer, k = 4) # Cluster
sil_1_k4 <- silhouette(cluster_assigments_k4, dist(vivienda_3_est[,1:6]))
sil_1_avg_k4 <- mean(sil_1_k4[,3])
cat("Coeficiente de Silhouette promedio k=4 : ", sil_1_avg_k4) 
## Coeficiente de Silhouette promedio k=4 :  0.2772796
cluster_assigments_k5 <- cutree(modelo_jer, k = 5) # Cluster
sil_1_k5 <- silhouette(cluster_assigments_k5, dist(vivienda_3_est[,1:6]))
sil_1_avg_k5 <- mean(sil_1_k5[,3])
cat("Coeficiente de Silhouette promedio k=5 : ", sil_1_avg_k5)
## Coeficiente de Silhouette promedio k=5 :  0.2883832
cluster_assigments_k6 <- cutree(modelo_jer, k = 6) # Cluster
sil_1_k6 <- silhouette(cluster_assigments_k6, dist(vivienda_3_est[,1:6]))
sil_1_avg_k6 <- mean(sil_1_k6[,3])
cat("Coeficiente de Silhouette promedio k=6 : ", sil_1_avg_k6)
## Coeficiente de Silhouette promedio k=6 :  0.2191879
cluster_assigments_k7 <- cutree(modelo_jer, k = 7) # Cluster
sil_1_k7 <- silhouette(cluster_assigments_k7, dist(vivienda_3_est[,1:6]))
sil_1_avg_k7 <- mean(sil_1_k7[,3])
cat("Coeficiente de Silhouette promedio k=7 : ", sil_1_avg_k7)
## Coeficiente de Silhouette promedio k=7 :  0.2328442
plot(modelo_jer)
rect.hclust(modelo_jer, k = 2, border = "red")

cluster_jer <- cutree(modelo_jer, k = 2)
vivienda_3_est <- data.frame(vivienda_3_est,cluster_jer)
table(vivienda_3_est$cluster_jer)
## 
##    1    2 
## 2781 5538
aggregate(vivienda_3,
          by = list(vivienda_3_est$cluster_jer),
          FUN = median)
##   Group.1 zona estrato preciom areaconst banios habitaciones
## 1       1    5       5     600       258      4            4
## 2       2    5       5     260        90      2            3
fviz_cluster(list(data = vivienda_3_est[,1:6], 
                  cluster = vivienda_3_est$cluster_jer),
             palette = c("#2E9FDF",  "#E7B800"),
             ellipse.type = "convex",repel = F, 
             show.clust.cent = FALSE, ggtheme = theme_minimal())

Los números de clusters sugeridos por los métodos jerárquico y no jerárquico difieren entre sí, aunque ninguno de ellos sugiere un valor de k = 3. Esto podría indicar que las propiedades carecen de suficiente información para encontrar patrones o características adicionales que permitan generar clusters con una estructura más específica, en lugar de una estructura más general.

Utilizando el modelo K-Means, hemos obtenido tres grupos con características bien definidas. En cuanto a los modelos jerárquicos, cada uno ha generado dos grupos. Las características identificadas eran similares a las obtenidas con el modelo K-Means. Sin embargo, el modelo jerárquico que implementó el criterio “average” arrojó datosm con características muy atípicas en el segundo grupo.

Los gráficos jugaron un papel de respaldo para respaldar las pruebas encontradas a través de las métricas.

No es posible afirmar que un modelo sea superior al otro. Aunque en la comparación entre los modelos jerárquicos, el enfoque basado en el criterio “average” presentó resultados mejores en las métricas en comparación con el método “Ward”. No obstante, como se evidenció en el análisis, este primer modelo tenía un desequilibrio significativo en los clusters.

Estas agrupaciones pueden ser empleadas para realizar un análisis estadístico más exhaustivo en cada uno de los grupos,identificando las características compartidas, los patrones seguidos y las diferencias entre clusters similares. También podría considerarse proponer nuevas medidas y añadir nuevos datos a la tabla para generar clusters con una estructura interna más sólida.

ANÁLISIS DE CORRESPONDENCIA

#se contruye una tabla cruzada para las variables categóricas zona y estrato
library(FactoMineR) # Librería
## Warning: package 'FactoMineR' was built under R version 4.2.3
tabla <- table(vivienda_3$zona, vivienda_3$estrato)
tabla # Tabla cruzada
##    
##        3    4    5    6
##   1  105   14    4    1
##   2  572  407  769  172
##   3   54   84  290  770
##   4  340    8    2    1
##   5  382 1616 1685 1043
chisq.test(tabla)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla
## X-squared = 3830.4, df = 12, p-value < 2.2e-16
library(factoextra) # Librerías
library(gridExtra)
## Warning: package 'gridExtra' was built under R version 4.2.3
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
ac <- CA(tabla)

fviz_screeplot(ac, addlabels = TRUE, 
               ylim = c(0, 80))+ggtitle("")+
  ylab("Porcentaje de varianza explicado") + xlab("Ejes")

Por medio del análisis del plano se puede concluir lo siguiente: Las viviendas que están en la zona Oeste son estrato 6. Las viviendas que están ubicadas en las zonas Norte y Sur son principalmente de estratos 4 y 5. Las viviendas que están ubicadas en las zonas Oriente y Centro son en su mayoría de estrato 3.