#Preparación de los datos

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> 
kable(head(vivienda), caption = "Primeras filas del conjunto de datos de vivienda")
Primeras filas del conjunto de datos de vivienda
id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
1147 Zona Oriente NA 3 250 70 1 3 6 Casa 20 de julio -76.51168 3.43382
1169 Zona Oriente NA 3 320 120 1 2 3 Casa 20 de julio -76.51237 3.43369
1350 Zona Oriente NA 3 350 220 2 2 4 Casa 20 de julio -76.51537 3.43566
5992 Zona Sur 02 4 400 280 3 5 3 Casa 3 de julio -76.54000 3.43500
1212 Zona Norte 01 5 260 90 1 2 3 Apartamento acopi -76.51350 3.45891
1724 Zona Norte 01 5 240 87 1 3 3 Apartamento acopi -76.51700 3.36971

Datos faltantes

#Análiis de data set

vivienda2 <- data.frame(vivienda)

md.pattern(vivienda2, rotate.names = TRUE)

     preciom id zona estrato areaconst banios habitaciones 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

Se encuentran 4808 registros sin datos faltantes, también se encontraron 3514 registros con datos faltante, en donde 2638 resgistros no tiene datos en la variable piso, 1605 les falta información en la variable parqueadero

A continuación se imputan los valores de las variables parqueaderos y piso por el valor de 0 en los registros que no tengan datos.

suppressMessages({
# Imputar valores faltantes con 0
vivienda2$parqueaderos[is.na(vivienda2$parqueaderos)] <- 0

# Imputar valores faltantes con 0
vivienda2$piso[is.na(vivienda2$piso)] <- 0

# Eliminar datos faltantes
vivienda2 <- na.omit(vivienda2)

# Visualizar data
md.pattern(vivienda2, rotate.names = TRUE)
})
 /\     /\
{  `---'  }
{  O   O  }
==>  V <==  No need for mice. This data set is completely observed.
 \  \|/  /
  `-----'

     id zona piso estrato preciom areaconst parqueaderos banios habitaciones
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
Se convierten las columnas a tipo numérico
vivienda2$piso <- as.numeric(vivienda2$piso)
vivienda2$estrato <- as.numeric(vivienda2$estrato)
vivienda2$preciom <- as.numeric(vivienda2$preciom)
vivienda2$areaconst <- as.numeric(vivienda2$areaconst)
vivienda2$banios <- as.numeric(vivienda2$banios)
vivienda2$habitaciones <- as.numeric(vivienda2$habitaciones)

kable(head(vivienda2), caption = "Data con conversión de variables")
Data con conversión de variables
id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
1147 Zona Oriente 0 3 250 70 1 3 6 Casa 20 de julio -76.51168 3.43382
1169 Zona Oriente 0 3 320 120 1 2 3 Casa 20 de julio -76.51237 3.43369
1350 Zona Oriente 0 3 350 220 2 2 4 Casa 20 de julio -76.51537 3.43566
5992 Zona Sur 2 4 400 280 3 5 3 Casa 3 de julio -76.54000 3.43500
1212 Zona Norte 1 5 260 90 1 2 3 Apartamento acopi -76.51350 3.45891
1724 Zona Norte 1 5 240 87 1 3 3 Apartamento acopi -76.51700 3.36971

Análisis de Componentes Principales PCA

Acá se inicia asignando las variables de estrato, presio, area construida, parqueaderos, baños y habitaciones, además, se escalan para continuar con el proceso del PCA

# Selecciona las variables relevantes para el PCA 
vivienda_pca <- vivienda2[, c("estrato", "preciom", "areaconst", "parqueaderos", "banios", "habitaciones")]

# Escala las variables para realizar el PCA
vivienda_pca_scaled <- scale(vivienda_pca)

# Realiza el PCA
res_pca <- prcomp(vivienda_pca_scaled)
# Aplicar PCA
pca_result <- prcomp(vivienda_pca_scaled, center = TRUE, scale. = TRUE)
vivienda3= vivienda2[4:9] %>%
scale()
head(vivienda3) # 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

Componentes principales

prcomp(vivienda3)
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

vivienda3 = scale(vivienda2[,4:9]) 
res.pca <- prcomp(vivienda3)
fviz_eig(res.pca, addlabels = TRUE)

En este caso el primer componente principal explica el 56.9% de la variabilidad contenida en la base de datos y entre los 2 primeros se el 77.9% de los datos, lo cual indicaría que con dos variables (PC1, PC2) que se obtiene mediante una combinación lineal de las variables se puede resumir gran parte de la variabilidad que contiene la base de datos.

fviz_pca_var(res.pca,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#FF7F00",  "#034D94"),
repel = TRUE     # Avoid text overlapping
)

Al visualizar las variables en el plano de los componentes principales se identifica el sentido y la caracterización de los componentes. El primero componente principal está asociado principalmente con la variables habitaciones y área construida, mientras que el segundo componente se puede asociar a las variables estrato y precio.

Para explicar el sentido de los ejes, se escogen cuatro casos extremos conformados por las siguientes viviendas:

datos<- rbind(vivienda2[76,], # ok
              vivienda2[4507,],
              vivienda2[1360,],
              vivienda2[15,])

datos <- as.data.frame(datos)
rownames(datos) = c("vivienda 76","vivienda 4507","vivienda 1360","vivienda 15")
datos
                id       zona piso estrato preciom areaconst parqueaderos
vivienda 76   2635 Zona Norte    0       5     420       105            0
vivienda 4507 5040   Zona Sur    3       3     420       360            1
vivienda 1360 6675   Zona Sur    1       6    1200       420            2
vivienda 15   7824 Zona Norte    2       4     600       160            1
              banios habitaciones        tipo        barrio  longitud latitud
vivienda 76        3            3 Apartamento         acopi -76.52115 3.48967
vivienda 4507      4            8        Casa      melendez -76.53464 3.44987
vivienda 1360      6            5        Casa ciudad jardín -76.54400 3.35700
vivienda 15        4            5        Casa         acopi -76.55210 3.42125
casos1 <- rbind(res.pca$x[76,1:2],res.pca$x[4507,1:2]) # CP1
rownames(casos1) = c("76","4507")
casos1 <- as.data.frame(casos1)

casos2 <- rbind(res.pca$x[1360,1:2], res.pca$x[15,1:2]) # CP2
rownames(casos2) = c("1360","15")
casos2 <- as.data.frame(casos2)

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)

datos<- rbind(vivienda2[76,],
vivienda2[4507,],
vivienda2[1360,],
vivienda2[15,])
rownames(datos) = c("vivienda 76","vivienda 4507","vivienda 1360","vivienda 15")
datos
                id       zona piso estrato preciom areaconst parqueaderos
vivienda 76   2635 Zona Norte    0       5     420       105            0
vivienda 4507 5040   Zona Sur    3       3     420       360            1
vivienda 1360 6675   Zona Sur    1       6    1200       420            2
vivienda 15   7824 Zona Norte    2       4     600       160            1
              banios habitaciones        tipo        barrio  longitud latitud
vivienda 76        3            3 Apartamento         acopi -76.52115 3.48967
vivienda 4507      4            8        Casa      melendez -76.53464 3.44987
vivienda 1360      6            5        Casa ciudad jardín -76.54400 3.35700
vivienda 15        4            5        Casa         acopi -76.55210 3.42125

En la vivienda 76 se observa que tiene 3 habitaciones y en comparación con la vivienda 4507 tiene 8 habitaciones, la cual se encuentra al extremo. Acá se observa como aumentan los valores en el primer componente. En comparación, observamos cómo la vivienda 4507 tiene más habitaciones, un estrato menor y un piso más alto en comparación con la vivienda 76. Además, al mencionar que el valor en el primer componente principal indica la posición en relación con los ingresos, podemos inferir que la vivienda 76 tiende a tener ingresos más bajos, mientras que la vivienda 4507 tiende a tener ingresos más altos.

La Vivienda 1360 se encuentra en la Zona Sur, tiene un estrato más alto (6), un piso más bajo (1), un precio por metro cuadrado más alto ($1200), un área construida de 420 metros cuadrados, 2 parqueaderos, 6 baños y 5 habitaciones.

En comparación, la Vivienda 15 está ubicada en la Zona Norte, tiene un estrato más bajo (4), un piso más alto (2), un precio por metro cuadrado más bajo ($600), un área construida de 600 metros cuadrados, 1 parqueadero, 4 baños y 5 habitaciones.

Ambas viviendas tienen características distintivas en términos de ubicación, estrato, precio, y distribución interna. La Vivienda 6675 destaca por su ubicación en la Zona Sur, estrato más alto y más baños, mientras que la Vivienda 15 tiene un área construida más grande y está ubicada en la Zona Norte.

Análisis de Conglomerados

Viviendacong = (vivienda2)
Viviendacong$piso <- as.numeric(Viviendacong$piso)

Para este análisis de conglomerados se seleccionan las varaibles estrato, precio, area construida, parqueaderos, baños, habitaciones y piso

# Seleccionar variables relevantes para el análisis de conglomerados
viviendacong1 <- select(Viviendacong, "estrato", "preciom", "areaconst", "parqueaderos", "banios", "habitaciones", "piso")

cor(viviendacong1)|>
round(2)
             estrato preciom areaconst parqueaderos banios habitaciones  piso
estrato         1.00    0.61      0.27         0.51   0.42        -0.07  0.11
preciom         0.61    1.00      0.69         0.64   0.67         0.26 -0.04
areaconst       0.27    0.69      1.00         0.48   0.65         0.52 -0.17
parqueaderos    0.51    0.64      0.48         1.00   0.52         0.20  0.02
banios          0.42    0.67      0.65         0.52   1.00         0.59 -0.08
habitaciones   -0.07    0.26      0.52         0.20   0.59         1.00 -0.17
piso            0.11   -0.04     -0.17         0.02  -0.08        -0.17  1.00

Según la anterior matriz de correlación, se encuentran los siguientes resultados:

Se estandarizan las variables

## Se estandarizar las variables para tener media 0 y varianza 1
viviendacong2 = scale(viviendacong1)

viviendacong2 = as.data.frame(viviendacong2)

Se valida la cantidad de clusters sugeridos

fviz_nbclust(viviendacong2, kmeans, method = "wss")

fviz_nbclust(viviendacong2, kmeans, method = "silhouette")

Los anteriores gráficos sugieren que se utilicen 2 cluster para el análisis de los conglomerados

k2 <- kmeans(viviendacong2, centers = 2, nstart = 25)

Por medio de esta gráfica se representan los dos clusters seleccionados

fviz_cluster(k2, data = viviendacong2)

A continuación vamos a representar los clusters y validar sus distacias

# distancia euclidiana
dist_vivi <- dist(viviendacong1, method = 'euclidean')

# Cluster jerarquico con el método complete
hc_emp <- hclust(dist_vivi, method = 'complete')

# Determinamos a dónde pertenece cada observación
cluster_assigments <- cutree(hc_emp, k = 2)

# asignamos los clusters
assigned_cluster <- viviendacong1 %>% mutate(cluster = as.factor(cluster_assigments))


# gráfico de puntos
ggplot(assigned_cluster, aes(x = estrato, y = areaconst, color = cluster)) +
geom_point(size = 2) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()

La formación de dos clusters distintos sugiere que hay diferencias significativas en las propiedades residenciales en términos de estrato socioeconómico y área construida. Este hallazgo indica la existencia de patrones claros.

También se observa que el cluster 1 Incluye propiedades con características específicas, como estrato bajo, áreas construidas más pequeñas, y un menor número de comodidades como parqueaderos y habitaciones. Y el cluster Caracterizado por propiedades de estratos más altos, áreas construidas más grandes, y comodidades adicionales Este cluster representa propiedades más espaciosas.

#```{r, echo=FALSE}
# distancia euclidiana
dist_vivi <- dist(viviendacong1, method = 'euclidean')

# Cluster jerarquico con el método complete
hc_emp <- hclust(dist_vivi, method = 'complete')

# Determinamos a dónde pertenece cada observación
cluster_assigments <- cutree(hc_emp, k = 2)


# Calcular el coeficiente de Silhouette
sil <- silhouette(cluster_assigments, dist(viviendacong1))
sil_avg <- mean(sil[,3])

# Imprimir el coeficiente de Silhouette promedio
cat("Coeficiente de Silhouette promedio k=2 : ", sil_avg)
Coeficiente de Silhouette promedio k=2 :  0.6931269

El Coeficiente de Silhouette promedio sugiere que la configuración de dos clústeres es apropiada y que las observaciones dentro de cada clúster están más cerca de las otras observaciones en el mismo clúster que de las observaciones en otros clústeres.

Análisis por correspondencia

Acá se construye una tabla cruzada con las variables involucradas en el análisis :

Zona : Centro, Norte, Oeste, Oriente, Sur Estrato : 3,4,5,6

library(FactoMineR)
tabla <- table(vivienda2$zona, vivienda2$estrato)
colnames(tabla) <- c("Estrato3", "Estrato4", "Estrato5", "Estrato6" )
tabla
              
               Estrato3 Estrato4 Estrato5 Estrato6
  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)

    Pearson's Chi-squared test

data:  tabla
X-squared = 3830.4, df = 12, p-value < 2.2e-16

Dado que el p-valor es prácticamente cero (menor que cualquier nivel de significancia común, como 0.05), hay evidencia estadística suficiente para rechazar la hipótesis nula de independencia.

resultados_ac <- CA(tabla)

El gráfico permite establecer relaciones y validarlas como son:

El estrato 3 se encuentra en la Zona Oriente y Centro El estrato 6 se encuentra ubicado en la Zona Oeste Los estratos 4 y 5 están ubicados principalmente en la Zona Sur y en a zona Norte el estrato 5 es el único presente

valores_prop <-resultados_ac$eig ; valores_prop
      eigenvalue percentage of variance cumulative percentage of variance
dim 1 0.32215213              69.965515                          69.96551
dim 2 0.12745096              27.680002                          97.64552
dim 3 0.01084108               2.354483                         100.00000

En este resultado se sugiere que la dimensión 1 es la más relevante y explica la mayoría de la variabilidad.

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

Los resultados indican que el primer componente resume el 70 % y los dos primeros componentes y los dos primeros ejes resumen un 97.7% de los datos.

Zona : Centro, Norte, Oeste, Oriente, Sur Tipo de vivienda : Casa, apartamento

tabla2 <- table(vivienda2$zona, vivienda2$tipo)
colnames(tabla2) <- c("Casa", "Apartamento")
tabla2
              
               Casa Apartamento
  Zona Centro    24         100
  Zona Norte   1198         722
  Zona Oeste   1029         169
  Zona Oriente   62         289
  Zona Sur     2787        1939
chisq.test(tabla2)

    Pearson's Chi-squared test

data:  tabla2
X-squared = 690.93, df = 4, p-value < 2.2e-16

En este análisis también se rechazar la hipótesis nula de independencia dado que el p-valor es prácticamente cero (menor que cualquier nivel de significancia común, como 0.05)

res.ACM <- MCA(vivienda2[,c(2,10)], graph = FALSE,)
fviz_mca_var(res.ACM, repel = TRUE, col.var = "blue")

El gráfico permite establecer relaciones y validarlas como son:

El tipo de vivienda Casa se encuentra en la Zona centro, sur y oroente

El tipo de vivienda apartamento se encuentra en la Zona norte y oeste.

valores_prop <-res.ACM$eig ; valores_prop
      eigenvalue percentage of variance cumulative percentage of variance
dim 1  0.6440958               25.76383                          25.76383
dim 2  0.5000000               20.00000                          45.76383
dim 3  0.5000000               20.00000                          65.76383
dim 4  0.5000000               20.00000                          85.76383
dim 5  0.3559042               14.23617                         100.00000
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")

Los resultados indican que el primer componente resume el 70 % y los dos primeros componentes y los dos primeros ejes resumen un 97.7% de los datos, igual que con las variables, zona y estrato.

Conclusiones

El análisis detallado de los datos de vivienda revela información valiosa sobre las propiedades residenciales. A continuación, se presentan algunos hallazgos clave y conclusiones derivadas de los diferentes análisis realizados:

  1. Análisis individual de viviendas:
    • Las viviendas 76 y 4507 representan extremos en términos de habitaciones, estrato y piso. La Vivienda 76 indica ingresos más bajos, mientras que la 4507 sugiere ingresos más altos.
    • La Vivienda 6675, ubicada en la Zona Sur, estrato 6 y con más comodidades, contrasta con la Vivienda 15 en la Zona Norte, estrato 4 y con características diferentes.
  2. Matriz de correlación:
    • El análisis de correlación destaca asociaciones significativas, como el aumento de precios en estratos más altos y la relación positiva entre precio por metro cuadrado y área construida.
    • Además, se observa que propiedades con más baños tienden a tener más habitaciones, y una correlación negativa entre habitaciones y piso.
  3. Análisis de conglomerados:
    • La formación de dos clusters sugiere diferencias significativas en propiedades en términos de estrato y área construida. El cluster 1 representa propiedades con características más modestas, mientras que el cluster 2 incluye propiedades más espaciosas.
    • El Coeficiente de Silhouette respalda la elección de dos clústeres, indicando una buena separación entre las observaciones.
  4. Análisis de Correspondencia Múltiple (ACM):
    • El ACM revela relaciones entre variables categóricas, como la distribución de estratos por zonas y tipos de vivienda. Por ejemplo, el estrato 3 predomina en Zonas Oriente y Centro, mientras que el estrato 6 se encuentra en la Zona Oeste.
  5. Análisis de Componentes Principales (ACP):
    • El primer componente principal resume el 70% de la varianza, y los dos primeros componentes alcanzan un 97.7%. Esto destaca la capacidad de estos componentes para resumir eficientemente la información contenida en los datos.

Recomendaciones: - Considerar estrategias de segmentación de mercado basadas en las diferencias observadas entre los clusters. - En el caso del análisis por correspondencia se puede hacer un zoom a los tipos de vivienda y el estrato, es interesante validar una de las estrategias sobre la ubicación de estratos específicos a los que se quieran llegar con alguna táctica de venta u oferta de compra de viviendas.