Introducción

El presente trabajo tiene como propósito analizar el mercado de viviendas urbanas a partir de una base de datos de propiedades residenciales, con el fin de identificar patrones y características que puedan aportar información útil para la toma de decisiones en el sector inmobiliario. Para abordar este reto se realizará inicialmente una exploración y preparación de los datos, seguida de la aplicación de técnicas de análisis multivariado como el Análisis de Componentes Principales (ACP), el Análisis de Conglomerados y el Análisis de Correspondencia. Finalmente, los resultados obtenidos serán representados mediante diferentes recursos gráficos y visualizaciones, con el objetivo de interpretar los principales hallazgos y plantear conclusiones y recomendaciones a partir de la evidencia encontrada

1. Preparación y exploración de los datos

Como primer paso procedemos a cargar el paquete MODELOS que contiene la base de datos vivienda.

library(paqueteMODELOS)
data("vivienda")
dim(vivienda)
## [1] 8322   13

A partir de esto, se identifica un total de 8322 registros y 13 variables.

A continuación, se presenta la descripción y clasificación de las variables que componen la base de datos.

1.1 Revisión de valores faltantes

Se verifica la presencia de valores faltantes en cada una de las variables de la base de datos.

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

Con base en el resultado anterior, se observa la presencia de datos faltantes en todas las variables. Sin embargo, piso y parqueaderos presentan la mayor cantidad de valores faltantes, con 2638 y 1605 registros, respectivamente. Debido a su magnitud, se analizará el comportamiento de estos valores antes de tomar una decisión sobre su tratamiento.

table(vivienda$tipo, is.na(vivienda$piso))
##              
##               FALSE TRUE
##   Apartamento  3719 1381
##   Casa         1965 1254
table(vivienda$piso, useNA = "ifany")
## 
##   01   02   03   04   05   06   07   08   09   10   11   12 <NA> 
##  860 1450 1097  607  567  245  204  211  146  130   84   83 2638
table(vivienda$tipo, is.na(vivienda$piso), useNA = "ifany")
##              
##               FALSE TRUE
##   Apartamento  3719 1381
##   Casa         1965 1254
##   <NA>            0    3

Al analizar los 2638 valores faltantes de la variable piso, se encontró que 1381 corresponden a apartamentos y 1254 a casas. Los tres registros restantes no tienen información asociada en la variable tipo. Por lo tanto, los valores faltantes de piso no pueden atribuirse exclusivamente a un tipo específico de vivienda.

table(vivienda$tipo, is.na(vivienda$parqueaderos), useNA = "ifany")
##              
##               FALSE TRUE
##   Apartamento  4231  869
##   Casa         2486  733
##   <NA>            0    3

En la variable parqueaderos se identificaron 1.605 valores faltantes. Al analizar estos registros según el tipo de vivienda, se observa que los valores faltantes se distribuyen entre casas y apartamentos. Adicionalmente, 3 registros no presentan información sobre el tipo de vivienda, por lo que no pueden ser clasificados dentro de ninguna de estas dos categorías.

vivienda[is.na(vivienda$tipo), c("id", "tipo", "piso", "parqueaderos")]
## # A tibble: 3 × 4
##      id tipo  piso  parqueaderos
##   <dbl> <chr> <chr>        <dbl>
## 1    NA <NA>  <NA>            NA
## 2    NA <NA>  <NA>            NA
## 3    NA <NA>  <NA>            NA
vivienda[is.na(vivienda$id), ]
## # A tibble: 3 × 13
##      id zona  piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr> <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1    NA <NA>  <NA>       NA      NA        NA           NA     NA           NA
## 2    NA <NA>  <NA>       NA      NA        NA           NA     NA           NA
## 3    NA <NA>  <NA>       NA     330        NA           NA     NA           NA
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Durante la revisión de los datos faltantes se planteó la posibilidad de que los tres registros sin información en la variable tipo correspondieran a los mismos registros faltantes identificados en otras variables. Para comprobarlo, se examinaron las observaciones asociadas a estos valores y posteriormente los registros cuyo id era faltante. Se encontró que los mismos tres registros presentan valores NA en prácticamente todas las variables de la base de datos. Uno de ellos únicamente contiene información en la variable preciom, mientras que los demás no cuentan con información suficiente para caracterizar una propiedad. Por esta razón, se considera pertinente excluir estas tres observaciones antes de continuar con los análisis posteriores.

vivienda_limpia <- vivienda[!is.na(vivienda$id), ]

dim(vivienda_limpia)
## [1] 8319   13
colSums(is.na(vivienda_limpia))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0         2635            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##         1602            0            0            0            0            0 
##      latitud 
##            0

Luego de excluir los tres registros identificados, la base de datos quedó conformada por 8319 observaciones y 13 variables. Al realizar nuevamente la revisión de valores faltantes, se encontró que estos permanecen únicamente en las variables piso y parqueaderos, con 2635 y 1602 valores faltantes, respectivamente.

1.2 Revisión de datos duplicados

Se verifica la presencia de registros duplicados en la base de datos depurada (vivienda_limpia), considerando inicialmente la duplicación de filas completas.

sum(duplicated(vivienda_limpia))
## [1] 0

La revisión de duplicados no identificó registros completamente repetidos en la base de datos depurada. Ahora bien, es importante comprobar si existen identificadores (id) identicos.

sum(duplicated(vivienda_limpia$id))
## [1] 0

Al verificar la variable id, se obtuvo cero valores duplicados. Esto indica que cada una de las 8319 observaciones conservadas posee un identificador único y no se requiere realizar ninguna eliminación adicional por duplicidad.

1.3 Revisión de datos atípicos

Para la identificación de posibles valores atípicos se analizarán las variables cuantitativas relacionadas con las características físicas y económicas de las viviendas: precio, área construida, número de parqueaderos, baños y habitaciones.

variables_num <- vivienda_limpia[, c(
  "preciom",
  "areaconst",
  "parqueaderos",
  "banios",
  "habitaciones"
)]

summary(variables_num)
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 220.0   1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 330.0   Median : 123.0   Median : 2.000   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.835   Mean   : 3.111  
##  3rd Qu.: 540.0   3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1745.0   Max.   :10.000   Max.   :10.000  
##                                    NA's   :1602                     
##   habitaciones   
##  Min.   : 0.000  
##  1st Qu.: 3.000  
##  Median : 3.000  
##  Mean   : 3.605  
##  3rd Qu.: 4.000  
##  Max.   :10.000  
## 

El resumen descriptivo permite observar los rangos y principales medidas de las variables seleccionadas. Se identifican valores máximos considerablemente superiores a sus respectivas medianas en variables como precio y área construida. Asimismo, se observa la presencia de valores iguales a cero en las variables baños y habitaciones, los cuales requieren una revisión adicional antes de determinar si corresponden a valores válidos o a posibles inconsistencias en los datos

Revision de valores cero en baños y habitaciones

Debido a que el resumen descriptivo mostró valores mínimos iguales a cero en las variables baños y habitaciones, se revisa su frecuencia para determinar la magnitud de estos casos.

table(vivienda_limpia$banios)
## 
##    0    1    2    3    4    5    6    7    8    9   10 
##   45  496 2946 1993 1456  890  314  107   48   15    9
table(vivienda_limpia$habitaciones)
## 
##    0    1    2    3    4    5    6    7    8    9   10 
##   66   59  926 4097 1729  679  318  173  138   83   51

Se identificaron 45 propiedades registradas con cero baños y 66 con cero habitaciones. Debido a que estos valores podrían corresponder a características reales o a información registrada de manera incompleta, se procede a examinar estos casos con mayor detalle.

table(
  vivienda_limpia$tipo[vivienda_limpia$banios == 0]
)
## 
## Apartamento        Casa 
##          14          31
table(
  vivienda_limpia$tipo[vivienda_limpia$habitaciones == 0]
)
## 
## Apartamento        Casa 
##          21          45

Al analizar estos registros según el tipo de vivienda, se observa que los valores iguales a cero están presentes tanto en casas como en apartamentos. En el caso de los baños, 14 corresponden a apartamentos y 31 a casas, mientras que para habitaciones se identifican 21 apartamentos y 45 casas. Por lo tanto, estos valores no parecen estar asociados exclusivamente a un tipo específico de vivienda.

vivienda_limpia[vivienda_limpia$banios == 0,
                c("id", "tipo", "preciom", "areaconst",
                  "banios", "habitaciones")]
## # A tibble: 45 × 6
##       id tipo        preciom areaconst banios habitaciones
##    <dbl> <chr>         <dbl>     <dbl>  <dbl>        <dbl>
##  1   243 Casa            190       435      0            0
##  2  3273 Casa            400       324      0            0
##  3  7245 Casa           1200       752      0            0
##  4  4995 Casa            420       235      0            0
##  5  1816 Casa            750       183      0            0
##  6  7509 Casa           1200       660      0            0
##  7  6839 Apartamento     900       250      0            0
##  8  4393 Casa            380       264      0            0
##  9  1898 Apartamento     220        68      0            3
## 10  1425 Casa            395       220      0            0
## # ℹ 35 more rows
vivienda_limpia[vivienda_limpia$habitaciones == 0,
                c("id", "tipo", "preciom", "areaconst",
                  "banios", "habitaciones")]
## # A tibble: 66 × 6
##       id tipo  preciom areaconst banios habitaciones
##    <dbl> <chr>   <dbl>     <dbl>  <dbl>        <dbl>
##  1   243 Casa      190       435      0            0
##  2  2013 Casa      270       330      3            0
##  3  2014 Casa      270       330      3            0
##  4  2741 Casa      485       320      4            0
##  5  3273 Casa      400       324      0            0
##  6  4095 Casa      700       550      6            0
##  7  4118 Casa      620       450      3            0
##  8  4329 Casa      790       540      6            0
##  9  4512 Casa      620       300      8            0
## 10  7245 Casa     1200       752      0            0
## # ℹ 56 more rows

La inspección de los registros con valores iguales a cero permitió identificar situaciones poco habituales, como viviendas de áreas considerables registradas sin baños ni habitaciones, propiedades con habitaciones pero sin baños y propiedades con baños pero sin habitaciones. Aunque estas configuraciones son posibles, no representan características comunes en viviendas residenciales. Por esta razón, los valores se consideran potencialmente inconsistentes y se tendrán en cuenta durante la preparación de los datos para los análisis posteriores, sin asumir de manera inmediata que corresponden a errores de registro.

Diagramas de cajas y bigotes para variables Precio, habitaciones, baños, area construida y parqueaderos

par(mfrow = c(2, 3))

boxplot(vivienda_limpia$preciom,
        main = "Precio",
        ylab = "Millones de pesos")

boxplot(vivienda_limpia$areaconst,
        main = "Área construida",
        ylab = "Metros cuadrados")

boxplot(vivienda_limpia$parqueaderos,
        main = "Parqueaderos",
        ylab = "Cantidad")

boxplot(vivienda_limpia$banios,
        main = "Baños",
        ylab = "Cantidad")

boxplot(vivienda_limpia$habitaciones,
        main = "Habitaciones",
        ylab = "Cantidad")

par(mfrow = c(1, 1))

Los diagramas de caja evidencian la presencia de valores atípicos en las variables precio, área construida, parqueaderos, baños y habitaciones. No obstante, estos valores pueden corresponder a propiedades con características particulares dentro del mercado inmobiliario, por lo que no necesariamente representan errores y se mantienen en la base de datos. En el caso de baños y habitaciones, se mantienen las posibles inconsistencias identificadas previamente en los registros con valores iguales a cero.

1.4 Revisión de digitación y consistencia de los datos

En primer lugar, se revisan las variables zona, tipo, piso y estrato mediante la función unique(), con el fin de identificar los valores únicos presentes en cada una de sus categorías y detectar posibles inconsistencias en su digitación. Posteriormente, se analizará de manera independiente la variable barrio, debido a que presenta una mayor cantidad de valores únicos y requiere una revisión más detallada.

unique(vivienda_limpia$zona)
## [1] "Zona Oriente" "Zona Sur"     "Zona Norte"   "Zona Oeste"   "Zona Centro"
unique(vivienda_limpia$tipo)
## [1] "Casa"        "Apartamento"
unique(vivienda_limpia$piso)
##  [1] NA   "02" "01" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12"
unique(vivienda_limpia$estrato)
## [1] 3 4 5 6
length(unique(vivienda_limpia$barrio))
## [1] 436

El resultado anterior indica que la variable barrio presenta 436 valores únicos. Sin embargo, es importante considerar que algunos de estos valores pueden corresponder al mismo barrio, pero estar registrados con diferencias en el uso de mayúsculas y minúsculas o con espacios adicionales. R interpreta estas diferencias de escritura como categorías distintas, lo que podría generar una sobreestimación del número real de barrios. Por esta razón, se realiza una estandarización temporal mediante las funciones para arreglar mayusculas y minusculas (tolower) y espacios (trimws), con el fin de eliminar las diferencias asociadas al uso de mayúsculas y minúsculas y a la presencia de espacios innecesarios, respectivamente.

length(unique(tolower(trimws(vivienda_limpia$barrio))))
## [1] 407
barrios_originales <- unique(vivienda_limpia$barrio)

barrios_normalizados <- tolower(trimws(barrios_originales))

duplicados_barrio <- barrios_originales[
  duplicated(barrios_normalizados) |
  duplicated(barrios_normalizados, fromLast = TRUE)
]

sort(duplicados_barrio)
##  [1] "belalcazar"         "Belalcazar"         "brisas de los"     
##  [4] "Brisas De Los"      "camino real"        "Camino Real"       
##  [7] "centenario"         "Centenario"         "chiminangos"       
## [10] "Chiminangos"        "ciudad 2000"        "Ciudad 2000"       
## [13] "ciudad jardín"      "Ciudad Jardín"      "ciudad pacifica"   
## [16] "Ciudad Pacifica"    "colseguros andes"   "Colseguros Andes"  
## [19] "el bosque"          "El Bosque"          "el caney"          
## [22] "El Caney"           "el ingenio"         "El Ingenio"        
## [25] "la flora"           "La Flora"           "la hacienda"       
## [28] "La Hacienda"        "los guaduales"      "Los Guaduales"     
## [31] "miraflores"         "Miraflores"         "pance"             
## [34] "Pance"              "prados del limonar" "Prados Del Limonar"
## [37] "prados del norte"   "Prados Del Norte"   "quintas de don"    
## [40] "Quintas De Don"     "san fernando"       "San Fernando"      
## [43] "santa anita"        "Santa Anita"        "santa isabel"      
## [46] "Santa Isabel"       "santa monica"       "Santa Monica"      
## [49] "santa teresita"     "Santa Teresita"     "santo domingo"     
## [52] "Santo Domingo"      "valle del lili"     "Valle Del Lili"    
## [55] "villa del prado"    "Villa Del Prado"    "villas de veracruz"
## [58] "Villas De Veracruz"

Los resultados anteriores indican que, al estandarizar la escritura de los nombres, la variable barrio presenta realmente 407 categorías únicas, en comparación con las 436 identificadas inicialmente. Adicionalmente, se obtuvo el listado de los valores duplicados, evidenciando que las diferencias entre estos registros se deben al uso de mayúsculas y minúsculas. Por lo tanto, se considera pertinente estandarizar la variable barrio para evitar que un mismo barrio sea interpretado como categorías diferentes.Por lo anterior, se procede a convertir los registros de la variable barrio a minúsculas, con el propósito de estandarizar la información y evitar que un mismo barrio sea considerado como categorías diferentes debido únicamente al uso de mayúsculas y minúsculas.

vivienda_limpia$barrio <- tolower(trimws(vivienda_limpia$barrio))
length(unique(vivienda_limpia$barrio))
## [1] 407

Finalmente, se realiza la misma comprobación teniendo en cuenta el uso de tildes. Es posible que algunos registros correspondan al mismo barrio, pero sean reconocidos por R como categorías diferentes debido a la presencia o ausencia de tildes en su digitación. Por esta razón, se verifica si estas diferencias están generando categorías duplicadas dentro de la variable barrio.

barrios_sin_tilde <- iconv(
  vivienda_limpia$barrio,
  from = "UTF-8",  #indica que el texto de entrada esta escrito en caracteres especiales
  to = "ASCII//TRANSLIT")   #indica que el texto de salida sea su equivalente sin signos especiales

length(unique(barrios_sin_tilde))
## [1] 389
barrios_actuales <- unique(vivienda_limpia$barrio)

barrios_sin_tilde_unicos <- iconv(
  barrios_actuales,
  from = "UTF-8",
  to = "ASCII//TRANSLIT"
)

duplicados_tilde <- barrios_actuales[
  duplicated(barrios_sin_tilde_unicos) |
  duplicated(barrios_sin_tilde_unicos, fromLast = TRUE)
]


sort(duplicados_tilde)
##  [1] "alameda del rio"          "alameda del río"         
##  [3] "alfonso lopez"            "alfonso lópez"           
##  [5] "ciudad cordoba"           "ciudad córdoba"          
##  [7] "ciudad jardin"            "ciudad jardín"           
##  [9] "ciudad los alamos"        "ciudad los álamos"       
## [11] "cristobal colón"          "cristóbal colón"         
## [13] "junin"                    "junín"                   
## [15] "los alcazares"            "los alcázares"           
## [17] "los cambulos"             "los cámbulos"            
## [19] "napoles"                  "nápoles"                 
## [21] "normandia"                "normandía"               
## [23] "pacara"                   "pacará"                  
## [25] "san joaquin"              "san joaquín"             
## [27] "san luis"                 "san luís"                
## [29] "san nicolas"              "san nicolás"             
## [31] "santa monica"             "santa mónica"            
## [33] "santa monica popular"     "santa mónica popular"    
## [35] "santa monica residencial" "santa mónica residencial"

Adicionalmente, se revisaron posibles diferencias asociadas al uso de tildes en los nombres de los barrios. Al realizar esta comparación, el número de categorías únicas disminuyó de 407 a 389, evidenciando la existencia de registros correspondientes al mismo barrio escritos con y sin tilde. Por lo tanto, estas diferencias también generan categorías duplicadas y requieren ser estandarizadas

Debido a que las diferencias en el uso de tildes generan categorías duplicadas dentro de la variable barrio, se decide estandarizar los nombres eliminando las tildes. Esta decisión permite reducir inconsistencias asociadas a la digitación y facilita la comparación de los registros, dado que en procesos de captura manual es común que las tildes no sean utilizadas de manera uniforme.

vivienda_limpia$barrio <- iconv(     #modificamos los registros de la variable barrio en la base limpia
  vivienda_limpia$barrio,
  from = "UTF-8",
  to = "ASCII//TRANSLIT"
)

length(unique(vivienda_limpia$barrio))
## [1] 389

Finalmente, luego de realizar esta última modificación, la variable barrio queda conformada por 389 categorías únicas, obteniendo así una mayor estandarización y consistencia en su información.

1.5 Preparación de los datos para el análisis multivariado

Una vez realizada la exploración y limpieza general de la base de datos, se procede a preparar la información que será utilizada en los diferentes análisis multivariados. Debido a que cada técnica requiere variables con características específicas, se definirán los conjuntos de variables correspondientes para el Análisis de Componentes Principales, el Análisis de Conglomerados y el Análisis de Correspondencia.

1.5.1 Preparación de los datos para el PCA

Para la aplicación del Análisis de Componentes Principales se seleccionan las variables cuantitativas precio, área construida, número de baños, parqueaderos y habitaciones, debido a que representan características económicas y físicas de las propiedades y permiten analizar las relaciones existentes entre ellas.

Creamos entonces nuestro vector de datos para pca, con las variables.

datos_pca <- vivienda_limpia[, c(
  "preciom",
  "areaconst",
  "banios",
  "parqueaderos",
  "habitaciones"
)]

Como se analizo anteriormente, la variable parqueaderos presenta un total de 1602 valores faltantes. Al observar su distribución, se evidencia que el 50 % de los registros se encuentra entre 1 y 2 parqueaderos. Adicionalmente, la media (1.835) y la mediana (2) presentan valores cercanos. Sin embargo, debido a que parqueaderos es una variable cuantitativa discreta, resulta conveniente considerar valores enteros para su imputación.

table(datos_pca$parqueaderos, useNA = "ifany")  #incluye los NA
## 
##    1    2    3    4    5    6    7    8    9   10 <NA> 
## 3155 2475  520  384   68   68   18   17    4    8 1602
summary(datos_pca$parqueaderos)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.000   1.000   2.000   1.835   2.000  10.000    1602

Aunque la mediana general de la variable es 2, se realiza una comprobación adicional de esta medida según el tipo de vivienda, con el propósito de determinar si existen diferencias entre casas y apartamentos.

tapply(
  vivienda_limpia$parqueaderos,
  vivienda_limpia$tipo,
  median,
  na.rm = TRUE
)
## Apartamento        Casa 
##           1           2

Los resultados muestran que la mediana del número de parqueaderos es 1 para los apartamentos y 2 para las casas. Por consiguiente, se considera más adecuado realizar la imputación de manera diferenciada según el tipo de vivienda, asignando la mediana correspondiente a cada categoría.

datos_pca$parqueaderos[
  is.na(datos_pca$parqueaderos) &
  vivienda_limpia$tipo == "Apartamento" #imputacion para apartamento con mediana 1
] <- 1

datos_pca$parqueaderos[
  is.na(datos_pca$parqueaderos) &
  vivienda_limpia$tipo == "Casa"    # imnputacion para casa con mediana 2
] <- 2
sum(is.na(datos_pca$parqueaderos))    #verificamos los faltantes de nuevo
## [1] 0

1.5.2 Preparación de los datos para el análisis de conglomerados

Para el análisis de conglomerados se seleccionan inicialmente las variables cuantitativas precio, área construida, número de baños, parqueaderos y habitaciones, con el propósito de agrupar las viviendas según características económicas y físicas similares. Posteriormente, los grupos obtenidos serán analizados según las variables zona y estrato, con el fin de identificar cómo se distribuyen los diferentes segmentos en la ciudad y entre los niveles socioeconómicos.

colSums(is.na(vivienda_limpia[, c(
  "preciom",
  "areaconst",
  "banios",
  "parqueaderos",
  "habitaciones"
)]))
##      preciom    areaconst       banios parqueaderos habitaciones 
##            0            0            0         1602            0

Al verificar los datos faltantes de las variables seleccionadas, se observa nuevamente la presencia de valores faltantes en la variable parqueaderos. Con el fin de mantener un tratamiento homogéneo de los datos, se aplicará el mismo criterio utilizado previamente para el PCA, imputando los valores faltantes mediante la mediana de parqueaderos según el tipo de vivienda.

datos_cluster <- vivienda_limpia[, c(
  "id",
  "zona",
  "estrato",
  "preciom",
  "areaconst",
  "banios",
  "parqueaderos",
  "habitaciones",
  "tipo"
)]
datos_cluster$parqueaderos[
  is.na(datos_cluster$parqueaderos) &
  datos_cluster$tipo == "Apartamento"
] <- 1

datos_cluster$parqueaderos[
  is.na(datos_cluster$parqueaderos) &
  datos_cluster$tipo == "Casa"
] <- 2
colSums(is.na(datos_cluster))
##           id         zona      estrato      preciom    areaconst       banios 
##            0            0            0            0            0            0 
## parqueaderos habitaciones         tipo 
##            0            0            0

####analisis datos con 0 habitaciones y 0 baños

Debido a que las variables habitaciones y baños serán incluidas en el análisis de conglomerados, y durante la exploración inicial de los datos se identificaron algunos valores que llamaron la atención, se realiza una revisión antes de continuar con el análisis. A continuación, se presentan los registros que tienen 0 habitaciones y aquellos que tienen 0 baños, con el fin de verificar estos casos y determinar su tratamiento.

# Viviendas con 0 habitaciones
datos_cluster[datos_cluster$habitaciones == 0, ]
## # A tibble: 66 × 9
##       id zona   estrato preciom areaconst banios parqueaderos habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>  <dbl>        <dbl>        <dbl> <chr>
##  1   243 Zona …       3     190       435      0            2            0 Casa 
##  2  2013 Zona …       3     270       330      3            2            0 Casa 
##  3  2014 Zona …       3     270       330      3            2            0 Casa 
##  4  2741 Zona …       4     485       320      4            2            0 Casa 
##  5  3273 Zona …       3     400       324      0            2            0 Casa 
##  6  4095 Zona …       4     700       550      6            2            0 Casa 
##  7  4118 Zona …       5     620       450      3            2            0 Casa 
##  8  4329 Zona …       4     790       540      6            2            0 Casa 
##  9  4512 Zona …       4     620       300      8            2            0 Casa 
## 10  7245 Zona …       4    1200       752      0            2            0 Casa 
## # ℹ 56 more rows
# Viviendas con 0 baños
datos_cluster[datos_cluster$banios == 0, ]
## # A tibble: 45 × 9
##       id zona   estrato preciom areaconst banios parqueaderos habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>  <dbl>        <dbl>        <dbl> <chr>
##  1   243 Zona …       3     190       435      0            2            0 Casa 
##  2  3273 Zona …       3     400       324      0            2            0 Casa 
##  3  7245 Zona …       4    1200       752      0            2            0 Casa 
##  4  4995 Zona …       3     420       235      0            2            0 Casa 
##  5  1816 Zona …       3     750       183      0            2            0 Casa 
##  6  7509 Zona …       5    1200       660      0            2            0 Casa 
##  7  6839 Zona …       6     900       250      0            2            0 Apar…
##  8  4393 Zona …       3     380       264      0            2            0 Casa 
##  9  1898 Zona …       4     220        68      0            1            3 Apar…
## 10  1425 Zona …       5     395       220      0            1            0 Casa 
## # ℹ 35 more rows
sum(datos_cluster$habitaciones == 0)
## [1] 66
sum(datos_cluster$banios == 0)
## [1] 45
sum(
  datos_cluster$habitaciones == 0 &
  datos_cluster$banios == 0
)
## [1] 35
# Total de registros a excluir
sum(
  datos_cluster$habitaciones == 0 |
  datos_cluster$banios == 0
)
## [1] 76

Como resultado de la revisión, se identificaron 66 registros con 0 habitaciones y 45 con 0 baños, de los cuales 35 presentan simultáneamente ambos valores en cero. Teniendo en cuenta que se están analizando viviendas, independientemente de si corresponden a Casas o Apartamentos, no resulta coherente considerar como válidos registros que indiquen ausencia de habitaciones o baños. Además, al revisar sus demás características se observaron casos con áreas construidas y precios elevados, lo que sugiere que estos valores podrían corresponder a información no registrada.Al cruzar ambos grupos se obtiene un total de 76 registros únicos con 0 habitaciones, 0 baños o ambas condiciones. Debido a que no se cuenta con información adicional que permita completar estos valores, se decide excluir estos 76 registúnicamente del análisis de conglomerados, evitando que estas posibles inconsistencias influyan en la formación de los grupos.

# Eliminamos los 76 registros de la base para conglomerados
datos_cluster <- datos_cluster[
  datos_cluster$habitaciones > 0 & datos_cluster$banios > 0,
]
# Verificar que no queden registros con valores en cero para hab y banos
sum(datos_cluster$habitaciones == 0)
## [1] 0
sum(datos_cluster$banios == 0)
## [1] 0
sum(
  datos_cluster$habitaciones == 0 &
  datos_cluster$banios == 0
)
## [1] 0

Con la base de datos para conglomerados ya revisada y preparada, se continúa en la Sección 3 con el análisis de conglomerados, donde se buscará identificar grupos de viviendas que compartan características similares.

1.5.3 Preparación de los datos para el análisis de correspondencia

Para el análisis de correspondencias se seleccionan las variables tipo de vivienda, zona y barrio, de acuerdo con el objetivo de identificar posibles relaciones entre estas características y reconocer patrones en la oferta del mercado inmobiliario. Como primer paso, se revisa la presencia de datos faltantes y la cantidad de categorías presentes en cada variable.

datos_corresp <- vivienda_limpia[, c(
  "tipo",
  "zona",
  "barrio"
)]
str(datos_corresp)
## spc_tbl_ [8,319 × 3] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ tipo  : chr [1:8319] "Casa" "Casa" "Casa" "Casa" ...
##  $ zona  : chr [1:8319] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ barrio: chr [1:8319] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  - attr(*, "spec")=List of 3
##   ..$ cols   :List of 13
##   .. ..$ id          : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ zona        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ piso        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ estrato     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ preciom     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ areaconst   : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ parqueaderos: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ banios      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ habitaciones: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ tipo        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ barrio      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ longitud    : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ latitud     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   ..$ default: list()
##   .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
##   ..$ delim  : chr ";"
##   ..- attr(*, "class")= chr "col_spec"
##  - attr(*, "problems")=<externalptr>
colSums(is.na(datos_corresp))
##   tipo   zona barrio 
##      0      0      0
length(unique(datos_corresp$tipo))
## [1] 2
length(unique(datos_corresp$zona))
## [1] 5
length(unique(datos_corresp$barrio))
## [1] 389

Como se observa, las variables seleccionadas no presentan datos faltantes. Adicionalmente, se identifican 2 categorías para el tipo de vivienda, 5 para la zona y 389 para el barrio. Cabe mencionar que la variable barrio fue previamente depurada durante la etapa de limpieza de los datos, donde se corrigieron errores de digitación y se unificaron los nombres correspondientes a una misma categoría. Por lo tanto, no se requiere realizar tratamientos adicionales sobre estas variables antes de continuar con el análisis de correspondencias.

2. Análisis de Componentes Principales

2.1 Matriz de correlaciones

Como primer paso, se obtiene la matriz de correlaciones con el fin de evaluar el grado de relación existente entre las variables seleccionadas para el ACP. Este análisis permite identificar si las variables comparten información y verificar la existencia de correlaciones muy altas que puedan indicar una posible redundancia entre ellas.

cor(datos_pca)
##                preciom areaconst    banios parqueaderos habitaciones
## preciom      1.0000000 0.6873520 0.6691456    0.6681768    0.2640912
## areaconst    0.6873520 1.0000000 0.6484165    0.5735257    0.5169129
## banios       0.6691456 0.6484165 1.0000000    0.5504887    0.5899064
## parqueaderos 0.6681768 0.5735257 0.5504887    1.0000000    0.2902056
## habitaciones 0.2640912 0.5169129 0.5899064    0.2902056    1.0000000

al analizar la matriz de correlaciones, se observa que la mayoría de las variables presentan relaciones positivas moderadas entre sí. Las relaciones más altas se presentan entre el precio y el área construida (0.69), el precio y los baños (0.67) y el precio y los parqueaderos (0.67), lo cual indica que, en general, las viviendas de mayor tamaño y con mayor número de baños o parqueaderos tienden a presentar precios más altos. Por otra parte, la variable habitaciones presenta relaciones más bajas con el precio (0.26) y con el número de parqueaderos (0.29).En general, no se observan correlaciones excesivamente altas entre las variables, por lo que no se evidencia una posible redundancia entre ellas. A su vez, la presencia de varias correlaciones moderadas sugiere que existe información compartida entre las variables que puede ser analizada mediante el PCA. Sin embargo, como se planteó durante la exploración inicial de los datos, se identificaron algunos registros con valores de cero en las variables habitaciones y baños que resultaban poco habituales dadas las demás características de las propiedades. Por esta razón, se realiza una comprobación adicional para determinar si estos registros están afectando las correlaciones observadas con el precio.

# Correlación utilizando todos los registros
cor(
  datos_pca$preciom,
  datos_pca$habitaciones
)
## [1] 0.2640912
# Correlación excluyendo viviendas con 0 habitaciones
cor(
  datos_pca$preciom[datos_pca$habitaciones > 0],
  datos_pca$habitaciones[datos_pca$habitaciones > 0]
)
## [1] 0.2753258
# Correlación utilizando todos los registros
cor(
  datos_pca$preciom,
  datos_pca$banios
)
## [1] 0.6691456
# Correlación excluyendo viviendas con 0 banos
cor(
  datos_pca$preciom[datos_pca$banios > 0],
  datos_pca$banios[datos_pca$banios > 0]
)
## [1] 0.6843816

Al excluir temporalmente los registros con cero habitaciones, la correlación entre el número de habitaciones y el precio pasa de 0.264 a 0.275, mientras que al excluir los registros con cero baños, la correlación entre baños y precio pasa de 0.669 a 0.684. En ambos casos los cambios son pequeños, por lo que no se evidencia que estos registros estén afectando de manera importante las relaciones observadas. Por esta razón, se mantienen estas observaciones para el desarrollo del PCA.

2.2 Estandarizacion de las variables y aplicacion del PCA

Debido a que las variables seleccionadas se encuentran expresadas en diferentes unidades y escalas de medición, se realiza su estandarización antes de aplicar el PCA. De esta manera, se evita que variables con escalas mayores, como el precio o el área construida, tengan una influencia desproporcionada en la construcción de los componentes.

datos_pca_est <- scale(datos_pca)
summary(datos_pca_est)
##     preciom          areaconst           banios          parqueaderos    
##  Min.   :-1.1437   Min.   :-1.0138   Min.   :-2.17847   Min.   :-0.7298  
##  1st Qu.:-0.6508   1st Qu.:-0.6640   1st Qu.:-0.77811   1st Qu.:-0.7298  
##  Median :-0.3161   Median :-0.3633   Median :-0.07794   Median : 0.2273  
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.00000   Mean   : 0.0000  
##  3rd Qu.: 0.3228   3rd Qu.: 0.3782   3rd Qu.: 0.62224   3rd Qu.: 0.2273  
##  Max.   : 4.7620   Max.   :10.9822   Max.   : 4.82330   Max.   : 7.8840  
##   habitaciones    
##  Min.   :-2.4702  
##  1st Qu.:-0.4148  
##  Median :-0.4148  
##  Mean   : 0.0000  
##  3rd Qu.: 0.2704  
##  Max.   : 4.3813

Teniendo las variables estandarizadas y comprobando que este proceso se hizo de manera correcta (observamos la media 0 para todas las variables), proseguimos con el análisis de componentes principales.

pca <- prcomp(datos_pca_est)
pca$sdev
## [1] 1.7931121 0.9233378 0.6273765 0.5883659 0.4386577
pca$rotation
##                    PC1         PC2        PC3         PC4        PC5
## preciom      0.4688065  0.41321908 -0.3637543  0.15897694  0.6722199
## areaconst    0.4820725 -0.02337263 -0.3790299 -0.70227094 -0.3608485
## banios       0.4846358 -0.17272048 -0.1745056  0.68327354 -0.4878328
## parqueaderos 0.4330403  0.41806734  0.7860627 -0.08223573 -0.1141863
## habitaciones 0.3541620 -0.78999434  0.2750862 -0.08897429  0.4085210

Al analizar las cargas de las variables sobre los componentes principales, resulta interesante observar que en el primer componente (PC1) todas las cargas son positivas. Las mayores corresponden al área construida (0.482), baños (0.485) y precio (0.469), seguidas por parqueaderos (0.433) y habitaciones (0.354). Esto indica que todas las variables se relacionan en la misma dirección con este componente, por lo que PC1 parece representar una característica general asociada con el tamaño y las características de la vivienda. Para el segundo componente (PC2), las mayores cargas en valor absoluto corresponden a habitaciones (-0.790), parqueaderos (0.418) y precio (0.413). En este caso, habitaciones presenta un signo contrario al de precio y parqueaderos, indicando que estas variables se relacionan con el componente en direcciones opuestas.Finalmente, en el tercer componente (PC3) se destaca principalmente la variable parqueaderos (0.786), mientras que precio (-0.368) y área construida (-0.379) presentan cargas de menor magnitud y en dirección contraria.

Para determinar el número de componentes principales a conservar, se utiliza el gráfico de varianza explicada por componente. Como criterio para este análisis, se busca conservar el número mínimo de componentes que permita explicar al menos el 80 % de la variabilidad total de los datos.

library(factoextra)

fviz_eig(
  pca,
  addlabels = TRUE
)

Se observa que el primer componente explica el 64.3 % de la variabilidad y el segundo el 17.1 %. En conjunto, los dos primeros componentes explican aproximadamente el 81,4 % de la variabilidad total. Por lo tanto, de acuerdo con el criterio establecido, se decide conservar dos componentes principales.

2.3 Circulo de correlaciones del PCA

Con el fin de visualizar la relación de las variables originales con los dos componentes principales seleccionados, se construye el círculo de correlaciones. Este gráfico permite observar la dirección y la intensidad con la que cada variable se relaciona con los componentes PC1 y PC2.

fviz_pca_var(
  pca,
  axes = c(1, 2),
  repel = TRUE,
  col.var = "contrib",
  gradient.cols = c("blue", "orange", "red")
)

Al analizar el círculo de correlaciones, se observa que para la dimensión 1 (PC1) todas las variables presentan una relación positiva. La variable habitaciones presenta la menor carga sobre esta dimensión, mientras que precio, área construida, baños y parqueaderos presentan cargas relativamente similares. Esto indica que el primer componente recoge información compartida por las diferentes características de las viviendas. Para la dimensión 2 (PC2) se presenta un comportamiento diferente. Precio y parqueaderos tienen una relación positiva con esta dimensión, mientras que área construida, baños y habitaciones presentan una relación negativa. En particular, habitaciones es la variable con mayor peso en valor absoluto sobre PC2, por lo que desempeña un papel importante en la definición de este segundo componente.

En cuanto a la relación entre las variables, precio y parqueaderos presentan direcciones muy similares, lo que evidencia una asociación positiva entre ellas. De igual manera, área construida y baños se encuentran relativamente próximas. Por otra parte, la flecha correspondiente a habitaciones forma un ángulo cercano a 90° con precio y parqueaderos, lo que indica una relación débil entre estas variables. Este resultado es coherente con la matriz de correlaciones analizada previamente, donde habitaciones presentó correlaciones de apenas 0.26 con precio y 0.29 con parqueaderos.finalmente, se observa que habitaciones presenta una de las flechas más cercanas al borde del círculo, indicando que esta variable se encuentra muy bien representada en el plano formado por PC1 y PC2. En otras palabras, una parte importante de la información contenida en la variable habitaciones puede ser explicada mediante los dos componentes principales seleccionados.

2.4 Biplot

En el biplot se observa que una gran cantidad de viviendas se concentra cerca del centro del gráfico. Esto indica que muchas de las propiedades presentan características similares a los valores habituales del conjunto de datos en cuanto a precio, área construida, baños, parqueaderos y habitaciones. Sin embargo, también se observan algunas viviendas más alejadas de esta concentración, especialmente hacia la derecha, lo que indica que presentan características diferentes al comportamiento de la mayoría. Además, la distribución de las viviendas se extiende principalmente sobre el primer componente, lo cual es coherente con el hecho de que este componente concentra la mayor parte de la información de los datos (64.3 %).

fviz_pca_biplot(
  pca,
  axes = c(1, 2),
  label = "var",
  col.ind = "grey",
  col.var = "red",
  repel = TRUE
)

2.5 Análisis de individuos

Finalmente, tal como se observó en la sección teórica del curso, se realiza el análisis de los individuos con el propósito de interpretar el sentido de los dos componentes principales. Para ello, se seleccionan cuatro viviendas ubicadas en los extremos positivo y negativo de cada componente y se comparan sus características originales. Con el código presentado a continuación se identifican las viviendas ubicadas en los extremos de cada componente, es decir, aquellas que presentan los valores máximo y mínimo en PC1 y PC2.

# Casos extremos

which.max(pca$x[,1]) # PC1 positivo
## [1] 1762
which.min(pca$x[,1]) # PC1 negativo
## [1] 3108
which.max(pca$x[,2]) # PC2 positivo
## [1] 2926
which.min(pca$x[,2]) # PC2 negativo
## [1] 8199

Una vez identificadas las cuatro viviendas ubicadas en los extremos, se consultan sus características originales en términos de precio, área construida, número de baños, parqueaderos y habitaciones, con el propósito de comprender las diferencias entre ellas y, de esta manera, facilitar la interpretación de cada componente. Las viviendas 1762 y 3108 representan los extremos positivo y negativo de PC1, respectivamente, mientras que las viviendas 2926 y 8199 corresponden a los extremos positivo y negativo de PC2.

datos <- rbind(
  datos_pca[1762, ],
  datos_pca[3108, ],
  datos_pca[2926, ],
  datos_pca[8199, ]
)

datos <- as.data.frame(datos)

rownames(datos) <- c(
  "Vivienda 1762",
  "Vivienda 3108",
  "Vivienda 2926",
  "Vivienda 8199"
)

datos
##               preciom areaconst banios parqueaderos habitaciones
## Vivienda 1762    1800      1586      4           10            5
## Vivienda 3108     160        76      0            1            0
## Vivienda 2926     950       280      0           10            0
## Vivienda 8199     680       452     10            1           10

Una vez identificadas las viviendas extremas de cada componente, se procede a ubicarlas en el gráfico de individuos. Los extremos correspondientes a PC1 se resaltan en color rojo, mientras que los extremos de PC2 se presentan en color azul, con el fin de facilitar su identificación y posterior interpretación.

# Casos extremos del PC1
casos1 <- rbind(
  pca$x[1762, 1:2],
  pca$x[3108, 1:2]
)

rownames(casos1) <- c("1762", "3108")
casos1 <- as.data.frame(casos1)


# Casos extremos del PC2
casos2 <- rbind(
  pca$x[2926, 1:2],
  pca$x[8199, 1:2]
)

rownames(casos2) <- c("2926", "8199")
casos2 <- as.data.frame(casos2)
fviz_pca_ind(
  pca,
  col.ind = "#DEDEDE"
) +
  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
  )

Con respecto al PC1, se observa que a medida que nos desplazamos hacia la derecha, es decir, hacia valores positivos del componente, las características de las viviendas tienden a aumentar. En el caso extremo analizado, se presenta un mayor precio, mayor área construida y un mayor número de baños, parqueaderos y habitaciones. Este comportamiento es coherente con lo observado en el círculo de correlaciones, donde todas las variables presentaron cargas positivas sobre el primer componente. Para el PC2, el comportamiento es diferente. Al desplazarnos desde la parte negativa hacia la positiva del componente, se observa un aumento en el precio y en el número de parqueaderos, mientras que disminuyen el área construida, el número de baños y, especialmente, el número de habitaciones. Este comportamiento también coincide con las cargas observadas anteriormente para el segundo componente.

Al observar los dos componentes en conjunto, se pueden identificar diferentes comportamientos entre las viviendas. Hacia la parte superior derecha se encuentran viviendas asociadas con mayores precios y un mayor número de parqueaderos, mientras que hacia la parte inferior se encuentran viviendas donde características como el número de habitaciones y baños tienen mayor importancia. Esto permite observar que las viviendas pueden diferenciarse no solo por su precio, sino también por la combinación de sus características.En conclusión, el Análisis de Componentes Principales permitió resumir las cinco características estudiadas de las viviendas en dos componentes que explican en conjunto el 81,4 % de la información. El primer componente permite diferenciar viviendas con características generales más altas o más bajas, mientras que el segundo permite observar distintas combinaciones entre estas características. Adicionalmente, se evidenció que el precio presenta una mayor relación con el área construida, el número de baños y los parqueaderos, mientras que su relación con el número de habitaciones es considerablemente menor. De esta manera, el ACP permite identificar características relevantes asociadas con las diferencias de precio y con los distintos perfiles de viviendas presentes en la oferta inmobiliaria analizada.

3. Análisis de Conglomerados

Para realizar el análisis de conglomerados se seleccionaron las variables precio, área construida, habitaciones, baños y parqueaderos, ya que representan algunas de las principales características de las viviendas y permiten compararlas entre sí. Debido a que estas variables se encuentran en escalas diferentes, antes de formar los grupos es necesario estandarizarlas, de manera que ninguna tenga mayor influencia en el análisis únicamente por manejar valores más altos.

# Seleccionar variables para el análisis de conglomerados
variables_cluster <- datos_cluster[, c(
  "preciom",
  "areaconst",
  "habitaciones",
  "banios",
  "parqueaderos"
)]

# Estandarizar las variables
variables_cluster_est <- scale(variables_cluster)

Una vez estandarizadas las variables, se calculan las distancias euclidianas entre las viviendas. Estas distancias permiten conocer qué tan similares son las viviendas considerando conjuntamente el precio, área construida, habitaciones, baños y parqueaderos. Una distancia menor indica una mayor similitud entre las viviendas, mientras que una distancia mayor indica mayores diferencias entre sus características

# Comprobar media, debe dar aprox 0
colMeans(variables_cluster_est)
##       preciom     areaconst  habitaciones        banios  parqueaderos 
## -3.074520e-17  8.842607e-17 -1.756315e-17 -3.241574e-17  3.790086e-17
# Comprobar desviaciones estándar, debe dar 1
apply(variables_cluster_est, 2, sd)
##      preciom    areaconst habitaciones       banios parqueaderos 
##            1            1            1            1            1
# Distancias euclidianas
dist_euclidiana <- dist(
  variables_cluster_est,
  method = "euclidean"
)
summary(dist_euclidiana)  #utilizamos este chunck para verificar que el calculo de las distancias se realizo 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   1.304   2.182   2.616   3.543  15.208

Una vez calculadas las distancias euclidianas, se continúa con la construcción del dendrograma, utilizando el método de agrupamiento complete. Este gráfico permitirá observar cómo se van agrupando las viviendas según la similitud de sus características y servirá como apoyo para determinar una posible cantidad de conglomerados. Debido al gran número de viviendas analizadas, no se presenta la matriz completa de distancias, ya que su tamaño dificultaría su visualización e interpretación.

# Clúster jerárquico
hc_cluster <- hclust(
  dist_euclidiana,
  method = "complete"
)
plot(
  hc_cluster,
  labels = FALSE,
  hang = -1,
  main = "Dendrograma de las viviendas",
  xlab = "Viviendas",
  ylab = "Distancia"
)

Debido a la cantidad de viviendas, en el dendrograma no es fácil identificar a simple vista cuántos grupos sería conveniente formar. Por esta razón, se utilizan otros gráficos como apoyo. Primero se presenta el método del codo, que permite observar a partir de qué cantidad de grupos las mejoras empiezan a ser menores. También se utiliza el gráfico de agregaciones, en el cual se muestran únicamente las 10 últimas uniones. Se toman estas últimas porque al comienzo se unen las viviendas más parecidas, mientras que al final se van uniendo grupos cada vez más diferentes. Esto permite observar con mayor claridad si hay saltos grandes en las distancias y tener una mejor idea de dónde podría hacerse la separación de los conglomerados.

tail(hc_cluster$height, 10)
##  [1]  7.741699  7.855802  8.061207  9.169762  9.803005 10.261890 10.328276
##  [8] 11.120425 12.618686 15.207713
# Últimas distancias de agregación
ultimas_distancias <- tail(hc_cluster$height, 10)

barplot(
  ultimas_distancias,
  horiz = TRUE,
  names.arg = 10:1,
  xlab = "Distancia",
  ylab = "Nodo",
  main = "Grafico de aglomeracion",
  col="lightsteelblue"
)

# Método del codo
wss <- numeric(10)

for (k in 1:10) {
  modelo <- kmeans(
    variables_cluster_est,
    centers = k,
    nstart = 25
  )
  
  wss[k] <- modelo$tot.withinss
}

plot(
  1:10,
  wss,
  type = "b",
  pch = 19,
  xlab = "Número de conglomerados",
  ylab = "Suma de cuadrados dentro de los grupos",
  main = "Método del codo"
)

Al observar ambos gráficos, se tiene una primera idea de la cantidad de conglomerados que podrían formarse. El gráfico de agregaciones sugiere una posible separación entre 3 y 4 grupos, debido a los cambios que se observan en las últimas distancias de unión. Por su parte, en el método del codo se observa una disminución bastante marcada entre 1 y 2 conglomerados, que continúa entre 2 y 3, aunque en menor medida. A partir de 3 conglomerados, las diferencias empiezan a ser más pequeñas y la curva se vuelve más estable. Por esta razón, 3 conglomerados aparece inicialmente como una buena opción.Para comprobar si esta cantidad permite obtener grupos bien definidos, se evaluará a continuación el coeficiente de Silhouette.

library(cluster)

# Guardar los resultados
silhouette_promedio <- numeric(5)

for (k in 2:6) {                 # ciclo desde 2 clusters hasta 6. 
  
  grupos <- cutree(hc_cluster, k = k)
  
  sil <- silhouette(
    grupos,
    dist_euclidiana
  )
  
  silhouette_promedio[k - 1] <- mean(sil[, 3])
}

silhouette_promedio
## [1] 0.7452525 0.4955921 0.4753889 0.4751717 0.4728740
##   conglomerados silhouette
## 1             2  0.7452525
## 2             3  0.4955921
## 3             4  0.4753889
## 4             5  0.4751717
## 5             6  0.4728740

Al comparar el coeficiente de Silhouette para diferentes cantidades de conglomerados, se observa que el valor más alto se obtiene con 2 grupos (0.745). A partir de 3 conglomerados el valor disminuye considerablemente y se mantiene alrededor de 0.47–0.50. Teniendo en cuenta este resultado y lo observado anteriormente en el método del codo, se seleccionan 2 conglomerados para continuar con el análisis.

Ya teniendo asignados 2 conglomerados, vamos a asignar cada vivienda a uno de esos dos grupos mediante cutree()

# Asignar cada vivienda a uno de los 2 conglomerados
cluster_asignado <- cutree(hc_cluster, k = 2)

# Agregar el conglomerado a la base
datos_cluster$cluster <- as.factor(cluster_asignado)
table(datos_cluster$cluster)
## 
##    1    2 
## 8235    8
# Ver las viviendas del conglomerado 2
datos_cluster[datos_cluster$cluster == 2, ]
## # A tibble: 8 × 10
##      id zona    estrato preciom areaconst banios parqueaderos habitaciones tipo 
##   <dbl> <chr>     <dbl>   <dbl>     <dbl>  <dbl>        <dbl>        <dbl> <chr>
## 1  1017 Zona O…       3     200      1365      1            2            4 Casa 
## 2  5684 Zona S…       6    1800      1586      4           10            5 Casa 
## 3  3324 Zona O…       3     255      1745      3            2            2 Casa 
## 4   315 Zona S…       6    1650      1500      5            4            3 Casa 
## 5  5467 Zona S…       6    1500      1500      5            5            3 Casa 
## 6  5016 Zona S…       6    1500      1250      5            5            3 Casa 
## 7  5396 Zona S…       6    1600      1600      6            3            6 Casa 
## 8   534 Zona N…       3     370      1440      4            1           10 Casa 
## # ℹ 1 more variable: cluster <fct>
# Resumen de las variables por conglomerado
aggregate(
  cbind(preciom, areaconst, habitaciones, banios, parqueaderos) ~ cluster,
  data = datos_cluster,
  FUN = mean
)
##   cluster   preciom areaconst habitaciones   banios parqueaderos
## 1       1  432.6107  172.7487     3.632665 3.126776     1.758834
## 2       2 1109.3750 1498.2500     4.500000 4.125000     4.000000

Al revisar la cantidad de viviendas asignadas a cada conglomerado, se observa un fuerte desbalance: el primer grupo contiene 8235 viviendas, mientras que el segundo está formado únicamente por 8 viviendas. Al revisar este segundo grupo se observa que su principal característica son las áreas construidas considerablemente mayores al resto de la base, aunque sus precios presentan diferencias importantes entre sí. Por esta razón, antes de seleccionar definitivamente dos conglomerados, se revisarán con mayor detalle estos casos.

Revision cluster 2

Al revisar estas viviendas se observa que el segundo conglomerado está compuesto principalmente por casas con áreas construidas muy altas, entre aproximadamente 1250 y 1745 m². Sin embargo, tener un área superior a 1000 m² no determina por sí solo la pertenencia a este grupo, ya que se encontraron viviendas por encima de este valor y varias de ellas permanecen en el conglomerado 1. Esto indica que la separación se está dando por la combinación de las cinco características analizadas y no únicamente por el área construida.

datos_cluster[
  datos_cluster$areaconst > 1000,
  c("preciom", "areaconst", "habitaciones",
    "banios", "parqueaderos", "tipo", "cluster")
]
## # A tibble: 16 × 7
##    preciom areaconst habitaciones banios parqueaderos tipo  cluster
##      <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr> <fct>  
##  1     200      1365            4      1            2 Casa  2      
##  2    1600      1050            6      7            6 Casa  1      
##  3    1680      1040            5      7            3 Casa  1      
##  4    1800      1586            5      4           10 Casa  2      
##  5     650      1188            6      6            4 Casa  1      
##  6    1450      1200            6      6            2 Casa  1      
##  7     255      1745            2      3            2 Casa  2      
##  8    1650      1500            3      5            4 Casa  2      
##  9    1500      1500            3      5            5 Casa  2      
## 10    1800      1090            4      5            6 Casa  1      
## 11    1500      1100            4      5            2 Casa  1      
## 12    1500      1250            3      5            5 Casa  2      
## 13    1900      1092            5      6            5 Casa  1      
## 14    1600      1600            6      6            3 Casa  2      
## 15    1200      1200           10      6            2 Casa  1      
## 16     370      1440           10      4            1 Casa  2

Aun así, el área construida parece tener un papel importante en esta separación. La vivienda típica de la base presenta valores considerablemente menores: la mediana es de 122 m², el 75 % de las viviendas tiene hasta 227 m², mientras que el valor máximo alcanza los 1745 m². Por lo tanto, las viviendas que conforman el segundo conglomerado presentan áreas bastante alejadas de la mayoría de los registros.

summary(datos_cluster$areaconst)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##      30      80     122     174     227    1745

Estos valores no se consideran necesariamente errores, ya que pueden corresponder a viviendas realmente grandes. Sin embargo, su presencia está influyendo en la formación de los conglomerados. Por esta razón, antes de elegir definitivamente la solución de 2 grupos, se revisará cómo cambia la distribución de las viviendas al considerar 3 conglomerados.

Análisis con k=3

# Asignar las viviendas a 3 conglomerados
cluster_3 <- cutree(hc_cluster, k = 3)

# Cantidad de viviendas por conglomerado
table(cluster_3)
## cluster_3
##    1    2    3 
## 7070 1165    8

Al realizar el análisis con 3 conglomerados, se obtiene una distribución de 7070 viviendas en el primer grupo, 1165 en el segundo y 8 en el tercero. Se observa que las 8 viviendas identificadas anteriormente continúan formando un grupo independiente, mientras que el resto de las viviendas se divide ahora en dos conglomerados. Esta distribución resulta más interesante para el análisis, ya que permite identificar dos grupos dentro de la mayoría de las viviendas, además del pequeño grupo con características más extremas.

datos_cluster$cluster_3 <- as.factor(cluster_3)
aggregate(
  cbind(preciom, areaconst, habitaciones, banios, parqueaderos) ~ cluster_3,
  data = datos_cluster,
  FUN = mean
)
##   cluster_3   preciom areaconst habitaciones   banios parqueaderos
## 1         1  362.2999  135.4590     3.303536 2.786987     1.548939
## 2         2  859.3039  399.0473     5.630043 5.188841     3.032618
## 3         3 1109.3750 1498.2500     4.500000 4.125000     4.000000

Al probar 3 conglomerados, se observa una separación más clara de las viviendas. El primer grupo reúne la mayoría de los registros (7070 viviendas) y corresponde, en general, a viviendas más pequeñas y de menor precio. El segundo grupo contiene 1165 viviendas con mayor área, precio y cantidad de habitaciones, baños y parqueaderos. Por último, aparece un tercer grupo de solo 8 viviendas, que se diferencia principalmente por tener áreas construidas extremadamente grandes. Este último grupo debe revisarse con cuidado. Durante la preparación de los datos ya se habían encontrado viviendas con características poco coherentes, como áreas muy grandes acompañadas de 0 habitaciones o 0 baños, registros que fueron eliminados antes de realizar el análisis. Aunque estas 8 viviendas ya no presentan valores en cero, algunas siguen mostrando combinaciones poco comunes, como áreas superiores a 1.000 m² con pocas habitaciones. Por lo tanto, no se puede asegurar que sean errores, pero sí se pueden considerar viviendas atípicas dentro de la base. En comparación con la solución de 2 conglomerados, trabajar con 3 grupos resulta más útil para el análisis, ya que no solamente separa estas viviendas atípicas, sino que también permite distinguir dos perfiles diferentes dentro del resto de las viviendas

Grafico de dispersion k=3

Una vez revisados los resultados y seleccionada la alternativa de 3 conglomerados, se presenta un gráfico de dispersión entre el área construida y el precio para observar cómo se distribuyen las viviendas de cada grupo.

ggplot(
  datos_cluster,
  aes(
    x = areaconst,
    y = preciom,
    color = cluster_3
  )
) +
  geom_point(alpha = 0.5) +
  labs(
    title = "Distribución de las viviendas por conglomerado",
    x = "Área construida",
    y = "Precio",
    color = "Conglomerado"
  ) +
  theme_minimal()

En el gráfico se observa una relación positiva entre el área construida y el precio: en general, a medida que aumenta el área de la vivienda, también aumenta su precio. El conglomerado 1 concentra principalmente viviendas de menor área y precio, mientras que el conglomerado 2 reúne viviendas que, en general, presentan áreas y precios más altos. Por otro lado, el conglomerado 3 aparece bastante separado del resto y corresponde a las 8 viviendas que habíamos identificado con áreas construidas extremadamente grandes y características poco comunes.También se observa cierto cruce entre los conglomerados 1 y 2, lo cual es esperable, ya que los grupos no se formaron únicamente con precio y área construida, sino considerando también habitaciones, baños y parqueaderos.

ggplot(
  datos_cluster,
  aes(x = habitaciones, y = banios, color = cluster_3)
) +
  geom_jitter(alpha = 0.4, width = 0.15, height = 0.15) +
  labs(
    title = "Habitaciones y baños por conglomerado",
    x = "Número de habitaciones",
    y = "Número de baños",
    color = "Conglomerado"
  ) +
  theme_minimal()

En el gráfico se observa que el conglomerado 1 se concentra principalmente en viviendas con menor cantidad de habitaciones y baños. Por otro lado, el conglomerado 2 tiende a presentar una mayor cantidad de ambas características, aunque existe cierto cruce entre los dos grupos. Esto muestra que los conglomerados no están completamente separados por una sola variable, sino por la combinación de todas las características utilizadas en el análisis.El conglomerado 3, al estar formado únicamente por 8 viviendas, tiene poca presencia en el gráfico y no muestra un patrón tan claro en habitaciones y baños. Esto refuerza la idea de que su principal diferencia frente a los demás grupos está relacionada especialmente con sus áreas construidas extremadamente grandes.

Caracterizaciond e los conglomerados

Una vez definidos los 3 conglomerados, se procede a revisar sus principales características con el fin de entender qué tipo de viviendas conforman cada grupo y cómo se distribuyen según el tipo de vivienda, la zona y el estrato.

Tipo de vivienda por conglomerado

# Distribución del tipo de vivienda por conglomerado
table(datos_cluster$cluster_3, datos_cluster$tipo)
##    
##     Apartamento Casa
##   1        4907 2163
##   2         167  998
##   3           0    8
# Proporción dentro de cada conglomerado
prop.table(
  table(datos_cluster$cluster_3, datos_cluster$tipo),
  margin = 1
)
##    
##     Apartamento      Casa
##   1   0.6940594 0.3059406
##   2   0.1433476 0.8566524
##   3   0.0000000 1.0000000
ggplot(
  datos_cluster,
  aes(x = cluster_3, fill = tipo)
) +
  geom_bar(position = "fill") +
  scale_y_continuous(
    labels = scales::percent_format()
  ) +
  labs(
    title = "Tipo de vivienda por conglomerado",
    x = "Conglomerado",
    y = "Proporción",
    fill = "Tipo de vivienda"
  ) +
  theme_minimal()

En cuanto al tipo de vivienda, se observa una diferencia clara entre los conglomerados. En el conglomerado 1 predominan los apartamentos, mientras que en el conglomerado 2 predominan las casas. Esto tiene sentido con los resultados anteriores, ya que este segundo grupo se caracteriza por viviendas con mayor área construida y, en general, las casas presentan áreas mayores que los apartamentos. Por último, el conglomerado 3 está compuesto únicamente por casas, lo cual también coincide con las áreas extremadamente grandes encontradas en este grupo.

Zona por conglomerado

prop.table(
  table(datos_cluster$cluster_3, datos_cluster$zona),
  margin = 1
)
##    
##     Zona Centro Zona Norte Zona Oeste Zona Oriente   Zona Sur
##   1  0.01357850 0.23776521 0.14427157   0.03833098 0.56605375
##   2  0.02145923 0.17682403 0.14420601   0.06180258 0.59570815
##   3  0.00000000 0.12500000 0.00000000   0.25000000 0.62500000
ggplot(
  datos_cluster,
  aes(x = cluster_3, fill = zona)
) +
  geom_bar(position = "fill") +
  scale_y_continuous(
    labels = scales::percent_format()
  ) +
  labs(
    title = "Distribución de las zonas por conglomerado",
    x = "Conglomerado",
    y = "Proporción",
    fill = "Zona"
  ) +
  theme_minimal()

Al revisar la distribución por zona, no se observa un patrón muy marcado entre los conglomerados. En los grupos 1 y 2 la mayor proporción de viviendas se encuentra en la Zona Sur, seguida principalmente por la Zona Norte, manteniendo una distribución relativamente similar. Por lo tanto, la ubicación por zona no parece ser una característica que diferencie claramente estos dos conglomerados.En el conglomerado 3 se observa una mayor participación de la Zona Oriente, pero este resultado debe tomarse con cuidado, ya que este grupo está compuesto únicamente por 8 viviendas.

Estrato por conglomerado

# Proporción de estratos dentro de cada conglomerado
prop.table(
  table(datos_cluster$cluster_3, datos_cluster$estrato),
  margin = 1
)
##    
##             3         4         5         6
##   1 0.1779349 0.2765205 0.3415842 0.2039604
##   2 0.1467811 0.1296137 0.2686695 0.4549356
##   3 0.3750000 0.0000000 0.0000000 0.6250000
ggplot(
  datos_cluster,
  aes(x = cluster_3, fill = as.factor(estrato))
) +
  geom_bar(position = "fill") +
  scale_y_continuous(
    labels = scales::percent_format()
  ) +
  labs(
    title = "Distribución de los estratos por conglomerado",
    x = "Conglomerado",
    y = "Proporción",
    fill = "Estrato"
  ) +
  theme_minimal()

A diferencia de la zona, el estrato sí muestra algunas diferencias entre los conglomerados. En el conglomerado 1 hay una mayor participación de viviendas de estratos 3, 4 y 5, mientras que la proporción de estrato 6 es menor. En cambio, en el conglomerado 2 se observa una mayor concentración en los estratos altos, especialmente 5 y 6, lo cual coincide con las características encontradas anteriormente para este grupo: viviendas de mayor precio, área y número de habitaciones, baños y parqueaderos.el conglomerado 3 presenta una distribución particular, ya que sus viviendas se encuentran únicamente en los estratos 3 y 6, sin presencia de los estratos intermedios 4 y 5. Sin embargo, este resultado debe interpretarse con cuidado debido a que este grupo está formado por solamente 8 viviendas.

Recopilando lo anterior se tiene entonces: - Conglomerado 1 – Viviendas más pequeñas y económicas: Es el grupo más grande, con 7.070 viviendas. Presenta los menores valores promedio de precio y área construida, así como menos habitaciones, baños y parqueaderos. Predominan los apartamentos y hay una mayor participación de estratos 3, 4 y 5. - Conglomerado 2 – Viviendas más grandes y de mayor valor: Está formado por 1.165 viviendas. Se caracteriza por tener mayor precio y área construida, además de más habitaciones, baños y parqueaderos. Predominan claramente las casas y existe una mayor concentración de viviendas en estratos 5 y 6. - Conglomerado 3 – Viviendas con características extremas: Está compuesto únicamente por 8 viviendas, todas casas. Su principal diferencia son las áreas construidas extremadamente grandes, muy alejadas de las observadas en la mayoría de la base. Además, presentan algunas combinaciones poco comunes entre área y demás características, por lo que este grupo debe interpretarse con cuidado. Se encuentran únicamente en los estratos 3 y 6.

En cuanto a la zona, no se encontraron diferencias muy marcadas entre los conglomerados, por lo que la ubicación geográfica no parece ser un elemento que los diferencie claramente. En general, la separación de los grupos está más relacionada con el tamaño, precio y características físicas de las viviendas, además del tipo de vivienda y, en cierta medida, el estrato.

4. Análisis de Correspondencia

En esta sección se realiza un análisis de correspondencias con el propósito de estudiar la relación entre las variables categóricas asociadas a la oferta de vivienda. En particular, se busca responder la siguiente pregunta: determinados tipos de vivienda tienden a estar asociados con determinadas zonas y barrios de la ciudad? Para ello, inicialmente se analiza la relación entre el tipo de vivienda y la zona, con el fin de obtener una visión general de cómo se distribuye la oferta inmobiliaria en la ciudad.

Tipo × Zona:visión general del mercado.

tabla_tipo_zona <- table(
  datos_corresp$zona,
  datos_corresp$tipo
)

tabla_tipo_zona
##               
##                Apartamento Casa
##   Zona Centro           24  100
##   Zona Norte          1198  722
##   Zona Oeste          1029  169
##   Zona Oriente          62  289
##   Zona Sur            2787 1939

A partir de la tabla de contingencia se observan diferencias en la distribución de los tipos de vivienda entre las zonas. En las zonas centro y Oriente predominan las casas, mientras que en la zona Oeste predominanlos apartamentos. Por su parte, las zonas Norte y Sur presentan una mayor cantidad de apartamentos que de casas, aunque con una presencia importante de ambos tipos de vivienda.Estas diferencias sugieren que la composición de la oferta según el tipo de vivienda podría variar entre las zonas. Sin embargo, para determinar si existe una asociación estadísticamente significativa entre ambas variables, se realiza a continuación la prueba Chi-cuadrado de independencia.

Las hipotesis son las siguientes: H₀: El tipo de vivienda y la zona son independientes; es decir, no existe asociación entre ambas variables. H₁: El tipo de vivienda y la zona no son independientes; es decir, existe asociación entre ambas variables.

chisq.test(tabla_tipo_zona)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla_tipo_zona
## X-squared = 690.93, df = 4, p-value < 2.2e-16

El resultado de la prueba Chi-cuadrado presenta un p-value < 0.05, por lo que se rechaza la hipótesis nula de independencia. Por lo tanto, existe evidencia estadística de una asociación entre el tipo de vivienda y la zona de la ciudad. Esto indica que la distribución de casas y apartamentos no es la misma en todas las zonas. Ahora bien, una vez identificada la existencia de una asociacion entre tipo de vivienda y zona, se realiza el análisis de correspondencias con el proposito de visualizar como se relacionan las categorias de ambas variables.

library(FactoMineR)
library(factoextra)

resultados_ac <- CA(tabla_tipo_zona, graph=FALSE)
resultados_ac
## **Results of the Correspondence Analysis (CA)**
## The row variable has  5  categories; the column variable has 2 categories
## The chi square of independence between the two variables is equal to 690.9297 (p-value =  3.207561e-148 ).
## *The results are available in the following objects:
## 
##    name              description                   
## 1  "$eig"            "eigenvalues"                 
## 2  "$col"            "results for the columns"     
## 3  "$col$coord"      "coord. for the columns"      
## 4  "$col$cos2"       "cos2 for the columns"        
## 5  "$col$contrib"    "contributions of the columns"
## 6  "$row"            "results for the rows"        
## 7  "$row$coord"      "coord. for the rows"         
## 8  "$row$cos2"       "cos2 for the rows"           
## 9  "$row$contrib"    "contributions of the rows"   
## 10 "$call"           "summary called parameters"   
## 11 "$call$marge.col" "weights of the columns"      
## 12 "$call$marge.row" "weights of the rows"
valores_prop <- resultados_ac$eig
valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.08305442                    100                               100

Al cruzar la variable zona, que presenta cinco categorías, con la variable tipo de vivienda, que presenta dos categorías (Casa y Apartamento), el análisis de correspondencias genera una sola dimensión. Esta única dimensión explica el 100% de la información representada por el análisis, por lo que es suficiente para estudiar la forma en que se relacionan las categorías de ambas variables. Es importante aclarar que este 100% no significa que exista una relación perfecta entre la zona y el tipo de vivienda, sino que toda la información obtenida por el análisis de correspondencias se resume en un único eje o dimension. A continuación, se calculan las coordenadas para identificar la ubicación de cada categoría y observar cuáles se encuentran relacionadas entre sí.

# Coordenadas de las zonas (rows)
resultados_ac$row$coord
##  Zona Centro   Zona Norte   Zona Oeste Zona Oriente     Zona Sur 
##  -0.86131854   0.02238755   0.50482822  -0.89603812  -0.04791693
# Coordenadas de los tipos de vivienda(columns)
resultados_ac$col$coord
##                   [,1]
## Apartamento  0.2289585
## Casa        -0.3627488

Al observar las coordenadas, se identifica que Casa se encuentra en el lado negativo de la dimensión (-0.363), mientras que Apartamento se encuentra en el lado positivo (0.229). En cuanto a las zonas, Centro y Oriente presentan valores negativos, ubicándose en el mismo sentido que las casas, mientras que la Zona Oeste presenta un valor positivo y se ubica en el mismo sentido que los apartamentos. Por su parte, las zonas Norte y Sur se encuentran muy próximas al centro, por lo que no presentan un comportamiento tan marcado hacia uno de los dos tipos de vivienda. Estos resultados son coherentes con lo observado inicialmente en la tabla de contingencia, donde las casas presentan una mayor participación en Centro y Oriente, mientras que los apartamentos predominan claramente en la Zona Oeste.

mapa_ac <- data.frame(
  categoria = c(
    names(resultados_ac$row$coord),
    rownames(resultados_ac$col$coord)
  ),
  coordenada = c(
    as.numeric(resultados_ac$row$coord),
    as.numeric(resultados_ac$col$coord[, 1])
  ),
  grupo = c(
    rep("Zona", 5),
    rep("Tipo de vivienda", 2)
  )
)

mapa_ac
##      categoria  coordenada            grupo
## 1  Zona Centro -0.86131854             Zona
## 2   Zona Norte  0.02238755             Zona
## 3   Zona Oeste  0.50482822             Zona
## 4 Zona Oriente -0.89603812             Zona
## 5     Zona Sur -0.04791693             Zona
## 6  Apartamento  0.22895850 Tipo de vivienda
## 7         Casa -0.36274879 Tipo de vivienda
library(ggplot2)

ggplot(
  mapa_ac,
  aes(
    x = coordenada,
    y = 0,
    shape = grupo,
    color = grupo
  )
) +
  geom_point(size = 2.5) +

  geom_text(
    aes(label = categoria),
    angle = 45,
    vjust = 1.5,
    hjust = 1,
    size = 3.5,
    show.legend = FALSE
  ) +

  geom_vline(
    xintercept = 0,
    linetype = "dashed"
  ) +

  scale_color_manual(
    values = c(
      "Zona" = "purple",
      "Tipo de vivienda" = "cyan"
    )
  ) +

  labs(
    title = "Mapa de correspondencias: Tipo de vivienda y Zona",
    x = "Dimensión 1 (100%)",
    y = "",
    shape = "",
    color = ""
  ) +
  
  scale_x_continuous(
  expand = expansion(mult = c(0.18, 0.08))
) +

  theme_minimal() +

  theme(
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    axis.title.y = element_blank()
  )

Al interpretar el mapa de correspondencias, es importante tener en cuenta que la asociación entre las categorías no depende únicamente de la cantidad de viviendas presentes en cada zona, sino también de la proporción que representa cada tipo de vivienda con respecto al total de viviendas de esa zona. Por ejemplo, aunque la zoona Sur presenta una gran cantidad de apartamentos, también cuenta con una cantidad importante de casas, por lo que se ubica cerca del centro de la dimensión. En cambio, la Zona Oeste presenta una mayor asociación con los apartamentos, ya que estos representan una proporción mucho mayor de las viviendas de esta zona. Por el contrario, las zonas Oriente y Centro se encuentran más asociadas con las casas, debido al predominio de este tipo de vivienda dentro de dichas zonas.Por lo tanto, el mapa permite identificar que tipo de vivienda caracteriza en mayor medida la oferta de cada zona, más allá de comparar únicamente las cantidades absolutas.

##Tipo × Barrio:visión más específica de la ubicación.

En esta sección se busca realizar una visión más específica de la ubicación de las viviendas, utilizando la variable barrio. De esta manera, se busca responder la siguiente pregunta: determinados tipos de vivienda tienden a estar asociados con determinados barrios de la ciudad? Debido a los 389 barrios identificados previamente en la sección de conocimiento de los datos, inicialmente se revisará la cantidad de registros que presenta cada uno, con el fin de conocer cómo se encuentran distribuidas las observaciones entre los diferentes barrios. Se observa que muchos barrios cuentan con una cantidad reducida de registros, llegando algunos a presentar únicamente una observación. Incluir todos los barrios en el análisis de correspondencias podría llevar a interpretar asociaciones basadas en muy pocas viviendas y, adicionalmente, dificultaría la visualización e interpretación de los resultados. Por esta razón, se evaluarán diferentes cantidades mínimas de registros por barrio con el fin de establecer un criterio adecuado para continuar con el análisis.

freq_barrios <- sort(
  table(datos_corresp$barrio),
  decreasing = TRUE
)
summary(as.numeric(freq_barrios))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00    1.00    3.00   21.39   17.00 1009.00

Se observa una distribución desigual en la cantidad de registros por barrio. Mientras algunos barrios cuentan con un único registro, otros presentan hasta 1009 observaciones. El 25% de los barrios tiene 1 registro o menos, mientras que el 75% presenta 17 registros o menos. Asimismo, la mediana es de apenas 3 registros, lo que indica que la mitad de los barrios cuenta con tres observaciones o menos. Por otra parte, la media alcanza los 21.39 registros, valor considerablemente superior a la mediana debido a la presencia de algunos barrios con una gran cantidad de observaciones, los cuales elevan el promedio general.

Evaluemos entonces diferentes cantidades mínimas de registros por barrio, con el fin de determinar cuántos barrios podrían conservarse para el análisis.

sum(freq_barrios < 5)
## [1] 214
sum(freq_barrios < 10)
## [1] 263
sum(freq_barrios < 20)
## [1] 301
sum(freq_barrios >= 5)
## [1] 175
sum(freq_barrios >= 10)
## [1] 126
sum(freq_barrios >= 20)
## [1] 88

Se observa que 214 barrios tienen menos de 5 registros, 263 tienen menos de 10 y 301 tienen menos de 20. Por otra parte, al considerar cantidades mínimas de 5, 10 y 20 registros, se conservarían 175, 126 y 88 barrios, respectivamente. Esto evidencia que una gran proporción de los barrios cuenta con pocas observaciones.Sin embargo, para seleccionar un criterio no basta con conocer la cantidad de barrios que se conservarían; también es necesario determinar qué proporción del total de viviendas seguiría representada en cada caso.

barrios_5 <- names(freq_barrios[freq_barrios >= 5])
barrios_10 <- names(freq_barrios[freq_barrios >= 10])
barrios_20 <- names(freq_barrios[freq_barrios >= 20])

sum(datos_corresp$barrio %in% barrios_5)
## [1] 7982
sum(datos_corresp$barrio %in% barrios_10)
## [1] 7657
sum(datos_corresp$barrio %in% barrios_20)
## [1] 7104

Al considerar únicamente barrios con un mínimo de 20 registros, se mantienen 7104 de las 8319 viviendas, equivalentes aproximadamente al 85,4 % de las observaciones. Por lo tanto, aunque el número de barrios se reduce considerablemente, se conserva la mayor parte de la información disponible.A partir de estos resultados, se decide continuar el análisis de correspondencias considerando los 88 barrios que cuentan con al menos 20 registros, ya que este criterio permite reducir la influencia de barrios con muy pocas observaciones y realizar el análisis sobre aquellos que cuentan con una mayor representación dentro de la base de datos.

datos_corresp_barrio <- datos_corresp[   #base de datos depurada en la categoria barrios
  datos_corresp$barrio %in% barrios_20,
]
nrow(datos_corresp_barrio)
## [1] 7104
length(unique(datos_corresp_barrio$barrio))
## [1] 88

Ya teniendo al base de datos depurada, tomando unicamente los barrios con al menos 20 registros se construye la tabla de contingencia entre el barrio y tipo de vivienda, con el fin de observar como se distribuyen las casas y apartamentos en cada uno de los barrios seleccionados.

tabla_tipo_barrio <- table(
  datos_corresp_barrio$barrio,
  datos_corresp_barrio$tipo
)

tabla_tipo_barrio
##                           
##                            Apartamento Casa
##   acopi                             88   70
##   aguacatal                         98   11
##   alfonso lopez                      2   20
##   arboledas                         38    0
##   bellavista                        36    7
##   bochalema                         33    0
##   bosques del limonar               12    9
##   brisas de los                     60   22
##   cali                              23   14
##   camino real                       15   21
##   canaverales                       19    2
##   caney                             58   30
##   capri                             43   13
##   cerro cristales                   22    0
##   chipichape                        25    5
##   ciudad 2000                       19   77
##   ciudad bochalema                  48    0
##   ciudad cordoba                     1   34
##   ciudad jardin                    230  310
##   ciudad los alamos                 15   11
##   ciudadela pasoancho                3   18
##   colseguros                        22   22
##   cristales                         72   11
##   cuarto de legua                   30   14
##   departamental                     16   13
##   el bosque                         13   37
##   el caney                         125   84
##   el ingenio                       128   75
##   el ingenio ii                      9   12
##   el ingenio iii                    10   10
##   el lido                           34   25
##   el limonar                        59   76
##   el penon                          56    4
##   el refugio                        77   43
##   gran limonar                       8   16
##   guadalupe                         10   11
##   juanamb??                         41   12
##   junin                              2   22
##   la flora                         268  100
##   la hacienda                      109   57
##   la merced                          2   24
##   las ceibas                         8   15
##   los alcazares                     22    0
##   los andes                          8   13
##   los cambulos                      23    8
##   los cristales                    137   17
##   los guaduales                     16   10
##   mayapan las vegas                 32   14
##   mel?Cndez                         21    2
##   melendez                          40   12
##   menga                             21    2
##   metropolitano del norte           20    1
##   miraflores                         6   20
##   multicentro                       27    0
##   napoles                           13   18
##   normandia                        155    4
##   nueva tequendama                  37   36
##   pacara                            21    2
##   pampa linda                       13   13
##   pance                            206  206
##   parcelaciones pance               18   43
##   prados del limonar                 4   17
##   prados del norte                  96   31
##   primero de mayo                   24   13
##   quintas de don                    58   15
##   salomia                           20   20
##   san antonio                        1   23
##   san fernando                      22   33
##   san joaquin                        1   19
##   san vicente                       16   32
##   santa anita                       39   11
##   santa isabel                      44   20
##   santa monica                      37   18
##   santa monica residencial          23   21
##   santa rita                        37    8
##   santa teresita                   251   12
##   seminario                         23    9
##   tequendama                        15   29
##   torres de comfandi                55    2
##   urbanizacion la flora             60   23
##   valle del lili                   841  168
##   versalles                         55   16
##   villa del prado                   11   41
##   villa del sol                     13   12
##   vipasa                             1   31
##   zona norte                        13   19
##   zona oeste                        22    4
##   zona sur                          32   42

Aplicamos la prueba Chi cuadrado para evaluar las sigueintes hipotesis H₀: el tipo de vivienda y el barrio son independientes; no existe asociación entre ambas variables. H₁: el tipo de vivienda y el barrio están asociados.

chisq.test(tabla_tipo_barrio)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla_tipo_barrio
## X-squared = 1574.3, df = 87, p-value < 2.2e-16

La prueba Chi-cuadrado presenta un p-valor inferior a 0.05, por lo que se rechaza la hipótesis nula de independencia. Esto indica que existe una asociación estadísticamente significativa entre el tipo de vivienda y el barrio, es decir, la distribución de casas y apartamentos varia entre los barrios analizados.

Apliquemos entonces el análisis de correspondencias para obtener los valores propios y conocer cuántas dimensiones se generan.

library(FactoMineR)

resultados_ac_barrio <- CA(
  tabla_tipo_barrio,
  graph = FALSE
)
valores_prop_barrio <- resultados_ac_barrio$eig
valores_prop_barrio
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1  0.2216058                    100                               100

Como resultado, nuevamente se obtiene una única dimensión, la cual representa el 100 % de la información del análisis. Esto ocurre porque, aunque se están considerando 88 barrios, la variable tipo de vivienda continúa teniendo únicamente dos categorías: Casa y Apartamento. Por esta razón, esta variable limita el análisis a una sola dimensión.

                                                                                                      min(88−1,2−1)=min(87,1)=1
                                                                                                      

Por lo tanto, los 88 barrios podrán ubicarse a lo largo de esta única dimensión, permitiendo observar cuáles se orientan hacia casa y cuáles hacia apartamento.A continuación, se calculan las coordenadas de los barrios y de los tipos de vivienda sobre la dimensión obtenida, con el propósito de identificar su ubicación y posteriormente analizar las asociaciones existentes entre sus categorías.

# Coordenadas de los barrios
resultados_ac_barrio$row$coord
##                    acopi                aguacatal            alfonso lopez 
##             -0.201151842              0.517434541             -1.180044513 
##                arboledas               bellavista                bochalema 
##              0.729400450              0.387476584              0.729400450 
##      bosques del limonar            brisas de los                     cali 
##             -0.170766461              0.165881327             -0.065341508 
##              camino real              canaverales                    caney 
##             -0.495826735              0.529363358              0.013358589 
##                    capri          cerro cristales               chipichape 
##              0.241810040              0.729400450              0.379335540 
##              ciudad 2000         ciudad bochalema           ciudad cordoba 
##             -0.955286929              0.729400450             -1.310977882 
##            ciudad jardin        ciudad los alamos      ciudadela pasoancho 
##             -0.476378684             -0.159225860             -1.070933372 
##               colseguros                cristales          cuarto de legua 
##             -0.320794280              0.451035582              0.061094713 
##            departamental                el bosque                 el caney 
##             -0.212153446             -0.824887750             -0.114775218 
##               el ingenio            el ingenio ii           el ingenio iii 
##             -0.046605508             -0.470822098             -0.320794280 
##                  el lido               el limonar                 el penon 
##             -0.160595084             -0.453041023              0.589374486 
##               el refugio             gran limonar                guadalupe 
##             -0.023239106             -0.670859190             -0.370803553 
##                juanamb??                    junin                 la flora 
##              0.253840572             -1.195956554              0.158642445 
##              la hacienda                la merced               las ceibas 
##              0.008182383             -1.209420589             -0.640418763 
##            los alcazares                los andes             los cambulos 
##              0.729400450             -0.570840644              0.187364460 
##            los cristales            los guaduales        mayapan las vegas 
##              0.497539276             -0.078441650              0.090151484 
##                mel?Cndez                 melendez                    menga 
##              0.546757888              0.244695190              0.546757888 
##  metropolitano del norte               miraflores              multicentro 
##              0.629381904             -0.886283749              0.729400450 
##                  napoles                normandia         nueva tequendama 
##             -0.490180526              0.676560463             -0.306408051 
##                   pacara              pampa linda                    pance 
##              0.546757888             -0.320794280             -0.320794280 
##      parcelaciones pance       prados del limonar         prados del norte 
##             -0.751201956             -0.970914827              0.216706960 
##          primero de mayo           quintas de don                  salomia 
##             -0.008574225              0.297813575             -0.320794280 
##              san antonio             san fernando              san joaquin 
##             -1.283472782             -0.530833226             -1.265969536 
##              san vicente              santa anita             santa isabel 
##             -0.670859190              0.267314769              0.073028744 
##             santa monica santa monica residencial               santa rita 
##              0.042000263             -0.273058156              0.355997879 
##           santa teresita                seminario               tequendama 
##              0.633565189              0.138665914             -0.654947148 
##       torres de comfandi    urbanizacion la flora           valle del lili 
##              0.655702574              0.147364817              0.379682482 
##                versalles          villa del prado            villa del sol 
##              0.256073248             -0.926675854             -0.278786491 
##                   vipasa               zona norte               zona oeste 
##             -1.305351839             -0.517705791              0.406263610 
##                 zona sur 
##             -0.462712486
# Coordenadas de los tipos de vivienda
resultados_ac_barrio$col$coord
##                   [,1]
## Apartamento  0.3433655
## Casa        -0.6453935

Las coordenadas obtenidas ubican a Casa en -0.645 y a Apartamento en 0.343. Por lo tanto, los barrios con coordenadas negativas se orientan hacia Casa, mientras que aquellos con coordenadas positivas se orientan hacia Apartamento. Con el fin de identificar los barrios que presentan las asociaciones más marcadas, se revisarán aquellos ubicados en los extremos de la dimensión (se tomarán los 10 primeros).

library(dplyr)

# Coordenadas de los barrios
coord_barrios <- resultados_ac_barrio$row$coord

# 10 barrios más orientados hacia Casa
barrios_casa <- data.frame(
  barrio = names(sort(coord_barrios))[1:10],
  coordenada = as.numeric(sort(coord_barrios)[1:10]),
  orientacion = "Casa"
)

# 10 barrios más orientados hacia Apartamento
barrios_apto <- data.frame(
  barrio = names(sort(coord_barrios, decreasing = TRUE))[1:10],
  coordenada = as.numeric(sort(coord_barrios, decreasing = TRUE)[1:10]),
  orientacion = "Apartamento"
)

# Unir los 20 barrios extremos
barrios_extremos <- rbind(
  barrios_casa,
  barrios_apto
)

barrios_extremos
##                     barrio coordenada orientacion
## 1           ciudad cordoba -1.3109779        Casa
## 2                   vipasa -1.3053518        Casa
## 3              san antonio -1.2834728        Casa
## 4              san joaquin -1.2659695        Casa
## 5                la merced -1.2094206        Casa
## 6                    junin -1.1959566        Casa
## 7            alfonso lopez -1.1800445        Casa
## 8      ciudadela pasoancho -1.0709334        Casa
## 9       prados del limonar -0.9709148        Casa
## 10             ciudad 2000 -0.9552869        Casa
## 11               arboledas  0.7294004 Apartamento
## 12               bochalema  0.7294004 Apartamento
## 13        ciudad bochalema  0.7294004 Apartamento
## 14             multicentro  0.7294004 Apartamento
## 15         cerro cristales  0.7294004 Apartamento
## 16           los alcazares  0.7294004 Apartamento
## 17               normandia  0.6765605 Apartamento
## 18      torres de comfandi  0.6557026 Apartamento
## 19          santa teresita  0.6335652 Apartamento
## 20 metropolitano del norte  0.6293819 Apartamento

A continuación, se presenta el mapa de correspondencias correspondiente a los 10 barrios ubicados en cada uno de los extremos de la dimensión, seleccionados por presentar las asociaciones más marcadas con cada tipo de vivienda. Para facilitar su identificación, la leyenda se encuentra organizada en dos columnas: la columna de la izquierda corresponde a los barrios con mayor asociación hacia Apartamento, ubicados en el extremo de coordenadas positivas; mientras que la columna de la derecha presenta los barrios con mayor asociación hacia Casa, ubicados en el extremo de coordenadas negativas.

barrios_extremos <- barrios_extremos %>%
  arrange(orientacion, coordenada) %>%
  mutate(numero = row_number())

Mapa de correspondencias

library(ggplot2)
library(dplyr)

# Preparar los 20 barrios extremos para el gráfico
barrios_extremos_grafico <- barrios_extremos %>%
  arrange(orientacion, coordenada) %>%
  mutate(
    barrio = factor(barrio, levels = barrio),
    fila = ifelse(orientacion == "Casa", 1, 2)
  )

# Mapa de correspondencias
ggplot(
  barrios_extremos_grafico,
  aes(
    x = coordenada,
    y = fila,
    color = barrio
  )
) +
  
  # Puntos correspondientes a cada barrio
  geom_point(size = 4) +
  
  # Línea de referencia en cero
  geom_vline(
    xintercept = 0,
    linetype = "dashed",
    color = "gray50"
  ) +
  
  # Identificación de Casa y Apartamento
  scale_y_continuous(
    breaks = c(1, 2),
    labels = c("Casa", "Apartamento")
  ) +
  
  # Títulos
  labs(
    title = "Mapa de correspondencias: Tipo de vivienda y Barrio",
    subtitle = "10 barrios con mayor orientación hacia cada tipo de vivienda",
    x = "Dimensión 1 (100%)",
    y = "",
    color = "Barrio"
  ) +
  
  # Tema
  theme_minimal() +
  
  theme(
    legend.position = "right",
    legend.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  ) +
  
  # Leyenda de barrios en dos columnas
  guides(
    color = guide_legend(
      ncol = 2,
      override.aes = list(size = 4)
    )
  )

La figura anterior corresponde a el mapa de correspondencias con los 10 barrios que muestran mayor asociación con Casa y los 10 con mayor asociación con Apartamento, identificados a partir de los extremos de la dimensión. Los barrios correspondientes a cada grupo se presentan en la leyenda del gráfico. Es importante señalar que esta asociación no implica que en dichos barrios exista exclusivamente un solo tipo de vivienda, sino que su distribución presenta una mayor orientación relativa hacia Casa o Apartamento. De esta manera, los barrios ubicados en el extremo negativo presentan una mayor asociación con Casa, mientras que aquellos ubicados en el extremo positivo presentan una mayor asociación con Apartamento.

Tabla asociada a los barrios del mapa de correspondencias

# Obtener la zona con mayor número de registros para cada barrio
zona_referencia <- datos_corresp_barrio %>%
  count(barrio, zona) %>%
  group_by(barrio) %>%
  slice_max(n, n = 1, with_ties = FALSE) %>%
  ungroup() %>%
  select(barrio, zona)

# Agregar zona a los barrios extremos
barrios_extremos_zona <- barrios_extremos %>%
  left_join(zona_referencia, by = "barrio")

# Tabla final
knitr::kable(
  barrios_extremos_zona %>%
    select(numero, barrio, zona, orientacion, coordenada),
  digits = 3,
  col.names = c(
    "Número",
    "Barrio",
    "Zona de referencia",
    "Orientación",
    "Coordenada"
  ),
  caption = "Barrios representados en el mapa de correspondencias"
)
Barrios representados en el mapa de correspondencias
Número Barrio Zona de referencia Orientación Coordenada
1 metropolitano del norte Zona Norte Apartamento 0.629
2 santa teresita Zona Oeste Apartamento 0.634
3 torres de comfandi Zona Norte Apartamento 0.656
4 normandia Zona Oeste Apartamento 0.677
5 cerro cristales Zona Oeste Apartamento 0.729
6 los alcazares Zona Norte Apartamento 0.729
7 arboledas Zona Oeste Apartamento 0.729
8 bochalema Zona Sur Apartamento 0.729
9 ciudad bochalema Zona Sur Apartamento 0.729
10 multicentro Zona Sur Apartamento 0.729
11 ciudad cordoba Zona Oriente Casa -1.311
12 vipasa Zona Norte Casa -1.305
13 san antonio Zona Oeste Casa -1.283
14 san joaquin Zona Sur Casa -1.266
15 la merced Zona Norte Casa -1.209
16 junin Zona Centro Casa -1.196
17 alfonso lopez Zona Oriente Casa -1.180
18 ciudadela pasoancho Zona Sur Casa -1.071
19 prados del limonar Zona Sur Casa -0.971
20 ciudad 2000 Zona Sur Casa -0.955

La tabla anterior permite identificar los barrios representados en el mapa de correspondencias, su orientación hacia cada tipo de vivienda y la coordenada obtenida en la dimensión analizada. Adicionalmente, se incorpora una zona de referencia con el propósito de facilitar su contextualización geográfica. Como puede observarse, los barrios con mayor asociación hacia Casa o Apartamento no se concentran exclusivamente en una misma zona de la ciudad, lo que evidencia que el análisis por barrio permite identificar patrones más específicos que aquellos observados previamente a nivel de zona.

Sin embargo, durante la revisión de esta información se identificó que algunos barrios presentan registros asociados con más de una zona. Por esta razón, la zona mostrada en la tabla corresponde únicamente a aquella que concentra la mayor cantidad de registros para cada barrio y debe interpretarse como una referencia descriptiva, no como una clasificación geográfica validada.Nota: Durante la revisión se identificó que algunos barrios presentan registros asociados con más de una zona. En los 88 barrios analizados, 38 presentan esta situación: 29 aparecen asociados con dos zonas y 9 con tres. Por esta razón, la zona presentada en la tabla corresponde únicamente a la de mayor frecuencia y se utiliza como referencia descriptiva.

cantidad_zonas_barrio <- datos_corresp_barrio %>%
  group_by(barrio) %>%
  summarise(
    cantidad_zonas = n_distinct(zona),
    .groups = "drop"
  ) %>%
  filter(cantidad_zonas > 1)

table(cantidad_zonas_barrio$cantidad_zonas)
## 
##  2  3 
## 29  9

Gráfico de proporciones

Con el propósito de complementar el mapa de correspondencias, se presenta la proporción de Casas y Apartamentos en los 20 barrios seleccionados. Esto permite observar con mayor claridad cuál tipo de vivienda predomina en cada barrio.

# Calcular proporciones
proporcion_extremos <- datos_corresp_barrio %>%
  filter(barrio %in% barrios_extremos$barrio) %>%
  count(barrio, tipo) %>%
  group_by(barrio) %>%
  mutate(proporcion = n / sum(n)) %>%
  ungroup()

# Ordenar los barrios como aparecen en el análisis
proporcion_extremos$barrio <- factor(
  proporcion_extremos$barrio,
  levels = rev(barrios_extremos$barrio)
)

# Gráfico
ggplot(proporcion_extremos,
       aes(x = proporcion, y = barrio, fill = tipo)) +
  geom_col() +
  scale_x_continuous(
    labels = scales::percent_format(),
    limits = c(0, 1)
  ) +
  labs(
    title = "Composición del tipo de vivienda en los barrios extremos",
    subtitle = "10 barrios con mayor asociación hacia cada tipo de vivienda",
    x = "Porcentaje de viviendas",
    y = "Barrio",
    fill = "Tipo de vivienda"
  ) +
  theme_minimal() +
  theme(
    legend.position = "bottom"
  )

El gráfico muestra que los primeros 10 barrios presentan una mayor proporción de apartamentos, mientras que en los últimos 10 predominan las casas. Esto permite entender que la asociación observada en el mapa de correspondencias representa el predominio de un tipo de vivienda y no necesariamente su presencia exclusiva.

5. Resumen visual de resultados

5.1 Caracteristicas de las viviendas

Para resumir las principales relaciones encontradas entre las características de las viviendas, se presenta el círculo de correlaciones obtenido mediante el Análisis de Componentes Principales (ACP). Este permite observar de manera conjunta la relación entre el precio, el área construida, los parqueaderos, los baños y las habitaciones

Se observa principalmente una relación positiva entre el precio, los parqueaderos y el área construida, mostrando que las viviendas con mayor espacio y disponibilidad de parqueadero tienden a presentar precios más altos. En cuanto a la variable habitaciones, se identificaron algunos registros que requieren revisión, por lo que su interpretación debe realizarse con precaución. Como complemento, se presenta la relación entre el precio y el área construida según los conglomerados obtenidos. Esto permite observar de forma visual los diferentes perfiles de viviendas identificados y la presencia de un pequeño grupo con características extremas.

Se observa que el conglomerado 1 concentra principalmente viviendas de menor área y precio, mientras que el conglomerado 2 reúne viviendas de mayor tamaño y valor. El conglomerado 3 se encuentra más alejado del resto debido principalmente a sus áreas construidas extremadamente grandes.

5.2 Ubicacion y tipo de vivienda

Para observar cómo cambia el tipo de vivienda según su ubicación, se presenta la relación entre zona y tipo de vivienda. Esta visualización permite identificar qué zonas presentan una mayor orientación hacia Casas o Apartamentos dentro de la oferta analizada.

Se observa una mayor presencia de Apartamentos en las zonas Norte, Sur y Oeste, mientras que las Casas presentan una mayor orientación hacia las zonas Oriente y Centro. La Zona Sur presenta un comportamiento más equilibrado entre ambos tipos de vivienda, por lo que no muestra una asociación tan marcada como las demás zonas. Al analizar la ubicación con mayor detalle a nivel de barrio, se observan sectores con un predominio mucho más marcado hacia un tipo de vivienda. Los siguientes barrios corresponden a aquellos que presentaron las mayores asociaciones con Casas y Apartamentos en el análisis de correspondencias.

A nivel de barrio, las diferencias son más marcadas. Algunos presentan una oferta compuesta casi en su totalidad por Apartamentos, mientras que en otros predominan ampliamente las Casas. Esto muestra que el análisis por barrio permite identificar patrones específicos que pueden no observarse al analizar únicamente las zonas de la ciudad.También se revisa la composición de los conglomerados según el estrato socioeconómico. En este caso se observan algunas diferencias, principalmente entre los conglomerados 1 y 2.

El conglomerado 2 presenta una mayor participación de viviendas de estratos 5 y 6, mientras que el conglomerado 1 tiene una distribución más amplia entre los estratos 3, 4 y 5 y una menor participación del estrato 6.

6. Conclusiones y recomendaciones

Conclusiones

  • Se encontró que el precio de las viviendas está relacionado principalmente con el área construida y el número de parqueaderos. En general, las viviendas con mayor espacio y disponibilidad de parqueadero tienden a tener precios más altos.
  • La ubicación también presenta diferencias en el tipo de vivienda ofrecida. En algunas zonas y barrios predominan los apartamentos, mientras que en otros hay una mayor presencia de casas. Esto permite conocer mejor qué tipo de vivienda tiene mayor oferta en cada sector de la ciudad.
  • Al revisar los barrios con mayor relación hacia cada tipo de vivienda, se encontraron algunos con un predominio muy marcado. Incluso, en algunos barrios analizados, los registros correspondían únicamente a apartamentos o principalmente a casas.
  • El análisis de conglomerados permitió identificar tres grupos de viviendas. El primer grupo, que reúne la mayoría de los registros, está formado principalmente por viviendas más pequeñas y de menor precio. El segundo grupo presenta viviendas más grandes, costosas y con mayor cantidad de habitaciones, baños y parqueaderos. El tercer grupo está formado únicamente por 8 viviendas con áreas construidas extremadamente grandes, por lo que se consideran casos atípicos que deben analizarse con cuidado.
  • También se encontraron diferencias según el tipo de vivienda y el estrato. En el primer conglomerado predominan los apartamentos, mientras que en el segundo predominan las casas y existe una mayor presencia de viviendas de estratos 5 y 6. Por el contrario, la zona no mostró diferencias muy marcadas entre estos grupos.
  • Durante la preparación de los datos para el análisis de conglomerados se encontraron viviendas registradas con cero habitaciones o cero baños. Algunos de estos registros tenían áreas y precios altos, por lo que estos valores podían corresponder a información faltante o errores de registro. Como no era posible comprobarlos, se decidió excluirlos del análisis de conglomerados.
  • En general, los resultados permiten entender mejor qué características tienen las viviendas ofrecidas y qué perfiles existen dentro de la oferta. Esta información puede ayudar a la empresa a organizar y conocer mejor su oferta de inmuebles según características como precio, tamaño, tipo de vivienda y estrato.

Recomendaciones

  • Revisar los registros poco coherentes: verificar las viviendas que presentan valores poco habituales, especialmente aquellas con áreas construidas muy grandes en comparación con sus demás características. Esto permitiría determinar si corresponden a viviendas realmente particulares o a errores en la información.
  • Revisar la clasificación de los barrios por zona: durante el análisis se encontraron algunos barrios registrados en dos o más zonas diferentes. En ciertos casos, la mayoría de los registros aparecen en una zona y solamente uno o pocos en otra. Sería conveniente revisar estos casos para determinar si corresponden realmente a ubicaciones diferentes o si existe un error en la asignación de la zona.
  • Mejorar los controles al ingresar la información: establecer validaciones para variables como área construida, habitaciones, baños, parqueaderos, barrio y zona podría ayudar a detectar datos poco habituales o incompletos antes de incorporarlos a la base.
  • tener cuidado con las viviendas atípicas: el análisis identificó un pequeño grupo de 8 viviendas con áreas construidas extremadamente grandes. No necesariamente son registros incorrectos, pero sería recomendable verificarlos antes de utilizarlos para tomar decisiones sobre la oferta general.
  • Utilizar los grupos encontrados como apoyo para conocer la oferta: los conglomerados permiten diferenciar viviendas más pequeñas y económicas de aquellas más grandes y de mayor valor. Esta clasificación puede servir como punto de partida para organizar la oferta y entender mejor los distintos tipos de inmuebles disponibles.