Informe estadístico de caracterización del mercado inmobiliario de la ciudad de Cali

1. Introducción.

El presente informe, construido a partir de la muestra consolidada una empresa inmobiliaria (contenida en el paquete “paqueteMODELOS” de R) respecto a ubicaciones, precios y características de viviendas en la ciudad de Cali, provee un análisis descriptivo del mercado inmobiliario de la misma, de tal forma que los resultados y discusiones obtenidos puedan servir como un insumo inicial de cara a la toma de decisiones óptimas de la firma en materia de fijación de precios, segmentación espacial de la oferta, estrategias de marketing y personalización de servicios.

Así, este documento hace uso de técnicas descriptivas fundamentales de preparación, análisis y visualización de datos, y revisión de indicadores de centralidad y dispersión de variables críticas para la consecución de sus propósitos.

La siguiente sección presenta el objetivo general y objetivos específicos de este trabajo, la tercera sección realiza una descripción de los métodos empleados para su consecución, presentando los resultados obtenidos en la sección 4. Se realiza una discusión de los resultados en la sección 5, finalizando con la consignación de las conclusiones del informe en la sección 6.

2. Objetivos

2.1 Objetivo general.

Realizar una descripción fiable del comportamiento del mercado inmobiliario de la ciudad de Cali en función de las variables del data set provisto, la cual pueda ser un insumo inicial de cara a la toma de decisiones por parte de la empresa inmobiliaria.

2.2 Objetivos específicos.

  • Realizar un proceso de limpieza y preparación de datos con la mejor retención posible de información fiable del data frame.

  • Proveer una caracterización de los tipos de vivienda de la ciudad en función de sus atributos de mayor relevancia.

  • Proveer una descripción del comportamiento de los precios de las viviendas por cada zona del mercado inmobiliario de la ciudad.

  • Generar recomendaciones en función de los resultados obtenidos.

3. Métodos.

A continuación, se presenta una descripción de los métodos empleados para la preparación, despliegue y visualización de la estructura de datos que fundamenta este informe, así como los indicadores descriptivos obtenidos a partir de la misma.

3.1 Recolección y preparación de datos.

La muestra obtenida por la empresa consistió en el data frame “vivienda” dentro del paquete de R “paqueteMETODOS”, inicialmente, esta muestra contenía 8322 observaciones de 13 variables, las cuales describían las principales características de viviendas en distintas ubicaciones de Cali: área de la propiedad (areaconst), cantidad de baños (banios), estrato de la vivienda (estrato), cantidad de habitaciones (habitaciones), id de la observación (id), latitud (latitud) y longitud (longitud) como coordenadas de geolocalización, zona de la ciudad (zona), barrio (barrio) tipo de vivienda (tipo) cantidad de parqueaderos (parquea), número de piso de la vivienda (piso), y precio de la vivienda en millones de pesos (preciom).

La siguiente tabla muestra un resumen del data frame con sus principales características e indicadores:

Como puede observarse en la descripción por variables, la variable piso presenta sólo 5684 observaciones válidas, la variable parqueaderos presenta 6717 observaciones válidas, y todas las variables presentan 3 observaciones nulas. La presencia de estos datos faltantes se corrobora en la siguiente gráfica.

En este sentido, se procedió de la siguiente forma:

  • Se descartó la variable piso debido a la cantidad elevada de datos faltantes y su ambigüedad, pues no existía claridad sobre si la variable describe el número de piso de la vivienda o su cantidad total de pisos. Además, se consideró que la variable habitaciones (habitaciones) transmite información similar a ésta de forma más útil para propósitos descriptivos.
  • Se eliminaron las observaciones con datos faltantes en la variable parqueaderos, al ser relativamente pocas.
  • Se eliminaron las observaciones donde todas las variables eran nulas.

Nótese que el tratamiento de outliers no se consideró, en tanto el conocimiento del negocio a evaluar implica alta variabilidad en los atributos de viviendas, los cuales se justifican por el funcionamiento del mercado e incluso pueden agruparse correctamente bajo métodos de análisis de conglomerados (clusters), como se apreciará más adelante.

A continuación, se presenta la tabla resumen del data frame resultante de 6717 observaciones para 12 variables, el cual se empleó para este informe.

## df_clean 
## 
##  12  Variables      6717  Observations
## --------------------------------------------------------------------------------
## id 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0     6717        1     4413     2681    622.8   1177.6 
##      .25      .50      .75      .90      .95 
##   2474.0   4474.0   6428.0   7558.4   7931.2 
## 
## lowest :    1    2    4    5    6, highest: 8315 8316 8317 8318 8319
## --------------------------------------------------------------------------------
## zona 
##        n  missing distinct 
##     6717        0        5 
##                                                                            
## Value       Zona Centro   Zona Norte   Zona Oeste Zona Oriente     Zona Sur
## Frequency            64         1287         1098          163         4105
## Proportion        0.010        0.192        0.163        0.024        0.611
## --------------------------------------------------------------------------------
## estrato 
##        n  missing distinct     Info     Mean      Gmd 
##     6717        0        4     0.91     4.83    1.038 
##                                   
## Value          3     4     5     6
## Frequency    684  1641  2522  1870
## Proportion 0.102 0.244 0.375 0.278
## 
## For the frequency table, variable is rounded to the nearest 0
## --------------------------------------------------------------------------------
## preciom 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0      502        1    468.9    334.7    140.0    172.2 
##      .25      .50      .75      .90      .95 
##    248.0    355.0    580.0    910.0   1200.0 
## 
## lowest :   58   70   75   76   78, highest: 1850 1900 1940 1950 1999
## --------------------------------------------------------------------------------
## areaconst 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0      610        1    181.1    136.8     60.0     65.6 
##      .25      .50      .75      .90      .95 
##     86.0    130.0    233.0    357.0    450.0 
## 
## lowest :   30   40   42   43   44, highest: 1440 1500 1586 1600 1745
## --------------------------------------------------------------------------------
## parqueaderos 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0       10    0.846    1.835    1.039        1        1 
##      .25      .50      .75      .90      .95 
##        1        2        2        3        4 
##                                                                       
## Value          1     2     3     4     5     6     7     8     9    10
## Frequency   3155  2475   520   384    68    68    18    17     4     8
## Proportion 0.470 0.368 0.077 0.057 0.010 0.010 0.003 0.003 0.001 0.001
## 
## For the frequency table, variable is rounded to the nearest 0
## --------------------------------------------------------------------------------
## banios 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0       11    0.937    3.255     1.48        2        2 
##      .25      .50      .75      .90      .95 
##        2        3        4        5        6 
##                                                                             
## Value          0     1     2     3     4     5     6     7     8     9    10
## Frequency     15   199  2230  1757  1288   804   278    93    36    12     5
## Proportion 0.002 0.030 0.332 0.262 0.192 0.120 0.041 0.014 0.005 0.002 0.001
## 
## For the frequency table, variable is rounded to the nearest 0
## --------------------------------------------------------------------------------
## habitaciones 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0       11     0.86    3.611    1.297        2        2 
##      .25      .50      .75      .90      .95 
##        3        3        4        5        6 
##                                                                             
## Value          0     1     2     3     4     5     6     7     8     9    10
## Frequency     23    44   648  3373  1510   572   245   126    77    63    36
## Proportion 0.003 0.007 0.096 0.502 0.225 0.085 0.036 0.019 0.011 0.009 0.005
## 
## For the frequency table, variable is rounded to the nearest 0
## --------------------------------------------------------------------------------
## tipo 
##        n  missing distinct 
##     6717        0        2 
##                                   
## Value      Apartamento        Casa
## Frequency         4231        2486
## Proportion        0.63        0.37
## --------------------------------------------------------------------------------
## barrio 
##        n  missing distinct 
##     6717        0      367 
## 
## lowest : 20 de julio      3 de julio       acopi            aguablanca       aguacatal       
## highest: zona norte los   zona oeste       zona oriente     zona residencial zona sur        
## --------------------------------------------------------------------------------
## longitud 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0     2462        1   -76.53  0.01803   -76.55   -76.55 
##      .25      .50      .75      .90      .95 
##   -76.54   -76.53   -76.52   -76.51   -76.50 
## 
## lowest : -76.5892 -76.5888 -76.5874 -76.5873 -76.5853
## highest: -76.465  -76.4648 -76.4644 -76.464  -76.463 
## --------------------------------------------------------------------------------
## latitud 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0     3100        1    3.415  0.04927    3.349    3.363 
##      .25      .50      .75      .90      .95 
##    3.379    3.412    3.451    3.476    3.486 
## 
## lowest : 3.333   3.33308 3.33324 3.33333 3.33367
## highest: 3.49578 3.49584 3.49591 3.49684 3.4977 
## --------------------------------------------------------------------------------

3.2 Análisis descriptivo

Para el ejercicio de análisis descriptivo, se procedió a emplear las siguientes técnicas analíticas, con el objetivo de extraer los resultados de mayor valor haciendo el uso más eficiente del data frame:

  • Se inició empleando análisis de componentes principales (PCA) con el fin de identificar las variables numéricas que retienen la mayor cantidad de información con respecto al comportamiento del mercado inmobiliario provisto por la muestra.

  • Posterior a la identificación de componentes de mayor relevancia, se procedió a realizar análisis de conglomerados (clusters) con el fin de proveer un agrupamiento de las viviendas y establecer nichos de mercado para la empresa, los cuales fueron caracterizados de forma espacial.

  • Finalmente, se empleó análisis de correspondencias, con el fin de describir la relación de correspondencia entre los nichos de mercado hallados y los estratos socioeconómicos de los clientes potenciales.

4. Resultados.

En esta sección se presenta el despliegie metodologógico y los resultados obtenidos a partir de las herramientas seleccionadas para el análisis del mercado inmobiliario de la ciudad de Cali en función del data frame preparado. Este análisis descriptivo parte de la revisión de las características más relevantes de las viviendas, siendo éstas sus precios en millones de pesos, la cantidad de área construida en la vivienda, su ubicación, y su estrato, en tanto estas variables reúnen la mejor información respecto al resto de atributos de las viviendas.

4.1. Análisis por PCA.

Inicialmente, se procede con la selección de los atributos numéricos de la muestra, siendo éstos preciom, areaconst, parqueaderos, banios, habitaciones, longitud y latitud. Éstas variables se toman como un subconjunto del dataset empleado, de cara a la realización de análisis de componentes principales (PCA).

## df_numeric 
## 
##  7  Variables      6717  Observations
## --------------------------------------------------------------------------------
## preciom 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0      502        1    468.9    334.7    140.0    172.2 
##      .25      .50      .75      .90      .95 
##    248.0    355.0    580.0    910.0   1200.0 
## 
## lowest :   58   70   75   76   78, highest: 1850 1900 1940 1950 1999
## --------------------------------------------------------------------------------
## areaconst 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0      610        1    181.1    136.8     60.0     65.6 
##      .25      .50      .75      .90      .95 
##     86.0    130.0    233.0    357.0    450.0 
## 
## lowest :   30   40   42   43   44, highest: 1440 1500 1586 1600 1745
## --------------------------------------------------------------------------------
## parqueaderos 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0       10    0.846    1.835    1.039        1        1 
##      .25      .50      .75      .90      .95 
##        1        2        2        3        4 
##                                                                       
## Value          1     2     3     4     5     6     7     8     9    10
## Frequency   3155  2475   520   384    68    68    18    17     4     8
## Proportion 0.470 0.368 0.077 0.057 0.010 0.010 0.003 0.003 0.001 0.001
## 
## For the frequency table, variable is rounded to the nearest 0
## --------------------------------------------------------------------------------
## banios 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0       11    0.937    3.255     1.48        2        2 
##      .25      .50      .75      .90      .95 
##        2        3        4        5        6 
##                                                                             
## Value          0     1     2     3     4     5     6     7     8     9    10
## Frequency     15   199  2230  1757  1288   804   278    93    36    12     5
## Proportion 0.002 0.030 0.332 0.262 0.192 0.120 0.041 0.014 0.005 0.002 0.001
## 
## For the frequency table, variable is rounded to the nearest 0
## --------------------------------------------------------------------------------
## habitaciones 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0       11     0.86    3.611    1.297        2        2 
##      .25      .50      .75      .90      .95 
##        3        3        4        5        6 
##                                                                             
## Value          0     1     2     3     4     5     6     7     8     9    10
## Frequency     23    44   648  3373  1510   572   245   126    77    63    36
## Proportion 0.003 0.007 0.096 0.502 0.225 0.085 0.036 0.019 0.011 0.009 0.005
## 
## For the frequency table, variable is rounded to the nearest 0
## --------------------------------------------------------------------------------
## longitud 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0     2462        1   -76.53  0.01803   -76.55   -76.55 
##      .25      .50      .75      .90      .95 
##   -76.54   -76.53   -76.52   -76.51   -76.50 
## 
## lowest : -76.5892 -76.5888 -76.5874 -76.5873 -76.5853
## highest: -76.465  -76.4648 -76.4644 -76.464  -76.463 
## --------------------------------------------------------------------------------
## latitud 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     6717        0     3100        1    3.415  0.04927    3.349    3.363 
##      .25      .50      .75      .90      .95 
##    3.379    3.412    3.451    3.476    3.486 
## 
## lowest : 3.333   3.33308 3.33324 3.33333 3.33367
## highest: 3.49578 3.49584 3.49591 3.49684 3.4977 
## --------------------------------------------------------------------------------

El análisis PCA realizado implica la construcción de una matriz compuesta por combinaciones lineales de los atributos numéricos seleccionados, la cual reorganiza la estructura de correlación de estos y reduce la dimensionalidad de los datos al retener cerca del 64,7% de la variabilidad observada en sus dos componentes principales (PC1 y PC2), como se aprecia en el siguiente despliegue:

## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
## Standard deviations (1, .., p=7):
## [1] 1.8282744 1.0886642 0.9369016 0.8520510 0.6015479 0.5619836 0.4367632
## 
## Rotation (n x k) = (7 x 7):
##                      PC1         PC2         PC3         PC4         PC5
## preciom       0.46490903  0.12638995  0.25162286 -0.28074620 -0.33791941
## areaconst     0.46820146 -0.15988582 -0.01999282 -0.07147402 -0.49831147
## parqueaderos  0.43095210  0.10274462  0.16576439 -0.42485945  0.73957157
## banios        0.47774528 -0.09236027 -0.11235756  0.14096304 -0.06205145
## habitaciones  0.33389567 -0.43406939 -0.39415218  0.52445159  0.28521120
## longitud     -0.18073560 -0.61877477 -0.37990188 -0.64641161 -0.05518379
## latitud      -0.08083967 -0.60669332  0.77233592  0.15099489  0.04784344
##                      PC6         PC7
## preciom      -0.23478684 -0.67560217
## areaconst     0.61565035  0.34982280
## parqueaderos  0.18563847  0.11963571
## banios       -0.70075584  0.48561827
## habitaciones  0.14475940 -0.40913484
## longitud     -0.13303937 -0.03917002
## latitud      -0.04092237  0.04606840

Ahora, la estructura revelada por el análisis PCA se resume en el siguiente gráfico:

El gráfico indica que PC1, el cual contiene el 47,8% de la variabilidad de los datos, se halla principalmente explicado por las variables de área construida, precios, y cntidad de baños (debido la orientación horizontal y el tamaño de sus vectores), además, el ángulo angosto entre estas variables indica su alta correlación en el dataset original. Este es un resultado esperado, en tanto estas variables suelen ser los parámetros esenciales en la elección de compra de viviendas. Además, se obtiene que PC2 se halla principalmente explicado por las variables de longitud y latitud, lo que nos dice que la ubicación de la vivienda es el siguiente factor relevante para la descripción del comportamiento del mercado inmobiliario.

Los siguentes casos específicos de viviendas tomadas del dataset original amplían la explicación realizada:

##          preciom areaconst parqueaderos banios habitaciones  longitud latitud
## Casa 006     240     87.00            1      3            3 -76.51700 3.36971
## Casa 968    1600   1050.00            6      7            6 -76.53999 3.35878
## Casa 098     950    195.25            2      4            3 -76.55396 3.45092
## Casa 137     250    300.00            1      5            9 -76.47897 3.45313

Luego se precede a ubicar estas observaciones en el plano de los componentes PC1 y PC2:

El precio y área superiores de la casa 968 con respecto a la casa 006 (puntos rojos) es congruente con el incremento de PC1 en la dirección izquierda-derecha. Así como el incremento absoluto de las coordenadas longitud y latitud observado entre las casas 098 y 137 es congruente con el incremento de PC2 en la dirección arriba-abajo.

De esta manera, es pertinente centralizar el análisis en la variables precio, área construida y ubicación de las viviendas.

4.2 Análisis de conglomerados (Clusters):

Dada la exploración anterior, se procedió a realizar un análisis de clusters, con el fin de identificar los potenciales nichos de mercado para la empresa en función de las variables centrales de precios y área construida. Inicialmente, se consideró establecer clusters de la relación precio/área para cada zona utilizando la variable nominal zona del dataset original, sin embargo, al graficar los clusters obtenidos para cada zona por separado, se notó que el etiquetado de las variables por zona puede ser errado (se observaron bastantes viviendas por fuera de las zonas planteadas, especialmente en la zona Sur), como puede observarse en el Anexo.

En este sentido, se procedió a realizar el análisis de conglomerados jerárquicos en función de distancias euclideanas a través del método complete, al considerar los precios de las viviendas y la transformación unidimensional por valores Z de Morton. Esta transformación, alojada en la variable z_order_vals permite preservar la información de localización de las coordenadas longitud y latitud para un contraste con la variables de precios, obteniéndose los siguientes resultados:

Nótese que el índice Silhouette Width denota un beneficio similar entre elegir 3 clústeres y elegir 8 clústeres. Se decidió elegir 8 clústeres, con el fin de proveer mayor especificidad a la empresa en cuanto a la variabilidad de los nichos de mercado existentes en la ciudad de Cali.

A continuación, se despliegan los nichos de mercado identificados de dos formas, se presenta una tabla con las medidas de tendencia central en cuanto al precio y área construida de cada nicho de mercado, y se despliega la ubicación de las viviendas pertenecientes a cada nicho en un mapa interactivo de la ciudad de Cali, con el fin de especificar las tendencias espaciales de su mercado inmobiliario.

## # A tibble: 8 × 13
##   cluster count_preciom mean_preciom sd_preciom min_preciom max_preciom
##   <fct>           <int>        <dbl>      <dbl>       <dbl>       <dbl>
## 1 1                2429         294.       107.          58         590
## 2 2                2376         311.       119.          70         600
## 3 3                 611         758.       131.         540        1015
## 4 4                 803         681.       160.         400        1100
## 5 5                 275        1246.       107.        1050        1500
## 6 6                  28        1751.       105.        1600        1950
## 7 7                  79        1285.       135.        1050        1550
## 8 8                 116        1674.       143.        1450        1999
##   median_preciom count_areaconst mean_areaconst sd_areaconst min_areaconst
##            <dbl>           <int>          <dbl>        <dbl>         <dbl>
## 1            285            2429           126.         79.1            42
## 2            300            2376           134.         93.8            30
## 3            750             611           278.        143.             90
## 4            650             803           266.        137.             84
## 5           1230             275           376.        171.            153
## 6           1800              28           518.        229.            292
## 7           1280              79           444.        211.            194
## 8           1650             116           488.        276.            224
##   max_areaconst median_areaconst
##           <dbl>            <dbl>
## 1           605              99 
## 2          1745             105 
## 3          1000             240 
## 4          1188             229 
## 5          1100             320 
## 6          1092             450 
## 7          1250             431 
## 8          1600             432.

Evaluando a través de los promedios del precio de las viviendas mean_preciom y su área construida mean_areaconst, fue posible establecer 8 nichos para el mercado inmobiliario de la ciudad de Cali en función de la relación entre sus precios y ubicación, de la siguiente forma:

  • Nicho 1 (2429 casas): precio medio de 293,8 millones de pesos y área media de 126 metros cuadrados.

  • Nicho 2 (2376 casas): precio medio de 310,8 millones de pesos y área media de 133 metros cuadrados.

  • Nicho 3 (611 casas): precio medio de 757,6 millones de pesos y área media de 277 metros cuadrados.

  • Nicho 4 (803 casas): precio medio de 681 millones de pesos y área media de 265 metros cuadrados.

  • Nicho 5 (275 casas): precio medio de 1245,6 millones de pesos y área media de 375 metros cuadrados.

  • Nicho 6 (28 casas): precio medio de 1751 millones de pesos y área media de 517 metros cuadrados.

  • Nicho 7 (79 casas): precio medio de 1285 millones de pesos y área media de 444 metros cuadrados.

  • Nicho 8 (116 casas): precio medio de 1674 millones de pesos y área media de 487 metros cuadrados.

Como puede apreciarse, los nichos 1 y 2 acaparan las mayoría de las observaciones de la muestra empleada, consistiendo en el conjunto de viviendas con precios más accesibles, así como cantidades de área más pequeñas. En este sentido, se puede afirmar que los nichos 1 y 2 caracterizan el segmento promedio de la población, al cual se debería apuntar bajo estrategias de precios y servicios de mayor accesibilidad. Los nichos restantes tienden a incrementar los precios de las viviendas, siendo esto consistente con mayores cantidades de área construida, es decir, a partir del nicho 3 la empresa puede empezar a considerar estructurar su operación desde la oferta de viviendas con amenidades de mayor lujo.

La información anterior es congruente con la distribución espacial de los nichos determinados, de tal manera que es posible ubicar viviendas de mayor precio y área construida principalmente en la zona oeste, y, especialmente, en la zona sur: los nichos 1 y 2 (colores amarillo y naranja pálido) se hallan casi que uniformemente distribuidos por toda la ciudad, mientras que los nichos 3 a 8 poseen densidad casi que esclusivamente en las zonas oeste y sur (se puede denotar una muy leve presencia de estos nichos en las zonas oriente y centro), siendo esta última donde son mas comunes. Nótese que la descripción anterior refuerza la idea general que se posee sobre la distribución espacial de las viviendas en la ciudad de Cali, siendo ésta que los sectores de mayor prominencia se hallan principalmente en las zonas sur y oeste.

4.3 Análisis de correspondencia.

El análisis llevado a cabo anteriormente permitió determinar un conjunto de nichos de mercado y sus expresiones cuantitativas en términos del precio y área construida de las viviendas, siendo esto un insumo importante para la toma de decisiones de la empresa. Además, la construcción del despliegue visual de los clusters obtenidos en el mapa de la ciudad de Cali otorgó una idea clara con respecto a la distribución espacial del mercado inmobiliario. Sin embargo, esta hipótesis requiere una verificación estadística, la cual es posible gracias al ejercicio del método de análisis de correspondencia, al contrastar estadísticamente la correlación entre la variable Estrato, la cual denota una aproximación al poder adquisitivo de la población, y la variable categórica cluster obtenida del ejercicio anterior.

La aplicación del método de análisis de correspondencia inicia con la obtención de la tabla de contingencia entre ambas variables, la cual otorga la frecuencia absoluta de sus ocurrencias simultáneas. Sobre esta tabla de contingencia se calcula el estadístico Chi-cuadrado y se aplica la prueba de hipótesis de Pearson, en la cual se obtiene un p-valor cercano a cero, lo cual implica el rechazo de la hipótesis nula de independencia entre las dos variables.

##    
##     Estrato3 Estrato4 Estrato5 Estrato6
##   1      310      837     1032      250
##   2      350      698     1023      305
##   3        2       34      153      422
##   4       21       65      255      462
##   5        1        5       32      237
##   6        0        0        2       26
##   7        0        1       13       65
##   8        0        1       12      103
## 
##  Pearson's Chi-squared test
## 
## data:  tablacont
## X-squared = 2486.6, df = 21, p-value < 2.2e-16

Desde esta prueba de hipótesis, se procede al análisis de la matriz de covarianza diagonalizada entre estrato y cluster, la cual induce dos dimensiones independientes que retienen la variabilidad de las observaciones de estos atributos del dataset. A partir de esta matriz es posible graficar la correlación entre las instancias de los atributos analizados:

De esta manera, se obtiene un resultado congruente con el análisis espacial realizado en la sección anterior. Inicialmente, se tiene que la orientación de las instancias de ambas variables se da sobre la dimensión principal de la matriz Dim 1 (progresión horizontal), la cual contiene el 98,6% de la variabilidad de la observaciones. Además, se tiene como resultado principal que los nichos de mercado 1 y 2, los cuales acaparan la mayoría de las observaciones de la muestra, se hallan principalmente correlacionados con los estratos 3, 4 y 5, es decir, las viviendas asociadas a los nichos con menores precios medios y áreas construidas suelen hallarse habitadas por poblaciones en los estratos 3 a 5. Nótese que la asociación de los estratos 4 y 5 con los clusters 1 y 2 puede justificarse también con la alta variabilidad en las variables preciom y areaconst de estos clusters (véase la tabla con estadísticos descriptivos de cada nicho).

Adicionalmente, el gráfico también denota cómo los nichos 3 a 8, asociados a viviendas de mayor lujo, se hallan correlacionados principalmente con el estrato 6, es decir, el segmento de población que se presume con mayor poder adquisitivo de entre toda la muestra (para una revisión sobre la validez del ejercicio de análisis de correspondencia, véase el Anexo A).

Finalmente, al tener una idea concisa de cómo se distribuyen las viviendas desde sus características principales con respecto a los estratos socioeconómicos al determinar la correspondencia de éstos con los nichos de mercado determinados, es posible extender esta conclusión a los tipos de vivienda, a través del siguiente gráfico de barras doble:

Así, puede afirmarse que más del 40% de las viviendas representando el comportamiento del mercado inmobiliario, asociadas a los nichos de mercado 1 y 2, son apartamentos. A su vez, es notable el hecho de que los apartamentos componen aproximadamente dos tercios de los nichos de mercado mayoritarios, de tal forma que la proporción de casas tiende a equipararse e incluso superar a la de apartamentos en los nichos de mercado de mayores precios y área en promedio.

5. Discusión.

En esta sección se presenta una discusión alrededor de los resultados hallados, sus potenciales aplicaciones, y las limitaciones del ejercicio realizado.

El análisis del data frame, en general, determinó una marcada predominancia, en promedio, de casas con precios de alrededor de los 310 millones de pesos y cantidades de área de alrededor de los 133 metros cuadrados. En consonancia con este resultado principal, se pudo concluir que la gran mayoría de las viviendas se hallan habitadas por los estratos 3 a 5, lo cual es una consecuencia de la alta variabilidad de los precios de las viviendas en este segmento de la población (véanse las medidas de disérsión de los nichos de mercado 1 y 2). Además, fue posible proyectar esta caracterización por conglomerados en la distribución espacial del mercado inmobiliario de la ciudad de Cali, obteniendo un mapeo confiable de la asignación de grupos por precios de vivienda, de lo cual emerge el corolario de que las viviendas con mayor lujo, principalmente habitadas por el estrato 6, suelen ubicarse en las zonas sur y oeste de la ciudad.

Lo anterior es el conjunto de conclusiones principales de la caracterización jerárquica realizada para el mercado inmobiliario caleño desde el dataset disponible. De esta forma, es posible afirmar que con los insumos de los que se partió se obtuvo un buen rastreo cuantiativo y gráfico de las propiedades esenciales de este mercado.

En términos metodológicos, este resultado fue posible gracias a la aplicación del análisis por componentes principales (PCA), el cual permitió reducir la dimensionalidad del análisis al centralizarlo en función de los precios de las viviendas, las cantidades de área y la ubicación de las viviendas en función de sus coordenadas de geolocalización. Además, el análisis de clustering permitió extraer de la muestra los grupos de mayor representatividad del mercado inmobiliario, obteniéndose un esquema que puede significar una base cuantitativa y gráfica de alta fiabilidad para el desarrollo de estrategias de distinta índole para la empresa. Nótese que estas conclusiones también se hallan reforzadas por las implicaciones del análisis de correspondencia, las cuales permitieron evaluar el papel de la estratificación social en la distribución espacial del mercado inmobiliario, relacionadas estrechamente con la distribución de los tipos de vivienda por cada cluster.

En este sentido, es notorio que la recomendación principal desde los resultados obtenidos es la estructuración de operaciones por parte de la empresa en función de los nichos de mercado hallados, buscando métodos de discriminación y segmentación para la fijación de precios, la optimización de costos y el despliegue informacional y organizacional de las ofertas. Nótese que, a priori, lo anterior se identifica con la idea de que por encima de los nichos 1 y 2 se debe apuntar a la oferta de viviendas de mayor precio, sin embargo, los 8 nichos de mercado definidos pueden representar estrategias independientes que, si bien se hallan fundamentadas en los precios y área como componentes principales, se pueden profundizar en función del resto de atributos del dataset agrupado, y pueden desembocar en la personalización de servicios como raíz de éxito de la empresa.

Finalmente, si bien el análisis descriptivo obtenido otorga una buena idea respecto al comportamiento del mercado inmobiliario en la ciudad, se recomienda validar estos resultados a través de la construcción de estimadores robustos para las variables relevantes, dependiendo de los atributos de interés en futuros ejercicios de análisis predictivo y prescriptivo, lo cual elevaría el nivel del ejercicio realizado al campo de la modelación y estadística inferencial.

6. Conclusiones.

A continuación, se presentan la conclusiones de mayor relevancia respecto al informe provisto.

  • En general, se logró proveer una buena descripción del comportamiento inmobiliario de la ciudad de Cali en función del data frame utilizado, obteniendo caracterizaciones espaciales respecto a las viviendas, sus atributos, y niveles de precios.

  • Si bien la caracterización obtenida muestra patrones estables, debe mencionarse que algunas zonas (evaluadas desde los nichos de mercado) presentaron muy pocas observaciones y comportamientos bastante sesgados hacia patrones poco regulares, tales como precios elevados o altas cantidades de área construida. Si bien esto puede atribuirse a las características del mercado inmobiliario, se sugiere un análisis extendido bajo fuentes complementarias para su profundización, si es que éste es del interés de la empresa.

  • De cara a ventas y arrendamientos, la mejor información pudo hallarse en las zonas Sur y Oeste, las cuales determinaron nichos de mercado con tipos y características de alta especificidad para las viviendas, particularmente pensando en viviendas con amenidades y lujos por encima del promedio.

  • La determinación de clusters o nichos de mercado en función de precios y la geolocalización de las viviendas representa una herramienta descriptiva muy valiosa para el desarrollo de estrategias de la empresa con grados de personalización para distintos tipos de clientes. Este insumo representa un importante punto de partida para la consecución, no sólo de estrategias de precios, sino de marketing y decisiones de inversión en general para la empresa.

  • Debe hacerse énfasis en que el análisis descriptivo sólo es el primer paso en la metodología estadística, entonces, de cara a la toma de decisiones óptimas por parte de la empresa, es imprescindible corroborar las conclusiones obtenidas a través de estimadores robustos de variables de interés específicas, las cuales deben implicar modelos puntuales para su contraste.

Anexos.

A. Validez del análisis de correspondencia.

Matriz de eigenvalues y varianza acumulada.

valores_prop <-resultados_ac$eig
valores_prop
##        eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.365021936             98.6022035                          98.60220
## dim 2 0.003029798              0.8184297                          99.42063
## dim 3 0.002144796              0.5793668                         100.00000

Varianza acumulada mayoritaria en la dimensión 1 de la matriz.

library(factoextra)

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

B. Análisis por conglomerados discriminados por la variables categórica Zona.

Nótese el alto nivel de dispersión de las viviendas con respecto a las zonas que les fueron etiquetadas

Zona Centro.

#Cluster analysis by zone

#Zona Centro
zonacentro <- subset(df_clean, df_clean$zona == "Zona Centro")
zonacentro
## # A tibble: 64 × 14
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1  5298 Zona …       3     650      240             2      4            4 Casa 
##  2  5608 Zona …       3     295      200             1      5            9 Casa 
##  3  4408 Zona …       3     120       84             1      2            3 Apar…
##  4  3355 Zona …       4    1100      217             1      3            1 Casa 
##  5  2879 Zona …       3     148       86             1      2            3 Casa 
##  6  2991 Zona …       3     215       74             2      1            2 Casa 
##  7  3180 Zona …       3     340      240             1      4            7 Casa 
##  8  2873 Zona …       3     270      143.            1      4            7 Casa 
##  9  2892 Zona …       3     270      143.            1      4            7 Casa 
## 10  4411 Zona …       3     350      340             1      4           10 Casa 
## # ℹ 54 more rows
## # ℹ 5 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   z_order_vals <dbl>, cluster <fct>
#select precio and areaconst columns
P_A_Centro <- zonacentro %>%
  select(preciom, areaconst)

#Standardizing variables
P_A_Centro_Z =scale(P_A_Centro)
P_A_Centro_Z = as.data.frame(P_A_Centro_Z)

#install.packages('tidyverse')

library(tidyverse)
# distancia euclidiana
dist_PACentro <- dist(P_A_Centro_Z, method = 'euclidean')

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

#install.packages('cluster')

library(cluster)
sil_width <- sapply(2:10, function(k) {
  pam(P_A_Centro_Z, k)$silinfo$avg.width
})

plot(2:10, sil_width, type = "b", pch = 19, frame = FALSE, 
     xlab = "Number of clusters K",
     ylab = "Average Silhouette Width")

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

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


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

#install.packages("leaflet")
#install.packages("tmap")

library(leaflet)
library(dplyr)

# Ensure that 'zonacentro' contains 'longitud', 'latitud', and 'cluster' columns
zonacentro <- zonacentro %>%
  mutate(longitud = as.numeric(longitud),
         latitud = as.numeric(latitud),
         cluster = as.factor(cluster_assigments)) %>%
  filter(!is.na(longitud) & !is.na(latitud))

# Create a color palette for the clusters
palette <- colorFactor(palette = c("blue", "orange"), domain = zonacentro$cluster)

# Plot the map using leaflet
leaflet(data = zonacentro) %>%
  addTiles() %>%  # Add default OpenStreetMap tiles
  addCircleMarkers(
    ~longitud, ~latitud,
    color = ~palette(cluster),  # Color points by cluster
    radius = 8,
    popup = ~paste("Cluster:", cluster, "<br>",
                   "Price:", preciom, "<br>",
                   "Area:", areaconst)
  ) %>%
  addLegend(
    position = "bottomright",
    pal = palette,
    values = ~cluster,
    title = "Conglomerados de viviendas por similitud en relación precio/área (Zona Centro)",
    opacity = 2
  )
#descriptive stats table

# Compute descriptive statistics per cluster
descriptive_stats <- zonacentro %>%
  group_by(cluster) %>%
  summarise(
    count_preciom = n(),
    mean_preciom = mean(preciom, na.rm = TRUE),
    sd_preciom = sd(preciom, na.rm = TRUE),
    min_preciom = min(preciom, na.rm = TRUE),
    max_preciom = max(preciom, na.rm = TRUE),
    median_preciom = median(preciom, na.rm = TRUE),
    
    count_areaconst = n(),
    mean_areaconst = mean(areaconst, na.rm = TRUE),
    sd_areaconst = sd(areaconst, na.rm = TRUE),
    min_areaconst = min(areaconst, na.rm = TRUE),
    max_areaconst = max(areaconst, na.rm = TRUE),
    median_areaconst = median(areaconst, na.rm = TRUE)
  )

# Print the descriptive statistics table
print(descriptive_stats)
## # A tibble: 2 × 13
##   cluster count_preciom mean_preciom sd_preciom min_preciom max_preciom
##   <fct>           <int>        <dbl>      <dbl>       <dbl>       <dbl>
## 1 1                   8         655.      211.          450        1100
## 2 2                  56         289.       84.9         120         450
## # ℹ 7 more variables: median_preciom <dbl>, count_areaconst <int>,
## #   mean_areaconst <dbl>, sd_areaconst <dbl>, min_areaconst <dbl>,
## #   max_areaconst <dbl>, median_areaconst <dbl>

Zona Norte.

#Cluster analysis by zone

#Zona Norte
zonanorte <- subset(df_clean, df_clean$zona == "Zona Norte")
zonanorte
## # A tibble: 1,287 × 14
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1  1212 Zona …       5     260        90            1      2            3 Apar…
##  2  1724 Zona …       5     240        87            1      3            3 Apar…
##  3  2326 Zona …       4     220        52            2      2            3 Apar…
##  4  4386 Zona …       5     310       137            2      3            4 Apar…
##  5  1209 Zona …       5     320       150            2      4            6 Casa 
##  6  1592 Zona …       5     780       380            2      3            3 Casa 
##  7  4460 Zona …       4     625       355            3      5            5 Casa 
##  8  6081 Zona …       5     750       237            2      6            6 Casa 
##  9  7497 Zona …       6     520        98            2      2            2 Apar…
## 10  7824 Zona …       4     600       160            1      4            5 Casa 
## # ℹ 1,277 more rows
## # ℹ 5 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   z_order_vals <dbl>, cluster <fct>
#select precio and areaconst columns
P_A_Norte <- zonanorte %>%
  select(preciom, areaconst)

#Standardizing variables
P_A_Norte_Z =scale(P_A_Norte)
P_A_Norte_Z = as.data.frame(P_A_Norte_Z)

#install.packages('tidyverse')

library(tidyverse)
# distancia euclidiana
dist_PANorte <- dist(P_A_Norte_Z, method = 'euclidean')

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

#install.packages('cluster')

library(cluster)
sil_width <- sapply(2:10, function(k) {
  pam(P_A_Norte_Z, k)$silinfo$avg.width
})

plot(2:10, sil_width, type = "b", pch = 19, frame = FALSE, 
     xlab = "Number of clusters K",
     ylab = "Average Silhouette Width")

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

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


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

#install.packages("leaflet")
#install.packages("tmap")

library(leaflet)
library(dplyr)

# Ensure that 'zonanorte' contains 'longitud', 'latitud', and 'cluster' columns
zonanorte <- zonanorte %>%
  mutate(longitud = as.numeric(longitud),
         latitud = as.numeric(latitud),
         cluster = as.factor(cluster_assigments)) %>%
  filter(!is.na(longitud) & !is.na(latitud))

# Create a color palette for the clusters
palette <- colorFactor(palette = c("blue", "orange"), domain = zonanorte$cluster)

# Plot the map using leaflet
leaflet(data = zonanorte) %>%
  addTiles() %>%  # Add default OpenStreetMap tiles
  addCircleMarkers(
    ~longitud, ~latitud,
    color = ~palette(cluster),  # Color points by cluster
    radius = 5,
    popup = ~paste("Cluster:", cluster, "<br>",
                   "Price:", preciom, "<br>",
                   "Area:", areaconst)
  ) %>%
  addLegend(
    position = "bottomright",
    pal = palette,
    values = ~cluster,
    title = "Conglomerados de viviendas por similitud en relación precio/área (Zona Norte)",
    opacity = 2
  )
#descriptive stats table

# Compute descriptive statistics per cluster
descriptive_stats <- zonanorte %>%
  group_by(cluster) %>%
  summarise(
    count_preciom = n(),
    mean_preciom = mean(preciom, na.rm = TRUE),
    sd_preciom = sd(preciom, na.rm = TRUE),
    min_preciom = min(preciom, na.rm = TRUE),
    max_preciom = max(preciom, na.rm = TRUE),
    median_preciom = median(preciom, na.rm = TRUE),
    
    count_areaconst = n(),
    mean_areaconst = mean(areaconst, na.rm = TRUE),
    sd_areaconst = sd(areaconst, na.rm = TRUE),
    min_areaconst = min(areaconst, na.rm = TRUE),
    max_areaconst = max(areaconst, na.rm = TRUE),
    median_areaconst = median(areaconst, na.rm = TRUE)
  )

# Print the descriptive statistics table
print(descriptive_stats)
## # A tibble: 2 × 13
##   cluster count_preciom mean_preciom sd_preciom min_preciom max_preciom
##   <fct>           <int>        <dbl>      <dbl>       <dbl>       <dbl>
## 1 1                1285         370.       229.          70        1940
## 2 2                   2         510        198.         370         650
## # ℹ 7 more variables: median_preciom <dbl>, count_areaconst <int>,
## #   mean_areaconst <dbl>, sd_areaconst <dbl>, min_areaconst <dbl>,
## #   max_areaconst <dbl>, median_areaconst <dbl>

Zona Sur.

#Cluster analysis by zone

#Zona Sur
zonasur <- subset(df_clean, df_clean$zona == "Zona Sur")
zonasur
## # A tibble: 4,105 × 14
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1  5992 Zona …       4     400       280            3      5            3 Casa 
##  2  5098 Zona …       4     290        96            1      2            3 Apar…
##  3   698 Zona …       3      78        40            1      1            2 Apar…
##  4  8199 Zona …       6     875       194            2      5            3 Apar…
##  5  5157 Zona …       3     500       354            1      2            4 Casa 
##  6  5156 Zona …       3     420       369            1      5            5 Casa 
##  7  6975 Zona …       4     220        75            1      2            3 Apar…
##  8  5615 Zona …       3     210        72            2      2            3 Apar…
##  9  7396 Zona …       3     115        58            1      2            2 Apar…
## 10  1126 Zona …       5     380       151            1      3            3 Casa 
## # ℹ 4,095 more rows
## # ℹ 5 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   z_order_vals <dbl>, cluster <fct>
#select precio and areaconst columns
P_A_Sur <- zonasur %>%
  select(preciom, areaconst)

#Standardizing variables
P_A_Sur_Z =scale(P_A_Sur)
P_A_Sur_Z = as.data.frame(P_A_Sur_Z)

#install.packages('tidyverse')

library(tidyverse)
# distancia euclidiana
dist_PASur <- dist(P_A_Sur_Z, method = 'euclidean')

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

#install.packages('cluster')

library(cluster)
sil_width <- sapply(2:10, function(k) {
  pam(P_A_Sur_Z, k)$silinfo$avg.width
})

plot(2:10, sil_width, type = "b", pch = 19, frame = FALSE, 
     xlab = "Number of clusters K",
     ylab = "Average Silhouette Width")

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

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


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

#install.packages("leaflet")
#install.packages("tmap")

library(leaflet)
library(dplyr)

# Ensure that 'zonasur' contains 'longitud', 'latitud', and 'cluster' columns
zonasur <- zonasur %>%
  mutate(longitud = as.numeric(longitud),
         latitud = as.numeric(latitud),
         cluster = as.factor(cluster_assigments)) %>%
  filter(!is.na(longitud) & !is.na(latitud))

# Create a color palette for the clusters
palette <- colorFactor(palette = c("blue", "orange"), domain = zonasur$cluster)

# Plot the map using leaflet
leaflet(data = zonasur) %>%
  addTiles() %>%  # Add default OpenStreetMap tiles
  addCircleMarkers(
    ~longitud, ~latitud,
    color = ~palette(cluster),  # Color points by cluster
    radius = 8,
    popup = ~paste("Cluster:", cluster, "<br>",
                   "Price:", preciom, "<br>",
                   "Area:", areaconst)
  ) %>%
  addLegend(
    position = "bottomright",
    pal = palette,
    values = ~cluster,
    title = "Conglomerados de viviendas por similitud en relación precio/área (Zona Sur)",
    opacity = 2
  )
#descriptive stats table

# Compute descriptive statistics per cluster
descriptive_stats <- zonasur %>%
  group_by(cluster) %>%
  summarise(
    count_preciom = n(),
    mean_preciom = mean(preciom, na.rm = TRUE),
    sd_preciom = sd(preciom, na.rm = TRUE),
    min_preciom = min(preciom, na.rm = TRUE),
    max_preciom = max(preciom, na.rm = TRUE),
    median_preciom = median(preciom, na.rm = TRUE),
    
    count_areaconst = n(),
    mean_areaconst = mean(areaconst, na.rm = TRUE),
    sd_areaconst = sd(areaconst, na.rm = TRUE),
    min_areaconst = min(areaconst, na.rm = TRUE),
    max_areaconst = max(areaconst, na.rm = TRUE),
    median_areaconst = median(areaconst, na.rm = TRUE)
  )

# Print the descriptive statistics table
print(descriptive_stats)
## # A tibble: 2 × 13
##   cluster count_preciom mean_preciom sd_preciom min_preciom max_preciom
##   <fct>           <int>        <dbl>      <dbl>       <dbl>       <dbl>
## 1 1                4094         446.       321.          78        1900
## 2 2                  11        1635.       148.        1450        1900
## # ℹ 7 more variables: median_preciom <dbl>, count_areaconst <int>,
## #   mean_areaconst <dbl>, sd_areaconst <dbl>, min_areaconst <dbl>,
## #   max_areaconst <dbl>, median_areaconst <dbl>

Zona Oeste.

#Cluster analysis by zone

#Zona Oeste
zonaoeste <- subset(df_clean, df_clean$zona == "Zona Oeste")
zonaoeste
## # A tibble: 1,098 × 14
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1  6999 Zona …       6     870       200            2      5            3 Apar…
##  2  8055 Zona …       4     165        61            1      2            3 Apar…
##  3  8058 Zona …       4     165        61            1      2            2 Apar…
##  4  8079 Zona …       6     410       120            2      3            3 Apar…
##  5  8179 Zona …       3     140        60            1      2            2 Apar…
##  6  8197 Zona …       6    1100       216            3      3            3 Apar…
##  7  8255 Zona …       6    1130       237            3      4            3 Apar…
##  8  8258 Zona …       3     120        60            1      1            3 Apar…
##  9  6928 Zona …       6    1850       302            4      4            3 Casa 
## 10  7369 Zona …       6     750       179            2      4            3 Apar…
## # ℹ 1,088 more rows
## # ℹ 5 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   z_order_vals <dbl>, cluster <fct>
#select precio and areaconst columns
P_A_Oeste <- zonaoeste %>%
  select(preciom, areaconst)

#Standardizing variables
P_A_Oeste_Z =scale(P_A_Oeste)
P_A_Oeste_Z = as.data.frame(P_A_Oeste_Z)

#install.packages('tidyverse')

library(tidyverse)
# distancia euclidiana
dist_PAOeste <- dist(P_A_Oeste_Z, method = 'euclidean')

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

#install.packages('cluster')

library(cluster)
sil_width <- sapply(2:10, function(k) {
  pam(P_A_Oeste_Z, k)$silinfo$avg.width
})

plot(2:10, sil_width, type = "b", pch = 19, frame = FALSE, 
     xlab = "Number of clusters K",
     ylab = "Average Silhouette Width")

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

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


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

#install.packages("leaflet")
#install.packages("tmap")

library(leaflet)
library(dplyr)

# Ensure that 'zonaoeste' contains 'longitud', 'latitud', and 'cluster' columns
zonaoeste <- zonaoeste %>%
  mutate(longitud = as.numeric(longitud),
         latitud = as.numeric(latitud),
         cluster = as.factor(cluster_assigments)) %>%
  filter(!is.na(longitud) & !is.na(latitud))

# Create a color palette for the clusters
palette <- colorFactor(palette = c("blue", "orange"), domain = zonaoeste$cluster)

# Plot the map using leaflet
leaflet(data = zonaoeste) %>%
  addTiles() %>%  # Add default OpenStreetMap tiles
  addCircleMarkers(
    ~longitud, ~latitud,
    color = ~palette(cluster),  # Color points by cluster
    radius = 8,
    popup = ~paste("Cluster:", cluster, "<br>",
                   "Price:", preciom, "<br>",
                   "Area:", areaconst)
  ) %>%
  addLegend(
    position = "bottomright",
    pal = palette,
    values = ~cluster,
    title = "Conglomerados de viviendas por similitud en relación precio/área (Zona Oeste)",
    opacity = 2
  )
#descriptive stats table

# Compute descriptive statistics per cluster
descriptive_stats <- zonaoeste %>%
  group_by(cluster) %>%
  summarise(
    count_preciom = n(),
    mean_preciom = mean(preciom, na.rm = TRUE),
    sd_preciom = sd(preciom, na.rm = TRUE),
    min_preciom = min(preciom, na.rm = TRUE),
    max_preciom = max(preciom, na.rm = TRUE),
    median_preciom = median(preciom, na.rm = TRUE),
    
    count_areaconst = n(),
    mean_areaconst = mean(areaconst, na.rm = TRUE),
    sd_areaconst = sd(areaconst, na.rm = TRUE),
    min_areaconst = min(areaconst, na.rm = TRUE),
    max_areaconst = max(areaconst, na.rm = TRUE),
    median_areaconst = median(areaconst, na.rm = TRUE)
  )

# Print the descriptive statistics table
print(descriptive_stats)
## # A tibble: 2 × 13
##   cluster count_preciom mean_preciom sd_preciom min_preciom max_preciom
##   <fct>           <int>        <dbl>      <dbl>       <dbl>       <dbl>
## 1 1                1094         695.       384.          89        1950
## 2 2                   4        1400.       400.        1200        1999
## # ℹ 7 more variables: median_preciom <dbl>, count_areaconst <int>,
## #   mean_areaconst <dbl>, sd_areaconst <dbl>, min_areaconst <dbl>,
## #   max_areaconst <dbl>, median_areaconst <dbl>

Zona Oriente.

#Cluster analysis by zone

#Zona Oriente
zonaoriente <- subset(df_clean, df_clean$zona == "Zona Oriente")
zonaoriente
## # A tibble: 163 × 14
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1  1147 Zona …       3     250        70            1      3            6 Casa 
##  2  1169 Zona …       3     320       120            1      2            3 Casa 
##  3  1350 Zona …       3     350       220            2      2            4 Casa 
##  4    77 Zona …       3     190       410            1      2            2 Casa 
##  5    82 Zona …       3     115       111            1      2            4 Apar…
##  6    85 Zona …       3     200       146            1      2            4 Casa 
##  7    99 Zona …       3     403       384            1      3            5 Casa 
##  8    78 Zona …       3      58        50            1      1            2 Apar…
##  9    72 Zona …       3     250       300            1      5            9 Casa 
## 10   154 Zona …       3     400       163            2      3            3 Casa 
## # ℹ 153 more rows
## # ℹ 5 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   z_order_vals <dbl>, cluster <fct>
#select precio and areaconst columns
P_A_Oriente <- zonaoriente %>%
  select(preciom, areaconst)

#Standardizing variables
P_A_Oriente_Z =scale(P_A_Oriente)
P_A_Oriente_Z = as.data.frame(P_A_Oriente_Z)

#install.packages('tidyverse')

library(tidyverse)
# distancia euclidiana
dist_PAOriente <- dist(P_A_Oriente_Z, method = 'euclidean')

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

#install.packages('cluster')

library(cluster)
sil_width <- sapply(2:10, function(k) {
  pam(P_A_Oriente_Z, k)$silinfo$avg.width
})

plot(2:10, sil_width, type = "b", pch = 19, frame = FALSE, 
     xlab = "Number of clusters K",
     ylab = "Average Silhouette Width")

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

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


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

#install.packages("leaflet")
#install.packages("tmap")

library(leaflet)
library(dplyr)

# Ensure that 'zonaoriente' contains 'longitud', 'latitud', and 'cluster' columns
zonaoriente <- zonaoriente %>%
  mutate(longitud = as.numeric(longitud),
         latitud = as.numeric(latitud),
         cluster = as.factor(cluster_assigments)) %>%
  filter(!is.na(longitud) & !is.na(latitud))

# Create a color palette for the clusters
palette <- colorFactor(palette = c("green", "red"), domain = zonaoriente$cluster)

# Plot the map using leaflet
leaflet(data = zonaoriente) %>%
  addTiles() %>%  # Add default OpenStreetMap tiles
  addCircleMarkers(
    ~longitud, ~latitud,
    color = ~palette(cluster),  # Color points by cluster
    radius = 8,
    popup = ~paste("Cluster:", cluster, "<br>",
                   "Price:", preciom, "<br>",
                   "Area:", areaconst)
  ) %>%
  addLegend(
    position = "bottomright",
    pal = palette,
    values = ~cluster,
    title = "Conglomerados de viviendas por similitud en relación precio/área (Zona Oriente)",
    opacity = 2
  )
#descriptive stats table

# Compute descriptive statistics per cluster
descriptive_stats <- zonaoriente %>%
  group_by(cluster) %>%
  summarise(
    count_preciom = n(),
    mean_preciom = mean(preciom, na.rm = TRUE),
    sd_preciom = sd(preciom, na.rm = TRUE),
    min_preciom = min(preciom, na.rm = TRUE),
    max_preciom = max(preciom, na.rm = TRUE),
    median_preciom = median(preciom, na.rm = TRUE),
    
    count_areaconst = n(),
    mean_areaconst = mean(areaconst, na.rm = TRUE),
    sd_areaconst = sd(areaconst, na.rm = TRUE),
    min_areaconst = min(areaconst, na.rm = TRUE),
    max_areaconst = max(areaconst, na.rm = TRUE),
    median_areaconst = median(areaconst, na.rm = TRUE)
  )

# Print the descriptive statistics table
print(descriptive_stats)
## # A tibble: 9 × 13
##   cluster count_preciom mean_preciom sd_preciom min_preciom max_preciom
##   <fct>           <int>        <dbl>      <dbl>       <dbl>       <dbl>
## 1 1                  77         259        56.0         185         400
## 2 2                  34         312.       60.9         150         403
## 3 3                  38         127.       27.3          58         170
## 4 4                   4         358.       73.7         250         410
## 5 5                   1         750        NA           750         750
## 6 6                   5         472        36.2         430         500
## 7 7                   2         650        70.7         600         700
## 8 8                   1         255        NA           255         255
## 9 9                   1        1350        NA          1350        1350
## # ℹ 7 more variables: median_preciom <dbl>, count_areaconst <int>,
## #   mean_areaconst <dbl>, sd_areaconst <dbl>, min_areaconst <dbl>,
## #   max_areaconst <dbl>, median_areaconst <dbl>

C. Código en R empleado para el análisis.

#devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
# Load the necessary libraries
library(paqueteMODELOS)
library(naniar)
library(dplyr)
library(Hmisc)

# Load the vivienda dataset
data("vivienda")


describe(vivienda)


knitr::opts_chunk$set(echo = TRUE)

# Generate the missing data chart with a title
plot <- gg_miss_var(vivienda)
plot <- plot + ggtitle("Datos faltantes en el data frame inicial")
print(plot)

#DATA PREPARATION
#Removing NA's for analysis
vivienda.noNA <- vivienda %>%
  select(-piso)                     # Drop 'piso' column (not using because 'habitac' contains very similar information and doesn't have NA's)

# Count occurrences
# Remove rows with any NA values
df_clean <- vivienda.noNA[complete.cases(vivienda.noNA), ]

describe(df_clean)

#creating a subset with numeric attributes
df_numeric_1 <- df_clean %>%
  select_if(is.numeric)

df_numeric <- df_numeric_1 %>%
  select(-estrato) %>%
  select(-id)

describe(df_numeric)


#PCA analysis

#install.packages("factoextra")
library(factoextra)

#standardizing data
df_numeric_Z= scale(df_numeric) 

#performing pca
res.pca <- prcomp(df_numeric_Z)

#visualize accumulated variance per component
print(res.pca)
fviz_eig(res.pca, addlabels = TRUE)


#visualization of contribution and correlation of variables within PC1 and PC2
fviz_pca_var(res.pca,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#FF7F00",  "#034D94"),
repel = TRUE     # Avoid text overlapping
)

#Examples of PCA axes

ejemplos <- rbind(df_numeric[6,], # ok
df_numeric[968,],
df_numeric[98,],
df_numeric[137,])

ejemplos <- as.data.frame(ejemplos)
rownames(ejemplos) = c("Casa 006","Casa 968","Casa 098","Casa 137")
ejemplos


casos1 <- rbind(res.pca$x[6,1:2],res.pca$x[968,1:2]) # CP1
rownames(casos1) = c("98","299")
casos1 <- as.data.frame(casos1)

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

fviz_pca_ind(res.pca, col.ind = "#DEDEDE", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
geom_point(data = casos1, aes(x = PC1, y = PC2), color = "red", size = 3) +
geom_point(data = casos2, aes(x = PC1, y = PC2), color = "blue", size = 3)


#Defining location coordinates using a 1-dimensional variable which preserves locality

# Install and load the necessary package
# install.packages("bitops")
library(bitops)

# Function to interleave bits of two numbers
interleave_bits <- function(x, y, max_bits = 16) {
  result <- 0
  for (i in 0:(max_bits - 1)) {
    bit_x <- bitAnd(x, bitShiftL(1, i))
    bit_y <- bitAnd(y, bitShiftL(1, i))
    result <- bitOr(result, bitShiftL(bit_x, i * 2 + 1))
    result <- bitOr(result, bitShiftL(bit_y, i * 2))
  }
  return(result)
}

# Normalize Latitude and Longitude to [0, 65535]
norm_lat <- round((df_clean$latitud - min(df_clean$latitud)) / 
                  (max(df_clean$latitud) - min(df_clean$latitud)) * (2^16 - 1))
norm_lon <- round((df_clean$longitud - min(df_clean$longitud)) / 
                  (max(df_clean$longitud) - min(df_clean$longitud)) * (2^16 - 1))

# Apply the interleave_bits function to generate Z-order curve indices
z_order_vals <- mapply(interleave_bits, norm_lon, norm_lat)

# Add the Z-order values to your data
df_clean$z_order_vals <- z_order_vals


#Cluster analysis.

# Select precio and z_order_vals columns
Precio_Coord <- df_clean %>%
  select(preciom, z_order_vals)

# Standardizing variables
Precio_Coord_Z <- scale(Precio_Coord)
Precio_Coord_Z <- as.data.frame(Precio_Coord_Z)
names(Precio_Coord_Z) <- c("preciom", "z_order_vals")  # Rename columns

# Install and load necessary package for clustering
# install.packages('tidyverse')
# install.packages('cluster')
library(tidyverse)
library(cluster)

# Compute Euclidean distance
dist_PrecioCoord <- dist(Precio_Coord_Z, method = 'euclidean')

# Hierarchical clustering with complete linkage
hc_PrecioCoord <- hclust(dist_PrecioCoord, method = 'complete')

# Determine the optimal number of clusters using silhouette width
sil_width <- sapply(2:10, function(k) {
  pam(Precio_Coord_Z, k)$silinfo$avg.width
})

plot(2:10, sil_width, type = "b", pch = 19, frame = FALSE, 
     xlab = "Number of clusters K",
     ylab = "Average Silhouette Width")

# Assign clusters
cluster_assigments <- cutree(hc_PrecioCoord, k = 8)

# Add cluster assignments to data
assigned_cluster <- Precio_Coord_Z %>% mutate(cluster = as.factor(cluster_assigments))

# Plot results
ggplot(assigned_cluster, aes(x = z_order_vals, y = preciom, color = cluster)) +
  geom_point(size = 4) +
  geom_text(aes(label = cluster), vjust = -.8) + # Add cluster labels
  theme_classic()

#install.packages("leaflet")
#install.packages("tmap")

library(leaflet)
library(dplyr)

# Ensure that 'df_clean' contains 'longitud', 'latitud', and 'cluster' columns
df_clean <- df_clean %>%
  mutate(longitud = as.numeric(longitud),
         latitud = as.numeric(latitud),
         cluster = as.factor(cluster_assigments)) %>%
  filter(!is.na(longitud) & !is.na(latitud))

# Create a color palette for the clusters
palette <- colorFactor(palette = c("yellow", "red", "blue"), domain = df_clean$cluster)

# Plot the map using leaflet
leaflet(data = df_clean) %>%
  addTiles() %>%  # Add default OpenStreetMap tiles
  addCircleMarkers(
    ~longitud, ~latitud,
    color = ~palette(cluster),  # Color points by cluster
    radius = 8,
    popup = ~paste("Cluster:", cluster, "<br>",
                   "Price:", preciom, "<br>",
                   "Area:", areaconst)
  ) %>%
  addLegend(
    position = "bottomright",
    pal = palette,
    values = ~cluster,
    title = "Conglomerados de viviendas por similitud en relación precio/área (Zona Centro)",
    opacity = 2
  )

#descriptive stats table

# Compute descriptive statistics per cluster
descriptive_stats <- df_clean %>%
  group_by(cluster) %>%
  summarise(
    count_preciom = n(),
    mean_preciom = mean(preciom, na.rm = TRUE),
    sd_preciom = sd(preciom, na.rm = TRUE),
    min_preciom = min(preciom, na.rm = TRUE),
    max_preciom = max(preciom, na.rm = TRUE),
    median_preciom = median(preciom, na.rm = TRUE),
    
    count_areaconst = n(),
    mean_areaconst = mean(areaconst, na.rm = TRUE),
    sd_areaconst = sd(areaconst, na.rm = TRUE),
    min_areaconst = min(areaconst, na.rm = TRUE),
    max_areaconst = max(areaconst, na.rm = TRUE),
    median_areaconst = median(areaconst, na.rm = TRUE)
  )

# Print the descriptive statistics table
print(descriptive_stats)

#contingency table for cluster and Estrato variables

library(FactoMineR)
tablacont <- table(df_clean$cluster, df_clean$estrato)
colnames(tablacont) <- c("Estrato3", "Estrato4", "Estrato5", "Estrato6" )

tablacont
chisq.test(tablacont)


#contingency table for cluster and Estrato variables

library(FactoMineR)
tablacont <- table(df_clean$cluster, df_clean$estrato)
colnames(tablacont) <- c("Estrato3", "Estrato4", "Estrato5", "Estrato6" )

tablacont
chisq.test(tablacont)



#contingency table for Cluster and Estrato variables

library(gridExtra)

resultados_ac <- CA(tablacont)


#bar chart: tipo de vivienda vs clusters
conteo <- table(df_clean$tipo, df_clean$cluster)

barplot(conteo/length(df_clean$cluster)*100,
        main = paste("Distribucion de viviendas por cluster y tipo (%), Zona Oeste", "(n=", length(df_clean$id), ")"),
        xlab = "Nichos de mercado",
        col = c("#0d3b66","#f4d35e"),
        legend = rownames(conteo),
        las = 1,
        names.arg = c("1", "2", "3", "4", "5", "6", "7", "8"),
        args.legend = list(x = "topleft", inset = c(0.2, 0)),
        ylim = c(0,80))