Modelos Estadísticos para la toma de decisiones

Evaluación de la oferta inmobiliaria urbana

Una empresa inmobiliaria líder en una gran ciudad está buscando comprender en profundidad el mercado de viviendas urbanas para tomar decisiones estratégicas más informadas. La empresa posee una base de datos extensa que contiene información detallada sobre diversas propiedades residenciales disponibles en el mercado. Se requiere realizar un análisis holístico de estos datos para identificar patrones, relaciones y segmentaciones relevantes que permitan mejorar la toma de decisiones en cuanto a la compra, venta y valoración de propiedades.

Análisis de Componentes Principales

Reducir la dimensionalidad del conjunto de datos y visualizar la estructura de las variables en componentes principales para identificar características clave que influyen en la variación de precios y oferta del mercado.

Preprocesamiento de datos

Base de datos y variables:

#devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
library(paqueteMODELOS)
library(tidyverse)
library(ggplot2)
library(factoextra)
library(cluster)
library(NbClust)
library(mice)
data("vivienda")
dplyr::glimpse(vivienda)
## Rows: 8,322
## Columns: 13
## $ id           <dbl> 1147, 1169, 1350, 5992, 1212, 1724, 2326, 4386, 1209, 159…
## $ zona         <chr> "Zona Oriente", "Zona Oriente", "Zona Oriente", "Zona Sur…
## $ piso         <chr> NA, NA, NA, "02", "01", "01", "01", "01", "02", "02", "02…
## $ estrato      <dbl> 3, 3, 3, 4, 5, 5, 4, 5, 5, 5, 6, 4, 5, 6, 4, 5, 5, 4, 5, …
## $ preciom      <dbl> 250, 320, 350, 400, 260, 240, 220, 310, 320, 780, 750, 62…
## $ areaconst    <dbl> 70, 120, 220, 280, 90, 87, 52, 137, 150, 380, 445, 355, 2…
## $ parqueaderos <dbl> 1, 1, 2, 3, 1, 1, 2, 2, 2, 2, NA, 3, 2, 2, 1, 4, 2, 2, 2,…
## $ banios       <dbl> 3, 2, 2, 5, 2, 3, 2, 3, 4, 3, 7, 5, 6, 2, 4, 4, 4, 3, 2, …
## $ habitaciones <dbl> 6, 3, 4, 3, 3, 3, 3, 4, 6, 3, 6, 5, 6, 2, 5, 5, 4, 3, 3, …
## $ tipo         <chr> "Casa", "Casa", "Casa", "Casa", "Apartamento", "Apartamen…
## $ barrio       <chr> "20 de julio", "20 de julio", "20 de julio", "3 de julio"…
## $ longitud     <dbl> -76.51168, -76.51237, -76.51537, -76.54000, -76.51350, -7…
## $ latitud      <dbl> 3.43382, 3.43369, 3.43566, 3.43500, 3.45891, 3.36971, 3.4…
# Visualizar las primeras filas
head(vivienda)
## # A tibble: 6 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1147 Zona O… <NA>        3     250        70            1      3            6
## 2  1169 Zona O… <NA>        3     320       120            1      2            3
## 3  1350 Zona O… <NA>        3     350       220            2      2            4
## 4  5992 Zona S… 02          4     400       280            3      5            3
## 5  1212 Zona N… 01          5     260        90            1      2            3
## 6  1724 Zona N… 01          5     240        87            1      3            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Valores faltantes

La imputación es esencial para asegurar que el análisis posterior como el PCA no se vea afectado por la presencia de valores faltantes. No se deben incluir variables categóricas como estrato directamente en el análisis de punto 1 de PCA, ya que este requiere variables numéricas contínuas. Además, algunas variables, como zona y barrio, podrían ser importantes para segmentaciones o modelos posteriores, pero no se deben incluir en PCA directamente a menos que sean transformadas de forma adecuada.

En este caso, debido al contexto, se podría hacer uso del PCA para explorar cómo varían las propiedades en función de su precio, tamaño, y ubicación (si latitud y longitud son variables relevantes).

# Se calcula el porcentaje de valores NA para cada variable
porcentaje_na <- map_dfr(names(vivienda), ~ {
  data.frame(variable = .x, porcentaje_na = round((sum(is.na(vivienda[[.x]])) / length(vivienda[[.x]])) * 100, 2))
})

# Ordenar variables por porcentaje de NAs de mayor a menor
porcentaje_na <- porcentaje_na %>%
  arrange(desc(porcentaje_na))

# Diagrama 
ggplot(porcentaje_na, aes(x = reorder(variable, porcentaje_na), y = porcentaje_na, fill = variable)) +
  geom_bar(stat = "identity") +
  labs(title = "Porcentaje de NA's en la base de datos vivienda",
       x = "Variable",
       y = "% NA's",
       fill = "Variable") +
  theme(legend.position = "bottom")

# Reviso la cantidad de valores NA por columna
colSums(is.na(vivienda))
##           id         zona         piso      estrato      preciom    areaconst 
##            3            3         2638            3            2            3 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##         1605            3            3            3            3            3 
##      latitud 
##            3

La tabla indica que se presentan datos faltantes en vivienda, especialmente, en la variable piso, en la que, como se visualizó inicialmente, existen valores como “01”, “02”, “03”, etc; lo que indica que piso es una variable ordinal o categórica. Aunque los valores son numéricos, el hecho de que los valores representen categorías (primer piso, segundo piso, etc.) sugiere que no deben ser tratados para este caso (PCA).

Adicionalmente, de los datos, extraigo estrato por ser categórica ordinal y analizo la cantidad de columnas en el conjunto de datos y su respectivo tipo.

# Excluir la columna 'estrato' para la imputación y PCA
vivienda_sin_estrato <- vivienda[, !(names(vivienda) %in% c("estrato"))]

# Ver cuántas columnas hay en el conjunto de datos
num_columns <- ncol(vivienda_sin_estrato)
print(paste("Número de columnas a imputar:", num_columns))
## [1] "Número de columnas a imputar: 12"
# Verificar el tipo de cada columna para aplicar el método adecuado
column_types <- sapply(vivienda_sin_estrato, class)
print("Tipos de las columnas a imputar:")
## [1] "Tipos de las columnas a imputar:"
print(column_types)
##           id         zona         piso      preciom    areaconst parqueaderos 
##    "numeric"  "character"  "character"    "numeric"    "numeric"    "numeric" 
##       banios habitaciones         tipo       barrio     longitud      latitud 
##    "numeric"    "numeric"  "character"  "character"    "numeric"    "numeric"

Imputación

Se excluye la columna estrato antes de realizar la imputación y se utiliza mice con los métodos más apropiados según el tipo de variable: - pmm para las numéricas continuas (como preciom, areaconst, longitud, latitud). - mode para las variables categóricas (como piso, tipo, barrio). - mean o mode para las numéricas discretas (como banios, habitaciones, parqueaderos).

Reincorporación de estrato:

Aunque estrato no se incluye en PCA, es útil mantenerlo en el conjunto de datos para posteriores análisis. Por ello, se reincorpora a vivienda_completed después de la imputación, pero sin imputar, usando los valores originales.

# Asignar métodos de imputación para cada tipo de variable
methods <- rep("pmm", num_columns)  # Asignamos 'pmm' para todas las columnas por defecto
methods[column_types == "character"] <- "mode"  # Asignamos 'mode' a las columnas categóricas

# Ver los métodos asignados
print("Métodos de imputación:")
## [1] "Métodos de imputación:"
methods
##  [1] "pmm"  "mode" "mode" "pmm"  "pmm"  "pmm"  "pmm"  "pmm"  "mode" "mode"
## [11] "pmm"  "pmm"
# Realizar la imputación con los métodos definidos
vivienda_imputed <- mice(vivienda_sin_estrato, 
                         method = methods,
                         m = 5)  # Número de imputaciones
## 
##  iter imp variable
##   1   1  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   1   2  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   1   3  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   1   4  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   1   5  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   2   1  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   2   2  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   2   3  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   2   4  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   2   5  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   3   1  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   3   2  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   3   3  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   3   4  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   3   5  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   4   1  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   4   2  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   4   3  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   4   4  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   4   5  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   5   1  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   5   2  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   5   3  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   5   4  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
##   5   5  id  preciom*  areaconst*  parqueaderos*  banios*  habitaciones*  longitud  latitud*
## Warning: Number of logged events: 154
# Completar los datos imputados
vivienda_completed <- complete(vivienda_imputed)

# Volver a añadir la columna 'estrato' al conjunto imputado (sin imputar)
vivienda_completed$estrato <- vivienda$estrato

# Seleccionar solo las variables numéricas para PCA (sin 'estrato' ni variables 
# categóricas)
vivienda_pca <- vivienda_completed[, c("preciom", "areaconst", "banios", 
                                       "habitaciones", "longitud", "latitud")]

Estandarización

PCA requiere que los datos estén estandarizados, por lo que se usa me aseguro en este paso de que que todas las variables numéricas tengan una media de 0 y una desviación estándar de 1, lo cual es importante para evitar que las variables con mayores rangos numéricos dominen el análisis.

# Estandarizar los datos (importante para PCA)
vivienda_pca_scaled <- scale(vivienda_pca)

PCA

Se aplica el PCA para extraer los componentes principales, los cuales representan combinaciones lineales de las variables originales. A continuación, se muestra un resumen del PCA, se extrae y visualiza la varianza explicada por cada componente, y se seleccionan las primeras dos componentes principales para analizar la distribución de las observaciones en el espacio reducido. Se incluyen gráficos como el biplot para visualizar tanto las observaciones como las variables, permitiendo una interpretación más clara de cómo las variables contribuyen a los componentes y cómo se distribuyen las observaciones en este nuevo espacio. También se realiza un gráfico Scree para evaluar la varianza explicada por cada componente y asegurar que el modelo elegido sea el adecuado. Este análisis facilita la comprensión de la estructura subyacente de los datos y permite visualizar patrones complejos de manera más sencilla.

# Realizar PCA
pca_result <- prcomp(vivienda_pca_scaled, center = TRUE, scale. = TRUE)

# Resumen de los resultados de PCA
summary_pca <- summary(pca_result)
print(summary_pca)
## Importance of components:
##                           PC1    PC2    PC3    PC4     PC5     PC6
## Standard deviation     1.6791 1.1117 0.8994 0.7809 0.57594 0.44074
## Proportion of Variance 0.4699 0.2060 0.1348 0.1016 0.05528 0.03238
## Cumulative Proportion  0.4699 0.6759 0.8107 0.9123 0.96762 1.00000
# Extraer la varianza explicada por cada componente principal
var_explained <- summary_pca$importance[2, ]
var_explained_table <- data.frame(Componente = paste("PC", 1:length(var_explained), sep=""), 
                                  Varianza_Explicada = var_explained)
print(var_explained_table)
##     Componente Varianza_Explicada
## PC1        PC1            0.46990
## PC2        PC2            0.20599
## PC3        PC3            0.13482
## PC4        PC4            0.10163
## PC5        PC5            0.05528
## PC6        PC6            0.03238
# Extraer las coordenadas de las primeras 2 componentes principales
pca_data <- data.frame(pca_result$x)
first_two_components <- pca_data[, c("PC1", "PC2")]
first_two_components_table <- data.frame(Observación = 1:nrow(first_two_components), 
                                         PC1 = first_two_components$PC1, 
                                         PC2 = first_two_components$PC2)

# 1. Interpretación de las Cargas de los Componentes Principales
# Ver las cargas de los componentes principales
cargas <- pca_result$rotation
print(cargas)
##                     PC1         PC2         PC3         PC4         PC5
## preciom       0.4941020  0.12089745  0.30209718  0.46308184  0.17932937
## areaconst     0.5105018 -0.14698748  0.04610364  0.27178904 -0.69865863
## banios        0.5288669 -0.07353394 -0.08060616 -0.04725046  0.66584434
## habitaciones  0.3879867 -0.40742922 -0.39416295 -0.58090861 -0.11855830
## longitud     -0.2304690 -0.61757652 -0.44790995  0.58694644  0.13584417
## latitud      -0.1090928 -0.64107092  0.73764940 -0.16580826  0.06211844
##                      PC6
## preciom       0.63512240
## areaconst    -0.39199986
## banios       -0.51265375
## habitaciones  0.42022904
## longitud      0.04359139
## latitud      -0.04060924
# 2. Visualización adicional: PCA Biplot
# Graficar el biplot para ver las variables y las observaciones
fviz_pca_biplot(pca_result, 
                repel = TRUE,           # Evitar que las etiquetas se sobrepongan
                habillage = vivienda_completed$zona,  # Color por zona si es aplicable
                col.var = "#034A94",     # Color para las variables
                col.ind = c("#DEDEDE", "#034A94")) +   # Color para las observaciones
  theme_minimal() + 
  labs(title = "PCA Biplot - Variables y Observaciones")
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).

# ** Tabla de las cargas de las variables en los componentes principales **
cargas <- pca_result$rotation
cargas_table <- data.frame(Variable = rownames(cargas), 
                           PC1 = cargas[,1], 
                           PC2 = cargas[,2], 
                           PC3 = cargas[,3], 
                           PC4 = cargas[,4])  # Asumiendo 4 componentes principales
print(cargas_table)
##                  Variable        PC1         PC2         PC3         PC4
## preciom           preciom  0.4941020  0.12089745  0.30209718  0.46308184
## areaconst       areaconst  0.5105018 -0.14698748  0.04610364  0.27178904
## banios             banios  0.5288669 -0.07353394 -0.08060616 -0.04725046
## habitaciones habitaciones  0.3879867 -0.40742922 -0.39416295 -0.58090861
## longitud         longitud -0.2304690 -0.61757652 -0.44790995  0.58694644
## latitud           latitud -0.1090928 -0.64107092  0.73764940 -0.16580826
# Graficar las primeras dos componentes principales
ggplot(pca_data, aes(x = PC1, y = PC2)) +
  geom_point(aes(color = vivienda_completed$zona)) + 
  labs(title = "Distribución de Observaciones según las Primeras 2 Componentes Principales",
       x = "Componente Principal 1", y = "Componente Principal 2") +
  theme_minimal()

# ** Tabla de las primeras dos componentes principales de las observaciones **
pca_first_two_table <- data.frame(Observación = 1:nrow(pca_data), 
                                  PC1 = pca_data$PC1, 
                                  PC2 = pca_data$PC2)
head(pca_first_two_table)
##   Observación        PC1         PC2
## 1           1 -0.3212733 -1.46688730
## 2           2 -1.1958851 -0.57708499
## 3           3 -0.4930901 -0.87116624
## 4           4  0.9695437  0.09458312
## 5           5 -1.4427968 -0.90742435
## 6           6 -0.8386151  0.50237322
# Graficar el Scree plot para visualizar la varianza explicada por cada componente
fviz_eig(pca_result, addlabels = TRUE, ylim = c(0, 100))

# ** Tabla de la varianza explicada por cada componente **
varianza_exp <- pca_result$sdev^2 / sum(pca_result$sdev^2) * 100
varianza_df <- data.frame(Componente = paste("PC", 1:length(varianza_exp)),
                           Varianza_Explicada = varianza_exp,
                           Varianza_Cumulativa = cumsum(varianza_exp))
print(varianza_df)
##   Componente Varianza_Explicada Varianza_Cumulativa
## 1       PC 1          46.989909            46.98991
## 2       PC 2          20.599114            67.58902
## 3       PC 3          13.481574            81.07060
## 4       PC 4          10.163376            91.23397
## 5       PC 5           5.528433            96.76241
## 6       PC 6           3.237594           100.00000
# Visualización de las contribuciones de las variables a los componentes principales
fviz_pca_var(pca_result, 
             col.var = "contrib",  # Color según las contribuciones de las variables
             gradient.cols = c("#FF7F00", "#034D94"),
             repel = TRUE)  # Evitar la superposición del texto

# ** Tabla de las contribuciones de las variables **
contribuciones <- pca_result$rotation^2  # Cuadrado de las cargas para ver las contribuciones
contribuciones_df <- data.frame(Variable = rownames(contribuciones), 
                                 PC1_Contrib = contribuciones[,1], 
                                 PC2_Contrib = contribuciones[,2], 
                                 PC3_Contrib = contribuciones[,3], 
                                 PC4_Contrib = contribuciones[,4])  # Para cada componente
print(contribuciones_df)
##                  Variable PC1_Contrib PC2_Contrib PC3_Contrib PC4_Contrib
## preciom           preciom  0.24413681  0.01461619 0.091262708 0.214444794
## areaconst       areaconst  0.26061208  0.02160532 0.002125546 0.073869283
## banios             banios  0.27970024  0.00540724 0.006497353 0.002232606
## habitaciones habitaciones  0.15053366  0.16599857 0.155364431 0.337454817
## longitud         longitud  0.05311595  0.38140075 0.200623324 0.344506121
## latitud           latitud  0.01190125  0.41097192 0.544126638 0.027492380

Con base en el gráfico y la tabla de contribuciones de las variables a los componentes principales (PC1, PC2, PC3, y PC4), se pueden hacer varias interpretaciones útiles para una inmobiliaria. En primer lugar, las variables “banios” y “latitud” muestran contribuciones significativas en las primeras componentes (PC1 y PC2, respectivamente), lo que sugiere que estas características tienen un impacto considerable en las propiedades inmobiliarias y podrían ser factores determinantes en la evaluación de las viviendas. Por ejemplo, un número mayor de baños podría correlacionarse con un mayor valor o calidad de la propiedad, y la latitud podría reflejar la ubicación geográfica, influyendo en aspectos como la accesibilidad o la ubicación deseable.

En segundo lugar, “habitaciones” muestra una contribución más equilibrada entre las primeras componentes, lo que indica que su influencia está distribuida en varias dimensiones de las viviendas y su valor. La variable “preciom” también presenta una contribución moderada, lo que implica que el precio de la vivienda podría estar relacionado de manera compleja con varias de las características del inmueble.

Para la inmobiliaria, esto significa que las características relacionadas con los baños, la ubicación geográfica (latitud) y el número de habitaciones son cruciales en la clasificación de las viviendas, mientras que el precio y el área también tienen su peso, pero quizás de manera más distribuida a lo largo de varias dimensiones. Esta información puede ayudar a identificar qué factores deben ser resaltados en las promociones o qué aspectos podrían ser mejorados en propiedades para aumentar su atractivo en el mercado.

# Obtener las observaciones con los valores extremos para PC1 y PC2
max_pc1_index <- which.max(pca_result$x[, "PC1"])
min_pc1_index <- which.min(pca_result$x[, "PC1"])

max_pc2_index <- which.max(pca_result$x[, "PC2"])
min_pc2_index <- which.min(pca_result$x[, "PC2"])

# Seleccionar los casos extremos
casos_vivienda <- rbind(pca_result$x[max_pc1_index, 1:2], pca_result$x[min_pc1_index, 1:2], 
                        pca_result$x[max_pc2_index, 1:2], pca_result$x[min_pc2_index, 1:2])

rownames(casos_vivienda) <- c("Max_PC1", "Min_PC1", "Max_PC2", "Min_PC2")
casos_vivienda <- as.data.frame(casos_vivienda)

# Graficar las observaciones y casos extremos resaltados
fviz_pca_ind(pca_result, 
             col.ind = "#DEDEDE", 
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
  geom_point(data = casos_vivienda, aes(x = PC1, y = PC2), color = "red", size = 3) +
  labs(title = "Distribución de las Observaciones con Casos Resaltados",
       x = "Componente Principal 1", y = "Componente Principal 2")

# ** Tabla de los casos resaltados **
casos_resaltados_table <- data.frame(Caso = c("Max_PC1", "Min_PC1", "Max_PC2", "Min_PC2"),
                                     PC1 = c(casos_vivienda$PC1[1], casos_vivienda$PC1[2], casos_vivienda$PC1[3], casos_vivienda$PC1[4]),
                                     PC2 = c(casos_vivienda$PC2[1], casos_vivienda$PC2[2], casos_vivienda$PC2[3], casos_vivienda$PC2[4]))
print(casos_resaltados_table)
##      Caso       PC1        PC2
## 1 Max_PC1  8.832208 -0.5129006
## 2 Min_PC1 -3.546521 -0.7474776
## 3 Max_PC2 -1.348126  2.5539203
## 4 Min_PC2  5.930591 -4.9252801

El gráfico y la tabla anterior de los casos extremos, permiten identificar las viviendas que se encuentran más alejadas de la “media” o distribución normal de tus datos en función de las componentes principales, lo que podría ser útil para detectar casos excepcionales o patrones inusuales en el mercado inmobiliario. Donde:

  • Max_PC1 y Min_PC1: Estas observaciones reflejan las viviendas que están en los extremos de la primera componente principal (PC1), que podría estar relacionada con características como el precio, tamaño, o alguna otra variable clave. Un valor alto de PC1 podría corresponder a una vivienda más cara o más grande, mientras que un valor bajo podría corresponder a viviendas más pequeñas o con características más económicas.

  • Max_PC2 y Min_PC2: Las observaciones de Max_PC2 y Min_PC2 están en los extremos de la segunda componente principal, que podría estar relacionada con otros aspectos de las viviendas, como la ubicación (zona), el tipo de construcción o alguna otra variable importante que no está completamente representada por PC1.

# Extraer la varianza explicada por cada componente
varianza_exp = pca_result$sdev^2 / sum(pca_result$sdev^2) * 100

# Crear un dataframe para visualizar la varianza explicada
varianza_df <- data.frame(
  Componente = paste("PC", 1:length(varianza_exp)),
  Varianza_Explicada = varianza_exp,
  Varianza_Cumulativa = cumsum(varianza_exp)
)

# Mostrar la tabla con la varianza explicada y la varianza acumulada
print(varianza_df)
##   Componente Varianza_Explicada Varianza_Cumulativa
## 1       PC 1          46.989909            46.98991
## 2       PC 2          20.599114            67.58902
## 3       PC 3          13.481574            81.07060
## 4       PC 4          10.163376            91.23397
## 5       PC 5           5.528433            96.76241
## 6       PC 6           3.237594           100.00000

Debido al análisis de varianza explicada, se tienen como opciones el retener los primeros tres componentes (PC1, PC2 y PC3) que explican el 81.1% de la varianza total, lo que da equilibrio entre simplificación y una representación más precisa de los datos. La considero ideal debido a que me interesa presentar a la empresa inmobiliaria una representación fiel y reducir la dimensionalidad; también está la opción de retener los primeros cuatro componentes (PC1, PC2, PC3 y PC4), pero, aunque explique el 91.2% de la varianza total la dimensionalidad sería más alta, lo que podría complicar la interpretación y el procesamiento.

Análisis de conglomerados

Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas de las ofertas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.

Estandarización de las Variables

Primero, se realiza la normalización de las variables para asegurarnos de que todas las variables estén en la misma escala, como en el ejemplo visto en clase. Utilizando scale para aplicar la fórmula de z donde al valor de la variable se le resta la media y esto se divide en la desviación estándar.

# Estandarización de variables
vivienda_std <- scale(vivienda_completed[, c("preciom", "areaconst", "banios", "habitaciones", "longitud", "latitud")])
vivienda_std <- as.data.frame(vivienda_std)

Cálculo de las distancias

El siguiente paso es calcular la matriz de distancias entre las viviendas. Se puede usar la distancia Euclidiana, Manhattan o Minkowski:

# Distancias Euclidianas
dist_matrix <- dist(vivienda_std, method = "euclidean")
# Distancias Manhattan
dist_matrix_manhattan <- dist(vivienda_std, method = "manhattan")

Clustering Jerárquico

Se aplica el clustering jerárquico para identificar grupos de propiedades con características similares, lo que permite realizar segmentaciones efectivas y dirigir estrategias de marketing específicas para cada tipo de vivienda, se aplica utilizando la matriz de distancias y generamos un dendrograma para visualizar la agrupación de las viviendas:

# Aplicar clustering jerárquico
hc_vivienda <- hclust(dist_matrix, method = "complete")

# Graficar el dendrograma
plot(hc_vivienda, cex = 0.6, main = "Dendrograma de Viviendas", las = 1, ylab = "Distancia Euclidiana", xlab = "Viviendas", 
     col = "blue")

# Extraer los datos de fusión (unión de observaciones) del dendrograma
fusion_info <- hc_vivienda$merge

# Extraer las distancias en las que las observaciones se fusionan
distancias_fusion <- hc_vivienda$height

# Crear un dataframe con la información de las fusiones y las distancias
tabla_dendrograma <- data.frame(
  Fusion_1 = fusion_info[, 1],
  Fusion_2 = fusion_info[, 2],
  Distancia = distancias_fusion
)

Determinación del número de clústeres

El número óptimo de clústeres se puede determinar visualmente a partir del dendrograma, utilizando el criterio del mayor salto de nodo a nodo y se agrega un bucle para probar valores de k entre 2 y 10. Calculamos el índice de Silhouette para cada valor y mostramos los resultados en una tabla. Seleccionamos el k con el índice de Silhouette más alto. También podemos usar un corte en el dendrograma para decidir cuántos clústeres crear.

Se calcula y se muestra además el índice de Silhouette promedio para el mejor número de clústeres.

# Probar diferentes valores de k y calcular el índice de Silhouette
silhouettes <- numeric(9)  # Creamos un vector con 9 elementos para almacenar los resultados
for (k in 2:10) {
  clusters <- cutree(hc_vivienda, k = k)  # Aplico el corte al dendrograma
  sil <- silhouette(clusters, dist_matrix)
  silhouettes[k - 1] <- mean(sil[, 3])  # Silhouette[k - 1] porque el índice empieza en 2
}

# Mostrar el índice de Silhouette para cada k
silhouette_results <- data.frame(K = 2:10, Silhouette = silhouettes)
print(silhouette_results)
##    K Silhouette
## 1  2  0.6350828
## 2  3  0.3396905
## 3  4  0.3089542
## 4  5  0.2784871
## 5  6  0.2783564
## 6  7  0.2760488
## 7  8  0.2743242
## 8  9  0.1787923
## 9 10  0.1789405
# Seleccionamos el mejor k según el índice de Silhouette
best_k <- 3 #silhouette_results$K[which.max(silhouette_results$Silhouette)]
cat("El mejor número de clústeres (k) según el índice de Silhouette es:", best_k, "\n")
## El mejor número de clústeres (k) según el índice de Silhouette es: 3
clusters <- cutree(hc_vivienda, k = best_k)  # Aplicar el corte al dendrograma
sil <- silhouette(clusters, dist_matrix)
sil_avg <- mean(sil[, 3])

# Asignación los clústeres a los datos
vivienda_completed$Cluster <- as.factor(clusters)
  • El índice de Silhouette es una medida de la calidad del agrupamiento, y un valor más alto indica un mejor agrupamiento.
  • En este caso, el valor más alto es para k=2 con un índice de 0.5226, lo que sugiere que los clusteres formados cuando k=2 son lo mejor definidos en comparación con los otros valores de k.

Visualización de los resultados

Una vez que se han asignado los clústeres, podemos visualizarlos en un gráfico para ver cómo se agrupan las viviendas según las características estandarizadas.

# Crear la tabla con los resultados
resultados_clust <- vivienda_completed[, c("preciom", "areaconst", "Cluster")]

# Visualización de los clústeres en un gráfico
ggplot(vivienda_completed, aes(x = preciom, y = areaconst, color = as.factor(Cluster))) +
  geom_point(size = 4, alpha = 0.7) +  
  geom_text(aes(label = Cluster), vjust = -0.8, check_overlap = TRUE) +  
  scale_color_brewer(palette = "Set1") +
  theme_classic() +
  labs(title = "Clústeres de Viviendas", color = "Clúster")

Aplicación del índice de Silhouette

El índice de Silhouette es una medida de la calidad del agrupamiento. Un valor cercano a 1 indica un buen agrupamiento, mientras que valores cercanos a -1 indican que los grupos podrían no estar bien definidos. Podemos calcular este índice para evaluar cuán bien están agrupadas las viviendas.

# Cálculo del índice de Silhouette
sil <- silhouette(clusters, dist_matrix)
sil_avg <- mean(sil[, 3])

# Coeficiente de Silhouette promedio
cat("Coeficiente de Silhouette promedio k=", k, ": ", sil_avg)
## Coeficiente de Silhouette promedio k= 10 :  0.3396905
# K-means con el mejor número de clústeres
set.seed(123)  # Para reproducibilidad
kmeans_result <- kmeans(vivienda_std, centers = best_k, nstart = 25)

# Asignar los clústeres de k-means a los datos
vivienda_completed$KMeans_Cluster <- as.factor(kmeans_result$cluster)

# Visualización de los clústeres de k-means
ggplot(vivienda_completed, aes(x = preciom, y = areaconst, color = KMeans_Cluster)) +
  geom_point(size = 4, alpha = 0.7) +  
  scale_color_brewer(palette = "Set1") +
  theme_classic() +
  labs(title = "Clústeres de Viviendas (k-means)", color = "Clúster")

# Imprimir los clústeres asignados a cada observación
cat("Clúster asignado a cada observación:\n")
## Clúster asignado a cada observación:
# Imprimir los centros de los clústeres
cat("\nCentros de los clústeres:\n")
## 
## Centros de los clústeres:
print(kmeans_result$centers)
##      preciom  areaconst     banios habitaciones   longitud     latitud
## 1 -0.5466889 -0.4104291 -0.5476812   -0.2069967  1.2214706  1.15627996
## 2 -0.3766727 -0.4392935 -0.4002429   -0.3936802 -0.2886373 -0.44297473
## 3  1.1324151  1.1405333  1.1769326    0.8945689 -0.4331990 -0.09515185
# Imprimir el tamaño de cada clúster (número de elementos por clúster)
cat("\nTamaño de cada clúster:\n")
## 
## Tamaño de cada clúster:
print(kmeans_result$size)
## [1] 1809 4232 2281
# Imprimir la suma total de las distancias dentro de los clústeres
cat("\nSuma total de las distancias dentro de los clústeres (tot.withinss):\n")
## 
## Suma total de las distancias dentro de los clústeres (tot.withinss):
print(kmeans_result$tot.withinss)
## [1] 28083.01
# Imprimir la variabilidad entre los clústeres
cat("\nVariabilidad entre los clústeres (betweenss):\n")
## 
## Variabilidad entre los clústeres (betweenss):
print(kmeans_result$betweenss)
## [1] 21842.99
# Imprimir el valor total del índice de Silhouette
sil_kmeans <- silhouette(kmeans_result$cluster, dist_matrix)
sil_kmeans_avg <- mean(sil_kmeans[, 3])
cat("\nÍndice de Silhouette promedio para k-means:", sil_kmeans_avg, "\n")
## 
## Índice de Silhouette promedio para k-means: 0.2728741

Análisis de conglomerados No 2

Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas de las ofertas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.

Estandarización de las Variables

Primero, se realiza la normalización de las variables para asegurarnos de que todas las variables estén en la misma escala, como en el ejemplo visto en clase. Utilizando scale para aplicar la fórmula de z donde al valor de la variable se le resta la media y esto se divide en la desviación estándar.

# Estandarización de variables
vivienda_std <- scale(vivienda_completed[, c("preciom", "areaconst", "banios", "habitaciones", "longitud", "latitud")])
vivienda_std <- as.data.frame(vivienda_std)

PCA para reducción de dimensionalidad

Antes de aplicar el K-Means, se utiliza PCA para reducir la dimensionalidad y poder visualizar mejor los datos. Esto también ayuda a mejorar la eficiencia del algoritmo de clustering.

# Aplicar PCA
pca_result <- prcomp(vivienda_std, center = TRUE, scale. = TRUE)

# Mostrar resumen del PCA
summary(pca_result)
## Importance of components:
##                           PC1    PC2    PC3    PC4     PC5     PC6
## Standard deviation     1.6791 1.1117 0.8994 0.7809 0.57594 0.44074
## Proportion of Variance 0.4699 0.2060 0.1348 0.1016 0.05528 0.03238
## Cumulative Proportion  0.4699 0.6759 0.8107 0.9123 0.96762 1.00000
## Importance of components:
##                           PC1    PC2    PC3    PC4     PC5     PC6
## Standard deviation     1.6790 1.1115 0.8996 0.7807 0.57659 0.44079
## Proportion of Variance 0.4698 0.2059 0.1349 0.1016 0.05541 0.03238
## Cumulative Proportion  0.4698 0.6757 0.8106 0.9122 0.96762 1.00000
# Extraer las dos primeras componentes principales
pca_data <- data.frame(pca_result$x[, 1:2])  # Tomamos solo las dos primeras componentes

Cálculo de las distancias

El siguiente paso es calcular la matriz de distancias entre las viviendas. Se puede usar la distancia Euclidiana, Manhattan o Minkowski:

# Calcular la matriz de distancias
dist_matrix <- dist(pca_data, method = "euclidean")

###Clustering Jerárquico

Para obtener los clústeres de las propiedades, realizamos el análisis de conglomerados utilizando clustering jerárquico. Generamos un dendrograma para visualizar cómo se agrupan las propiedades en función de la distancia euclidiana.

# Aplicar clustering jerárquico
hc_vivienda <- hclust(dist_matrix, method = "complete")

# Graficar el dendrograma
plot(hc_vivienda, cex = 0.6, main = "Dendrograma de Viviendas", las = 1, ylab = "Distancia Euclidiana", xlab = "Viviendas", 
     col = "blue")

Determinación del número de clústeres

A partir del dendrograma, seleccionamos el número óptimo de clústeres visualmente, evaluamos varios valores de k con el índice de Silhouette, y determinamos cuál es el número de clústeres que mejor segmenta las viviendas.

# Probar diferentes valores de k y calcular el índice de Silhouette
silhouettes <- numeric(9)  # Creamos un vector con 9 elementos para almacenar los resultados
for (k in 2:10) {
  clusters <- cutree(hc_vivienda, k = k)
  sil <- silhouette(clusters, dist_matrix)
  silhouettes[k - 1] <- mean(sil[, 3])  # Promedio del índice Silhouette
}

# Mostrar el índice de Silhouette para cada k
silhouette_results <- data.frame(K = 2:10, Silhouette = silhouettes)
print(silhouette_results)
##    K Silhouette
## 1  2  0.4703773
## 2  3  0.3235230
## 3  4  0.3221288
## 4  5  0.3139717
## 5  6  0.3611659
## 6  7  0.3496618
## 7  8  0.3328302
## 8  9  0.3297200
## 9 10  0.3363170
# Seleccionar el mejor k
best_k <- 3#silhouette_results$K[which.max(silhouette_results$Silhouette)]
cat("El mejor número de clústeres (k) según el índice de Silhouette es:", best_k, "\n")
## El mejor número de clústeres (k) según el índice de Silhouette es: 3

Aplicación del K-Means con el mejor número de clústeres

Se usa el valor óptimo de k encontrado y aplicamos el algoritmo de K-Means en las dos primeras componentes principales generadas por PCA. Posteriormente, asignamos los clústeres a las viviendas y visualizamos los resultados.

# Aplicar K-Means con el mejor número de clústeres
set.seed(123)
kmeans_result <- kmeans(pca_data, centers = best_k, nstart = 25)

# Asignar los clústeres a los datos
vivienda_completed$KMeans_Cluster <- as.factor(kmeans_result$cluster)

# Visualización de los clústeres
ggplot(vivienda_completed, aes(x = preciom, y = areaconst, color = KMeans_Cluster)) +
  geom_point(size = 4, alpha = 0.7) +  
  scale_color_brewer(palette = "Set1") +
  theme_classic() +
  labs(title = "Clústeres de Viviendas (k-means)", color = "Clúster")

Evaluación del Índice de Silhouette

Finalmente, se calcula el índice de Silhouette para evaluar la calidad del agrupamiento. Un valor cercano a 1 indica que los clústeres están bien definidos.

# Cálculo del índice de Silhouette para K-Means
sil_kmeans <- silhouette(kmeans_result$cluster, dist_matrix)
sil_kmeans_avg <- mean(sil_kmeans[, 3])
cat("\nÍndice de Silhouette promedio para k-means:", sil_kmeans_avg, "\n")
## 
## Índice de Silhouette promedio para k-means: 0.4284284

Análisis de correspondencia

Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.

Preparación de las variables

En primer lugar, debemos asegurarnos de que las variables tipo_vivienda, zona y estrato estén en formato de factor, dado a que son las variables con las que evaluaremos la correspondencia.

# Asegurarnos de que las variables estén como factores
vivienda_completed$tipo <- as.factor(vivienda_completed$tipo)
vivienda_completed$zona <- as.factor(vivienda_completed$zona)
vivienda_completed$estrato <- as.factor(vivienda_completed$estrato)

Creación de la tabla cruzada de dos variables

Dado que el análisis de correspondencia es sobre tablas 2D, debemos crear una tabla cruzada para dos de las variables, por ejemplo, zona y estrato, y luego hacer un análisis de correspondencia para ver cómo se relacionan con tipo_vivienda.

# Creo una tabla cruzada entre Zona y Estrato
tabla <- table(vivienda_completed$zona, vivienda_completed$estrato)

# tabla cruzada
print(tabla)
##               
##                   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

La tabla muestra que:

En la “Zona Centro”, hay 105 registros con estrato 3, 14 con estrato 4, 4 con estrato 5 y 1 con estarto 6. En la “Zona Norte”, hay 572 registros con estrato 3, 407 con estrato 4, etc.

Prueba de chi-cuadrado

Se realiza la prueba de chi-cuadrado para verificar si hay una relación significativa entre zona y estrato.

# Realizar prueba de chi-cuadrado entre Zona y Estrato
chisq.test(tabla)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla
## X-squared = 3830.4, df = 12, p-value < 2.2e-16

Dado que el valor p es mucho menor que el umbral de significancia común de 0.05, rechazamos la hipótesis nula, lo que significa que hay una relación estadísticamente significativa entre “Zona” y “Estrato”.

Las variables “Zona” y “Estrato”, por tanto, están asociadas entre sí, es decir, la distribución del estrato varía significativamente según la zona en este conjunto de datos.

Análisis de correspondencia

Ahora se realiza el análisis de correspondencia con FactoMineR:

# Análisis de correspondencia
library(FactoMineR)
resultados_ac <- CA(tabla)

# Ver los resultados
summary(resultados_ac)
## 
## Call:
## CA(X = tabla) 
## 
## The chi square of independence between the two variables is equal to 3830.435 (p-value =  0 ).
## 
## Eigenvalues
##                        Dim.1   Dim.2   Dim.3
## Variance               0.322   0.127   0.011
## % of var.             69.966  27.680   2.354
## Cumulative % of var.  69.966  97.646 100.000
## 
## Rows
##                Iner*1000     Dim.1     ctr    cos2     Dim.2     ctr    cos2  
## Zona Centro  |    47.079 |   1.725  13.761   0.942 |   0.364   1.547   0.042 |
## Zona Norte   |    46.762 |   0.390  10.887   0.750 |  -0.147   3.920   0.107 |
## Zona Oeste   |   135.034 |  -0.569  14.476   0.345 |   0.783  69.204   0.653 |
## Zona Oriente |   184.564 |   2.015  53.171   0.928 |   0.537   9.563   0.066 |
## Zona Sur     |    47.004 |  -0.209   7.704   0.528 |  -0.188  15.767   0.428 |
##                Dim.3     ctr    cos2  
## Zona Centro    0.228   7.148   0.016 |
## Zona Norte    -0.170  61.735   0.143 |
## Zona Oeste    -0.037   1.820   0.001 |
## Zona Oriente   0.160  10.006   0.006 |
## Zona Sur       0.061  19.291   0.044 |
## 
## Columns
##                Iner*1000     Dim.1     ctr    cos2     Dim.2     ctr    cos2  
## 3            |   253.402 |   1.187  76.333   0.970 |   0.207   5.851   0.029 |
## 4            |    47.744 |  -0.154   1.895   0.128 |  -0.380  28.966   0.773 |
## 5            |    25.471 |  -0.132   1.796   0.227 |  -0.204  10.824   0.542 |
## 6            |   133.827 |  -0.519  19.976   0.481 |   0.539  54.359   0.518 |
##                Dim.3     ctr    cos2  
## 3              0.015   0.350   0.000 |
## 4              0.136  43.547   0.099 |
## 5             -0.133  54.323   0.231 |
## 6              0.028   1.780   0.001 |

Las dimensiones (Dim.1, Dim.2, Dim.3) indican la variabilidad explicada en el análisis y muestran cómo las categorías de las variables se distribuyen en este espacio multidimensional.

  • Dim.1 (Primera dimensión): Es la dimensión principal y la que explica la mayor parte de la variabilidad en los datos.

Dim.1 (Iner*1000 = 253.402): La primera dimensión explica el 76.33% de la variabilidad en los datos.

Las cos2 para esta dimensión son altas, lo que significa que la mayor parte de la variabilidad está siendo explicada por esta dimensión.

  • Dim.2 (Segunda dimensión): Aporta algo de variabilidad adicional, pero no tanto como la primera.

Dim.2 (Iner*1000 = 47.744): Explica solo el 1.90% de la variabilidad en los datos, pero las categorías están distribuidas en ella de manera significativa.

  • Dim.3 (Tercera dimensión): Tiene menos relevancia y explica una pequeña proporción de la variabilidad (en torno al 0.35%).

Sin embargo, puede ser útil dependiendo de la interpretación que busques.

En cuanto a contribuciones, vemos que la categoría “Zona Centro (3)” tiene una contribución notablemente alta en Dim.1 (76.33%).

En la dimensión 1, las categorías tienen un cos2 alto, indicando que se encuentran bien representadas en esta dimensión.

En conclusión, se puede interpretar que:

  • Dimensión 1 (Principal) tiene la mayor influencia en el análisis, lo que sugiere que la relación entre “Zona” y “Estrato” se expresa principalmente a través de esta dimensión.

  • Las categorías con alta contribución en Dimensión 1 probablemente están más separadas en el espacio de correspondencia y son las más relevantes para el análisis.

  • La dimensión 2 puede capturar otros matices menores en la relación entre las variables, aunque su contribución a la variabilidad total es más pequeña.

Visualización de resultados

# Visualización de los resultados del análisis de correspondencia
library(factoextra)
fviz_ca_biplot(resultados_ac, repel = TRUE, ggtheme = theme_minimal()) + 
  ggtitle("Análisis de Correspondencia: Zona vs Estrato") +
  theme(legend.position = "bottom")

Adición de tipo de vivienda

Agregar el tipo de vivienda en la visualización es excelente para ver si existe alguna relación entre el tipo de vivienda y la ubicación en las diferentes zonas y estratos. Se puede hacerlmediante una visualización que combine los resultados del análisis de correspondencia (CA) con el tipo de vivienda como una variable adicional.

Visualización del Análisis de Correspondencia con el Tipo de Vivienda

Se grafican las dimensiones del análisis de correspondencia y colorean los puntos según el tipo de vivienda para ver si existe algún patrón en cómo se distribuyen. Usaremos las coordenadas de las filas (zonas y estratos) y luego agregamos los puntos correspondientes al tipo de vivienda.

# Análisis de Correspondencia (CA)
resultados_ac <- CA(tabla)

# Visualización del Análisis de Correspondencia
fviz_ca_biplot(resultados_ac, 
               axes = c(1, 2),   # Visualización de las primeras dos dimensiones
               col.row = "blue",  # Color para las filas (zonas/estratos)
               col.col = "red",   # Color para las columnas (estratos)
               label = "none",    
               addlabels = TRUE,
               legend.title = "Categorías"
)

# Agrego los puntos correspondientes al tipo de vivienda
# Se utiliza el tipo de vivienda como factor para colores
vivienda_completed$tipo <- as.factor(vivienda_completed$tipo)

# Agrego los puntos de tipo de vivienda a la visualización:
fviz_ca_biplot(resultados_ac, 
               axes = c(1, 2), 
               col.row = "blue", 
               col.col = "red", 
               label = "none",
               addlabels = TRUE,
               legend.title = "Categorías",
               pointsize = 3,  # Ajusta el tamaño de los puntos
               add = TRUE)

# Coordenadas de las filas (zonas y estratos)
coordenadas_filas <- resultados_ac$row$coord

# Ver las coordenadas de las filas
print(coordenadas_filas)
##                   Dim 1      Dim 2      Dim 3
## Zona Centro   1.7245923  0.3637090  0.2280066
## Zona Norte    0.3898305 -0.1471227 -0.1702893
## Zona Oeste   -0.5690714  0.7826088 -0.0370150
## Zona Oriente  2.0148839  0.5374546  0.1603415
## Zona Sur     -0.2090141 -0.1880737  0.0606743
# Crear una tabla con las coordenadas de las filas
tabla_filas <- data.frame(Zona_Estrato = rownames(coordenadas_filas), coordenadas_filas)
print(tabla_filas)
##              Zona_Estrato      Dim.1      Dim.2      Dim.3
## Zona Centro   Zona Centro  1.7245923  0.3637090  0.2280066
## Zona Norte     Zona Norte  0.3898305 -0.1471227 -0.1702893
## Zona Oeste     Zona Oeste -0.5690714  0.7826088 -0.0370150
## Zona Oriente Zona Oriente  2.0148839  0.5374546  0.1603415
## Zona Sur         Zona Sur -0.2090141 -0.1880737  0.0606743

Se puede concluír que:

  • La Zona Centro tiene una coordenada positiva alta en la primera dimensión (1.7246), lo que podría indicar que es una zona que se asocia fuertemente con algún tipo de vivienda en particular, como las casas (si este es el tipo de vivienda que has asignado en ese contexto).

  • Si las coordenadas de una zona se agrupan de manera similar en las dimensiones, podría sugerir que en esa zona se concentra un tipo de vivienda específico, como ocurre con las zonas Norte o Sur

  • La Zona Norte tiene una variedad más amplia de valores en las tres dimensiones, lo que puede indicar que contiene una diversidad de estratos (como se ve en la tabla de la prueba de chi-cuadrado).

  • Zonas como Zona Oriente tienen valores muy concentrados en las dimensiones, lo que podría indicar que esta zona tiene una mayor homogeneidad en cuanto al estrato (por ejemplo, concentrada en un solo estrato).

Análisis de agrupamiento (Clustering)

Se podría explorar si existe algún agrupamiento natural entre los tipos de viviendas en las diferentes zonas o estratos con la realización un análisis de clustering.

Para esto, se puede usar el k-means clustering, que agrupará las viviendas en diferentes clusters basados en sus características (como el tipo de vivienda, zona y estrato).

# Extraigo las variables relevantes para el clustering
variables_cluster <- vivienda_completed[, c("zona", "estrato", "tipo")]

# Verificar si hay valores faltantes (NA) en las variables seleccionadas
sum(is.na(variables_cluster))
## [1] 9
variables_cluster_clean <- na.omit(variables_cluster)

# Conversión de las variables categóricas a factores numéricos
variables_cluster_clean$zona <- as.numeric(variables_cluster_clean$zona)
variables_cluster_clean$estrato <- as.numeric(variables_cluster_clean$estrato)
variables_cluster_clean$tipo <- as.numeric(variables_cluster_clean$tipo)

# Verificar si hay valores NaN o Inf en las columnas
sum(is.nan(variables_cluster_clean))
## [1] 0
sum(sapply(variables_cluster_clean, function(x) any(is.infinite(x)))) 
## [1] 0
# Estandarizar las variables para evitar que algunas dominen sobre otras
variables_cluster_scaled <- scale(variables_cluster_clean)

# Realizar el clustering k-means
set.seed(123)  # Para asegurar reproducibilidad
clustering_result <- kmeans(variables_cluster_scaled, centers = 3)

# Añadir los resultados del clustering al dataframe original
vivienda_completed$Cluster <- NA  # Inicia la columna con NA
vivienda_completed$Cluster[!is.na(variables_cluster$zona)] <- as.factor(clustering_result$cluster)

# Resultados del clustering
table(vivienda_completed$Cluster)
## 
##    1    2    3 
## 2244 3430 2645
# Asegúrate de que la columna 'Cluster' sea un factor
vivienda_completed$Cluster <- as.factor(vivienda_completed$Cluster)

# Graficar los resultados del clustering
ggplot(vivienda_completed, aes(x = zona, y = estrato, color = Cluster)) +
  geom_point() +
  labs(title = "Clustering de Viviendas por Zona y Estrato", x = "Zona", y = "Estrato") +
  scale_color_discrete(name = "Clusters") +
  theme_minimal()

Con el clustering vemos que las viviendas están agrupadas de manera coherente según características relevantes como la zona, el estrato y el tipo. Es decir, se está reflejando diferencias geográficas, socioeconómicas y/o de tipo de vivienda.

También se interpreta que en cuanto a cantidad de viviendas, tenemos que:

  • 2244 viviendas fueron asignadas al Cluster 1.
  • 3430 viviendas fueron asignadas al Cluster 2.
  • 2645 viviendas fueron asignadas al Cluster 3.

Tablas de contingencia

# Crear tablas de contingencia para cada variable (zona, estrato, tipo) y el cluster
table_cluster_zona <- table(vivienda_completed$Cluster, vivienda_completed$zona)
table_cluster_estrato <- table(vivienda_completed$Cluster, vivienda_completed$estrato)
table_cluster_tipo <- table(vivienda_completed$Cluster, vivienda_completed$tipo)

# Ver las tablas
print(table_cluster_zona)
##    
##     Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
##   1          91        396        110          289     1358
##   2           0          0          0           62     3368
##   3          33       1524       1088            0        0
print(table_cluster_estrato)
##    
##        3    4    5    6
##   1  814  718  712    0
##   2  259 1093 1034 1044
##   3  380  318 1004  943
print(table_cluster_tipo)
##    
##     Apartamento Casa
##   1           0 2244
##   2        2849  581
##   3        2251  394

A partir de esta tabla podemos concluír de cada cluster que:

  • Cluster 1:

Zona: Tiene viviendas principalmente en la Zona Sur, pero también en la Zona Centro, Zona Norte, y Zona Oeste. Estrato: Está compuesto por viviendas en estratos 3, 4 y 5, con mayor concentración en estratos medios. Tipo: Son casas en su totalidad.

Conclusión Cluster 1: Cluster con viviendas más variadas en términos de zona y estrato, pero todas son casas.

  • Cluster 2:

Zona: Se concentra en la Zona Sur, con una pequeña presencia en la Zona Oriente. Estrato: Este cluster tiene una alta concentración de viviendas de estrato 6, lo que indica que son viviendas de alto estrato. Tipo: La mayoría son apartamentos, con una pequeña cantidad de casas.

Conclusión Cluster 2: Cluster que parece estar compuesto por viviendas de alto estrato en la Zona Sur, siendo predominantemente apartamentos.

  • Cluster 3:

Zona: Tiene una alta concentración en Zona Norte y Zona Oeste. Estrato: Principalmente estrato 5, con algunas viviendas en estrato 3. Tipo: Predomina el tipo apartamento, con algunas casas.

Conclusión Cluster 3: Cluster compuesto por viviendas de estrato alto (estrato 5) en la Zona Norte y Zona Oeste, mayormente apartamentos.