1. Introducción

El mercado inmobiliario en la ciudad de Cali ha presentado variaciones importantes en los últimos meses debido a cambios en la dinámica económica y en la disponibilidad de crédito por parte de las entidades financieras. En este contexto, la empresa C&A (Casas y Apartamentos), dirigida por María, ha recibido una solicitud por parte de una compañía internacional interesada en adquirir dos viviendas para ubicar a dos de sus empleados junto con sus familias.

Con el fin de brindar una recomendación basada en evidencia, se emplearán técnicas de análisis de datos y modelación estadística, específicamente regresión lineal múltiple, utilizando información de ofertas de viviendas disponibles en el mercado.

El objetivo del análisis es estimar el precio de las viviendas en función de sus características estructurales y de ubicación, así como identificar alternativas que se ajusten al presupuesto disponible de la empresa solicitante.

2. Metodología de análisis

Para desarrollar el estudio se seguirán los siguientes pasos metodológicos:

1. Filtrado de la base de datos

Se realizará un filtro a la base de datos con el fin de incluir únicamente las ofertas correspondientes a casas ubicadas en la zona norte de la ciudad. Se presentarán los primeros registros de la base filtrada y se incluirán tablas que validen la consulta realizada.

Adicionalmente, se construirá un mapa con la ubicación geográfica de las viviendas, con el objetivo de verificar si todos los registros corresponden efectivamente a la zona norte o si se presentan inconsistencias en la información.

2. Análisis exploratorio de datos

Se realizará un análisis exploratorio enfocado en la relación entre el precio de la vivienda y las siguientes variables:

  • área construida
  • estrato
  • número de baños
  • número de habitaciones
  • zona de ubicación

Para este análisis se utilizarán gráficos interactivos mediante el paquete plotly, lo cual permitirá visualizar posibles patrones o relaciones entre las variables.

3. Estimación del modelo de regresión

Posteriormente se estimará un modelo de regresión lineal múltiple donde el precio de la vivienda será explicado en función de las variables:

  • área construida
  • estrato
  • número de habitaciones
  • número de parqueaderos
  • número de baños

Se analizará la significancia estadística de los coeficientes, se interpretará el coeficiente de determinación (R²) y se discutirá si los resultados obtenidos son coherentes con el comportamiento esperado del mercado inmobiliario.

4. Validación de supuestos del modelo

Se evaluarán los supuestos clásicos del modelo de regresión:

  • normalidad de los residuos
  • homocedasticidad
  • independencia
  • linealidad

En caso de detectarse posibles problemas, se discutirán alternativas que podrían utilizarse para mejorar el modelo.

5. Predicción de la primera vivienda

A partir del modelo estimado se realizará la predicción del precio de una vivienda con las características descritas en la primera solicitud realizada por la compañía internacional.

6. Identificación de ofertas potenciales

Con base en las predicciones del modelo se identificarán al menos cinco viviendas potenciales que cumplan con las condiciones solicitadas y cuyo valor se encuentre dentro del crédito preaprobado de 350 millones de pesos. Estas viviendas serán presentadas y analizadas mediante un mapa geográfico.

7. Evaluación de la segunda solicitud

Finalmente, se repetirá el procedimiento para la segunda solicitud de vivienda, la cual cuenta con un crédito preaprobado de 850 millones de pesos, con el fin de identificar las opciones más adecuadas para este caso.

3. Instalación y carga de paquetes

Para el desarrollo del análisis se utilizaron diferentes paquetes del lenguaje R, los cuales permiten realizar procesos de manipulación de datos, visualización gráfica y modelación estadística.

En particular, se utiliza el paquete paqueteMODELOS, que contiene la base de datos empleada en el ejercicio. Adicionalmente, se emplean librerías como dplyr para manipulación de datos, ggplot2 y plotly para visualización gráfica, y car para el análisis de supuestos del modelo de regresión.

A continuación, se presentan los comandos utilizados para instalar y cargar las librerías necesarias.

devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
## 
## ── R CMD build ─────────────────────────────────────────────────────────────────
##      checking for file ‘/private/var/folders/ng/fwtq_pxj3nd55x83644l70bm0000gn/T/Rtmp5OuO01/remotes3c3b7b366af/Centromagis-paqueteMODELOS-3b06257/DESCRIPTION’ ...  ✔  checking for file ‘/private/var/folders/ng/fwtq_pxj3nd55x83644l70bm0000gn/T/Rtmp5OuO01/remotes3c3b7b366af/Centromagis-paqueteMODELOS-3b06257/DESCRIPTION’
##   ─  preparing ‘paqueteMODELOS’:
##    checking DESCRIPTION meta-information ...  ✔  checking DESCRIPTION meta-information
##   ─  checking for LF line-endings in source and make files and shell scripts
##   ─  checking for empty or unneeded directories
##   ─  building ‘paqueteMODELOS_0.1.0.tar.gz’
##      
## 
knitr::opts_chunk$set(
  echo = TRUE,
  warning = FALSE,
  message = FALSE
)

library(paqueteMODELOS)
library(dplyr)
library(ggplot2)
library(plotly)
library(car)
library(leaflet)
library(psych)
library(corrplot)
library(GGally)
library(stargazer)
library(formattable)
library(knitr)
library(kableExtra)
library(leaflet)

4. Carga de la base de datos

La base de datos utilizada corresponde al conjunto vivienda, el cual se encuentra disponible dentro del paquete paqueteMODELOS. Esta base contiene información sobre diferentes ofertas de viviendas, incluyendo variables relacionadas con el precio, área construida, número de habitaciones, número de baños, parqueaderos, estrato socioeconómico y ubicación dentro de la ciudad.

A continuación, se carga la base de datos y se realiza una inspección inicial de su estructura con el fin de conocer las variables disponibles y el tipo de información que contiene.

data("vivienda")

head(vivienda)
## # A tibble: 6 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1147 Zona O… <NA>        3     250        70            1      3            6
## 2  1169 Zona O… <NA>        3     320       120            1      2            3
## 3  1350 Zona O… <NA>        3     350       220            2      2            4
## 4  5992 Zona S… 02          4     400       280            3      5            3
## 5  1212 Zona N… 01          5     260        90            1      2            3
## 6  1724 Zona N… 01          5     240        87            1      3            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id          : num [1:8322] 1147 1169 1350 5992 1212 ...
##  $ zona        : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ piso        : chr [1:8322] NA NA NA "02" ...
##  $ estrato     : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
##  $ preciom     : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
##  $ areaconst   : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
##  $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
##  $ banios      : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
##  $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
##  $ tipo        : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  $ longitud    : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
##  - attr(*, "spec")=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>

Los primeros registros permiten identificar las variables disponibles en el conjunto de datos y verificar que la información fue cargada correctamente para el análisis posterior.

5. Casa, Zona Norte

5.1 Filtrado de la base de datos

De acuerdo con los requerimientos del análisis, es necesario trabajar únicamente con las ofertas de viviendas correspondientes a casas ubicadas en la zona norte de la ciudad.

Para ello, se realiza un proceso de filtrado sobre la base de datos original utilizando funciones del paquete dplyr. Este procedimiento permite seleccionar únicamente los registros que cumplen con las condiciones establecidas para el análisis.

Posteriormente, se presentan los primeros registros de la base filtrada con el fin de verificar que la consulta fue realizada correctamente.

base1 <- vivienda %>%
  filter(tipo == "Casa",
         zona == "Zona Norte")

# número de registros
nrow(base1)
## [1] 722
head(base1,3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1209 Zona N… 02          5     320       150            2      4            6
## 2  1592 Zona N… 02          5     780       380            2      3            3
## 3  4057 Zona N… 02          6     750       445           NA      7            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Los primeros registros de la base filtrada muestran únicamente viviendas correspondientes al tipo casa y ubicadas en la zona norte, lo cual confirma que el proceso de filtrado se realizó correctamente.

Verificación del filtro aplicado

table(base1$tipo)
## 
## Casa 
##  722
table(base1$zona)
## 
## Zona Norte 
##        722

Las tablas de frecuencia permiten confirmar que todos los registros de la base filtrada corresponden al tipo de vivienda Casa y se encuentran ubicados en la zona norte de la ciudad, cumpliendo con los criterios establecidos para el análisis.

Georeferenciación de propiedades

A continuación se presentan de manera georreferenciada las coordenadas de cada vivienda en el conjunto de datos. El objetivo es analizar la distribución espacial de las viviendas dentro de la zona norte de la ciudad de Cali.

leaflet(base1) %>%
  addTiles() %>%
  setView(lng = -76.53, lat = 3.45, zoom = 12) %>%
addCircleMarkers(
  lng = ~longitud,
  lat = ~latitud,
  radius = 4,
  color = "orange",
  fillOpacity = 0.7,
  popup = ~paste("Precio:", preciom, "millones")
)

El mapa interactivo permite visualizar la distribución geográfica de las viviendas incluidas en la base filtrada. Aunque el filtro se realizó para incluir únicamente viviendas clasificadas en la Zona Norte, se observa que algunos puntos aparecen en otras áreas del mapa.

Esta situación puede explicarse por posibles inconsistencias en las coordenadas geográficas registradas en la base de datos o por diferencias entre la clasificación administrativa de la zona y la ubicación geográfica exacta de las viviendas.

Este tipo de hallazgos es común en bases de datos geoespaciales y resalta la importancia de realizar procesos de validación de calidad de los datos antes de utilizarlos para análisis más avanzados.

Detección de valores extremos en coordenadas geográficas

Para la detección de posibles inconsistencias en las coordenadas geográficas se utilizó una variante del método del rango intercuartílico (IQR). En lugar de emplear los percentiles tradicionales (25% y 75%), se utilizaron los percentiles 30% y 70% con el fin de definir un rango más restrictivo alrededor de la distribución central de las coordenadas.

Posteriormente se calcularon los límites inferior y superior utilizando el criterio \(1.5 \times IQR\)., lo cual permitió identificar observaciones con coordenadas potencialmente atípicas.

Q1_lat <- quantile(base1$latitud, 0.30)
Q3_lat <- quantile(base1$latitud, 0.70)
IQR_lat <- Q3_lat - Q1_lat

lim_inf_lat <- Q1_lat - 1.5 * IQR_lat
lim_sup_lat <- Q3_lat + 1.5 * IQR_lat
Q1_lon <- quantile(base1$longitud, 0.30)
Q3_lon <- quantile(base1$longitud, 0.70)
IQR_lon <- Q3_lon - Q1_lon

lim_inf_lon <- Q1_lon - 1.5 * IQR_lon
lim_sup_lon <- Q3_lon + 1.5 * IQR_lon
base1_limpia <- base1 %>%
  filter(
    latitud >= lim_inf_lat & latitud <= lim_sup_lat,
    longitud >= lim_inf_lon & longitud <= lim_sup_lon
  )
nrow(base1)
## [1] 722
nrow(base1_limpia)
## [1] 613
nrow(base1) - nrow(base1_limpia)
## [1] 109
cat("Observaciones iniciales:", nrow(base1), "\n")
## Observaciones iniciales: 722
cat("Observaciones después de la limpieza:", nrow(base1_limpia), "\n")
## Observaciones después de la limpieza: 613
leaflet(base1_limpia) %>%
  addTiles() %>%
  setView(lng = -76.53, lat = 3.45, zoom = 12) %>%
addCircleMarkers(
  lng = ~longitud,
  lat = ~latitud,
  radius = 4,
  color = "darkorange",
  fillOpacity = 0.7,
  popup = ~paste("Precio:", preciom, "millones")
)

Durante el análisis exploratorio se realizó una validación espacial de las coordenadas geográficas de las viviendas. Para identificar posibles valores atípicos en las variables de latitud y longitud se aplicó el método del rango intercuartílico (IQR), el cual permite detectar observaciones que se encuentran significativamente alejadas de la distribución central de los datos.

A partir de este procedimiento se identificaron registros con coordenadas potencialmente inconsistentes, los cuales fueron excluidos del análisis con el fin de mejorar la calidad de los datos utilizados en el modelo. Posteriormente se generó un nuevo mapa con las observaciones depuradas, evidenciando una distribución espacial más coherente con la zona norte de la ciudad.

describe(base1_limpia)
##              vars   n    mean      sd  median trimmed     mad    min     max
## id              1 613 2231.15 1738.29 1666.00 2098.60 1890.31  88.00 7226.00
## zona*           2 613    1.00    0.00    1.00    1.00    0.00   1.00    1.00
## piso*           3 328    1.98    0.71    2.00    1.95    0.00   1.00    5.00
## estrato         4 613    4.15    0.97    4.00    4.12    1.48   3.00    6.00
## preciom         5 613  428.52  257.96  380.00  393.61  214.98  89.00 1940.00
## areaconst       6 613  261.32  166.39  240.00  240.54  148.26  30.00 1440.00
## parqueaderos    7 398    2.18    1.42    2.00    1.93    1.48   1.00   10.00
## banios          8 613    3.51    1.51    3.00    3.38    1.48   0.00   10.00
## habitaciones    9 613    4.58    1.82    4.00    4.38    1.48   0.00   10.00
## tipo*          10 613    1.00    0.00    1.00    1.00    0.00   1.00    1.00
## barrio*        11 613   50.58   28.00   47.00   51.25   34.10   1.00   92.00
## longitud       12 613  -76.51    0.02  -76.52  -76.52    0.02 -76.55  -76.48
## latitud        13 613    3.47    0.01    3.47    3.47    0.01   3.43    3.50
##                range  skew kurtosis    se
## id           7138.00  0.53    -0.93 70.21
## zona*           0.00   NaN      NaN  0.00
## piso*           4.00  0.47     0.54  0.04
## estrato         3.00  0.08    -1.32  0.04
## preciom      1851.00  1.88     5.76 10.42
## areaconst    1410.00  1.89     6.80  6.72
## parqueaderos    9.00  1.90     4.73  0.07
## banios         10.00  0.78     1.26  0.06
## habitaciones   10.00  0.82     1.14  0.07
## tipo*           0.00   NaN      NaN  0.00
## barrio*        91.00 -0.06    -1.28  1.13
## longitud        0.07  0.27    -1.08  0.00
## latitud         0.06 -0.54    -0.28  0.00

5.2 Análisis exploratorio de datos

Con el fin de comprender la relación entre el precio de las viviendas y sus principales características estructurales, se realiza un análisis exploratorio de datos (EDA).

En particular, se examina la relación entre el precio y variables como el área construida, el estrato socioeconómico, el número de habitaciones y el número de baños.

Para facilitar la interpretación de los resultados se utilizan gráficos interactivos mediante el paquete plotly.

Histograma del precio

ggplot(base1_limpia, aes(x = preciom)) +
  geom_histogram(bins = 20, fill = "darkorange", color = "black") +
  labs(
    title = "Distribución del precio de las viviendas",
    x = "Precio (millones de pesos)",
    y = "Frecuencia"
  )

El histograma muestra la distribución del precio de las viviendas en la muestra. Se observa que la mayoría de las propiedades se concentran en ciertos rangos de precio, mientras que algunas viviendas presentan valores más elevados. Este tipo de análisis permite identificar posibles valores extremos y comprender la variabilidad del mercado inmobiliario.

Boxplot del precio

ggplot(base1_limpia, aes(y = preciom)) +
  geom_boxplot(fill = "orange") +
  labs(
    title = "Boxplot del precio de las viviendas",
    y = "Precio (millones de pesos)"
  )

El boxplot permite identificar posibles valores atípicos en el precio de las viviendas. Se observa que algunas propiedades presentan precios considerablemente más altos que el resto de la muestra, lo cual podría influir en la estimación del modelo de regresión.

Precio vs área

p1 <- ggplot(base1_limpia, aes(x = areaconst, y = preciom)) +
  geom_point(color = "darkblue") +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre el precio y el área construida",
    x = "Área construida (m²)",
    y = "Precio (millones de pesos)"
  )

ggplotly(p1)

El gráfico muestra una relación positiva entre el área construida y el precio de la vivienda. A medida que aumenta el tamaño del inmueble, el precio tiende a incrementarse. Este comportamiento es consistente con lo esperado en el mercado inmobiliario, donde viviendas con mayor área suelen tener un mayor valor comercial.

Precio vs estrato

p2 <- ggplot(base1_limpia, aes(x = estrato, y = preciom)) +
  geom_point(color = "darkgreen") +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre el precio y el estrato",
    x = "Estrato socioeconómico",
    y = "Precio (millones de pesos)"
  )

ggplotly(p2)

Se observa una tendencia positiva entre el estrato socioeconómico y el precio de la vivienda. En general, las viviendas ubicadas en estratos más altos presentan precios más elevados, lo cual es consistente con las diferencias en calidad de infraestructura, ubicación y servicios asociados a cada estrato.

Precio vs habitaciones

p3 <- ggplot(base1_limpia, aes(x = habitaciones, y = preciom)) +
  geom_point(color = "darkorange") +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre el precio y el número de habitaciones",
    x = "Número de habitaciones",
    y = "Precio (millones de pesos)"
  )

ggplotly(p3)

El gráfico sugiere una relación positiva entre el número de habitaciones y el precio de la vivienda. Aunque existe cierta dispersión en los datos, se observa que las viviendas con mayor número de habitaciones tienden a presentar precios más altos.

Precio vs baños

p4 <- ggplot(base1_limpia, aes(x = banios, y = preciom)) +
  geom_point(color = "red") +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre el precio y el número de baños",
    x = "Número de baños",
    y = "Precio (millones de pesos)"
  )

ggplotly(p4)

Se observa una relación positiva entre el número de baños y el precio de la vivienda. En términos generales, las propiedades con mayor cantidad de baños tienden a presentar valores más elevados, lo cual puede estar asociado a un mayor nivel de comodidad y tamaño de la vivienda.

Matriz de dispersión

cor(base1_limpia[, c("preciom",
                     "areaconst",
                     "habitaciones",
                     "banios",
                     "parqueaderos",
                     "estrato")])
##                preciom areaconst habitaciones    banios parqueaderos   estrato
## preciom      1.0000000 0.7332501    0.4049050 0.5490607           NA 0.5915063
## areaconst    0.7332501 1.0000000    0.4373932 0.4964403           NA 0.4686173
## habitaciones 0.4049050 0.4373932    1.0000000 0.6268077           NA 0.1267576
## banios       0.5490607 0.4964403    0.6268077 1.0000000           NA 0.4053107
## parqueaderos        NA        NA           NA        NA            1        NA
## estrato      0.5915063 0.4686173    0.1267576 0.4053107           NA 1.0000000
corr <- cor(base1_limpia[, c("preciom",
                             "areaconst",
                             "habitaciones",
                             "banios",
                             "parqueaderos",
                             "estrato")])

corrplot(corr, method = "color")

La matriz de correlaciones permite identificar la intensidad de la relación lineal entre las variables numéricas analizadas. Se observa que el área construida presenta una de las correlaciones positivas más fuertes con el precio de la vivienda, Este resultado sugiere que el tamaño del inmueble es uno de los principales determinantes del valor de mercado, lo cual es consistente con la teoría económica del mercado inmobiliario.

Matriz de dispersión

ggpairs(
  base1_limpia[, c("preciom",
                   "areaconst",
                   "habitaciones",
                   "banios",
                   "parqueaderos",
                   "estrato")]
)

La matriz de dispersión permite analizar simultáneamente las relaciones entre las principales variables numéricas del conjunto de datos. Se observa que el precio de la vivienda presenta asociaciones positivas con variables como el área construida, el número de habitaciones y el número de baños. Estas relaciones sugieren que dichas variables podrían tener un efecto importante en la explicación del precio dentro del modelo de regresión.

En general, el análisis exploratorio sugiere que variables estructurales como el área construida, el estrato socioeconómico y el número de habitaciones y baños presentan una relación positiva con el precio de la vivienda. Estos resultados son coherentes con la teoría económica del mercado inmobiliario y respaldan la inclusión de estas variables en el modelo de regresión lineal múltiple.

conclusión

El análisis exploratorio de datos evidencia que variables estructurales como el área construida, el estrato socioeconómico, el número de habitaciones y el número de baños presentan una relación positiva con el precio de las viviendas. Estos hallazgos son consistentes con el comportamiento esperado del mercado inmobiliario y justifican la inclusión de estas variables como predictores dentro del modelo de regresión lineal múltiple.

5.3 Estimación del modelo de regresión lineal múltiple

Con el fin de analizar la relación entre el precio de las viviendas y sus características estructurales, se estima un modelo de regresión lineal múltiple donde el precio de la vivienda es explicado por variables como el área construida, el estrato socioeconómico, el número de habitaciones, el número de parqueaderos y el número de baños.

La especificación del modelo es la siguiente:

\[ Precio_i = \beta_0 + \beta_1 Areaconst_i + \beta_2 Estrato_i + \beta_3 Habitaciones_i + \beta_4 Parqueaderos_i + \beta_5 Banios_i + \epsilon_i \]

donde:

  • \(Precio\) corresponde al precio de la vivienda medido en millones de pesos.
  • \(Area\ construida\) representa el tamaño del inmueble en metros cuadrados.
  • \(Estrato\) corresponde al nivel socioeconómico de la zona.
  • \(Habitaciones\) indica el número de cuartos de la vivienda.
  • \(Parqueaderos\) corresponde al número de espacios disponibles para estacionamiento.
  • \(Baños\) representa el número de baños del inmueble.
  • \(\epsilon\) corresponde al término de error del modelo.

A continuación, se procede a estimar el modelo utilizando el método de Mínimos Cuadrados Ordinarios (OLS).

modelo1 <- lm(preciom ~ areaconst +
                        estrato +
                        habitaciones +
                        parqueaderos +
                        banios,
              data = base1_limpia)

summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base1_limpia)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -750.95  -71.46  -15.13   43.51  988.75 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -227.81808   46.71879  -4.876 1.57e-06 ***
## areaconst       0.65173    0.05617  11.602  < 2e-16 ***
## estrato        77.00602   10.38065   7.418 7.42e-13 ***
## habitaciones    7.00985    5.94922   1.178   0.2394    
## parqueaderos   27.24956    6.01671   4.529 7.88e-06 ***
## banios         20.47837    8.13337   2.518   0.0122 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 154.7 on 392 degrees of freedom
##   (215 observations deleted due to missingness)
## Multiple R-squared:  0.6028, Adjusted R-squared:  0.5977 
## F-statistic:   119 on 5 and 392 DF,  p-value: < 2.2e-16
coef(summary(modelo1))
##                  Estimate  Std. Error   t value     Pr(>|t|)
## (Intercept)  -227.8180845 46.71878710 -4.876370 1.573199e-06
## areaconst       0.6517263  0.05617434 11.601851 5.907815e-27
## estrato        77.0060179 10.38065078  7.418226 7.420405e-13
## habitaciones    7.0098452  5.94921902  1.178280 2.393998e-01
## parqueaderos   27.2495578  6.01670661  4.528982 7.876249e-06
## banios         20.4783672  8.13337379  2.517820 1.220602e-02
stargazer(modelo1, type = "text")
## 
## ===============================================
##                         Dependent variable:    
##                     ---------------------------
##                               preciom          
## -----------------------------------------------
## areaconst                    0.652***          
##                               (0.056)          
##                                                
## estrato                      77.006***         
##                              (10.381)          
##                                                
## habitaciones                   7.010           
##                               (5.949)          
##                                                
## parqueaderos                 27.250***         
##                               (6.017)          
##                                                
## banios                       20.478**          
##                               (8.133)          
##                                                
## Constant                    -227.818***        
##                              (46.719)          
##                                                
## -----------------------------------------------
## Observations                    398            
## R2                             0.603           
## Adjusted R2                    0.598           
## Residual Std. Error     154.735 (df = 392)     
## F Statistic          118.980*** (df = 5; 392)  
## ===============================================
## Note:               *p<0.1; **p<0.05; ***p<0.01

Con base en los resultados del modelo estimado, a continuación se presenta la interpretación de los coeficientes y del ajuste general del modelo.

Interpretación de los coeficientes del modelo

A partir de la estimación del modelo de regresión lineal múltiple se obtuvieron los coeficientes asociados a cada variable explicativa, los cuales permiten analizar cómo diferentes características estructurales de las viviendas influyen en su precio.

El modelo fue estimado con 398 observaciones y presenta un coeficiente de determinación \(R^2 = 0.603\), lo que indica que aproximadamente el 60.3% de la variabilidad del precio de las viviendas puede ser explicada por las variables incluidas en el modelo.

A continuación se presenta la interpretación de los principales coeficientes.

Área construida

El coeficiente asociado al área construida es 0.652 y es estadísticamente significativo al 1% (\(p < 0.01\)).

Esto significa que, manteniendo constantes las demás variables del modelo, un incremento de un metro cuadrado en el área construida aumenta en promedio el precio de la vivienda en aproximadamente 0.652 millones de pesos.

Este resultado es coherente con la lógica del mercado inmobiliario, ya que viviendas con mayor área construida ofrecen mayor espacio habitable y, por lo tanto, tienden a tener un mayor valor comercial.

Estrato socioeconómico

El coeficiente del estrato es 77.006 y también es estadísticamente significativo al 1% (\(p < 0.01\)).

Esto indica que, manteniendo constantes las demás variables, un aumento de un nivel en el estrato socioeconómico incrementa en promedio el precio de la vivienda en aproximadamente 77 millones de pesos.

Este resultado es consistente con el comportamiento del mercado inmobiliario en Colombia, donde las viviendas ubicadas en estratos más altos suelen estar asociadas a mejores condiciones de infraestructura, seguridad y acceso a servicios urbanos, lo que se refleja en precios más elevados.

Número de habitaciones

El coeficiente asociado al número de habitaciones es 7.01, pero no es estadísticamente significativo.

Esto sugiere que, una vez controlado por variables como el área construida, el estrato y otras características del inmueble, el número de habitaciones no tiene un efecto estadísticamente claro sobre el precio de la vivienda dentro de este modelo.

Este resultado puede explicarse porque el efecto del número de habitaciones ya podría estar siendo capturado indirectamente por el área construida, dado que viviendas con más habitaciones suelen tener también mayor tamaño.

Número de parqueaderos

El coeficiente asociado al número de parqueaderos es 27.25 y es estadísticamente significativo al 1% (\(p < 0.01\)).

Esto significa que, manteniendo constantes las demás variables del modelo, contar con un parqueadero adicional incrementa en promedio el precio de la vivienda en aproximadamente 27.25 millones de pesos.

Este resultado es lógico desde el punto de vista del mercado inmobiliario urbano, ya que el acceso a estacionamiento es un factor altamente valorado por los compradores, especialmente en zonas donde el espacio para parqueo es limitado.

Número de baños

El coeficiente asociado al número de baños es 20.48 y es estadísticamente significativo al 5% (\(p < 0.05\)).

Esto indica que, manteniendo constantes las demás variables, un baño adicional incrementa en promedio el precio de la vivienda en aproximadamente 20.48 millones de pesos.

Este resultado también es coherente con la lógica del mercado, ya que viviendas con mayor número de baños suelen ofrecer mayor comodidad y funcionalidad para los hogares.

Interpretación del coeficiente \(R^2\)

El coeficiente de determinación \(R^2 = 0.603\) indica que aproximadamente el 60.3% de la variabilidad observada en el precio de las viviendas es explicada por las variables incluidas en el modelo.

Este valor sugiere que el modelo presenta un nivel de ajuste moderadamente alto, teniendo en cuenta que el precio de los inmuebles suele depender de muchos factores adicionales que no están incluidos en la base de datos.

El \(R^2\) ajustado = 0.598 es muy cercano al \(R^2\), lo que indica que las variables incluidas en el modelo contribuyen de manera efectiva a explicar el precio de las viviendas y que no se están incluyendo predictores innecesarios.

Discusión del ajuste del modelo y posibles mejoras

Aunque el modelo logra explicar una proporción importante de la variabilidad del precio de las viviendas, todavía existe cerca de un 40% de variación que no es explicada por las variables incluidas.

Esto sugiere que podrían existir otros factores relevantes que influyen en el precio de los inmuebles, tales como:

  • la ubicación específica o barrio
  • la antigüedad de la vivienda
  • la calidad de los acabados
  • la proximidad a zonas comerciales o centros educativos
  • variables espaciales relacionadas con la localización geográfica

Adicionalmente, el modelo podría mejorarse evaluando posibles transformaciones de variables, como utilizar el logaritmo del precio, o explorando interacciones entre variables, por ejemplo entre el área construida y el número de habitaciones.

En general, los resultados obtenidos son consistentes con el comportamiento esperado del mercado inmobiliario, donde variables relacionadas con el tamaño del inmueble, el nivel socioeconómico de la zona y las comodidades disponibles influyen directamente en el precio de las viviendas.

En la siguiente sección se evalúan los supuestos del modelo de regresión con el fin de verificar la validez de las inferencias realizadas.

Comparación entre valores observados y valores predichos

ggplot(data.frame(
  predicho = fitted(modelo1),
  residuo = resid(modelo1)
), aes(x = predicho, y = residuo)) +
  geom_point(color = "darkorange", alpha = 0.6) +
  geom_smooth(method = "loess", se = FALSE, color = "black") +
  geom_hline(yintercept = 0, linetype = "dashed") +
  labs(
    title = "Residuos vs valores predichos",
    x = "Valores predichos",
    y = "Residuos"
  )

El gráfico de residuos frente a valores predichos permite evaluar si existen patrones sistemáticos en los errores del modelo.

En un modelo adecuadamente especificado, los residuos deberían distribuirse de manera aleatoria alrededor de cero y sin presentar estructuras visibles. En este caso se observa que los residuos se dispersan alrededor de la línea horizontal en cero, aunque se aprecia cierta variabilidad creciente en algunos rangos de valores predichos.

La línea suavizada (LOESS) permite identificar posibles patrones no lineales. En general, el comportamiento observado sugiere que el modelo captura una parte importante de la relación entre las variables, aunque podrían existir factores adicionales que influyan en el precio de las viviendas y que no están incluidos en el modelo.

5.4 Validación de supuestos del modelo

Una vez estimado el modelo de regresión lineal múltiple, es importante evaluar si se cumplen los supuestos clásicos del modelo lineal. Estos supuestos permiten garantizar que las inferencias estadísticas realizadas a partir del modelo sean válidas.

A continuación se presentan algunos gráficos y pruebas estadísticas que permiten analizar estos supuestos. Los resultados deben interpretarse de manera exploratoria, con el fin de identificar posibles patrones o señales de incumplimiento.

Normalidad de los residuos

Uno de los supuestos del modelo de regresión lineal es que los residuos siguen aproximadamente una distribución normal. Para explorar este supuesto se analizan tanto la distribución de los residuos como el gráfico Q-Q.

hist(residuals(modelo1),
     main = "Distribución de los residuos",
     xlab = "Residuos",
     col = "darkorange",
     border = "black")

Interpretación de la distribución de los residuos

El histograma muestra la distribución de los residuos del modelo de regresión. Se observa una forma aproximadamente simétrica con cierta concentración alrededor de cero, lo cual es consistente con el supuesto de normalidad de los errores.

Sin embargo, se aprecia una ligera asimetría en los extremos de la distribución, lo cual puede estar asociado a la presencia de algunas observaciones con mayor desviación respecto a los valores predichos por el modelo.

qqnorm(residuals(modelo1),
       main = "Q-Q Plot de los residuos")

qqline(residuals(modelo1),
       col = "darkorange",
       lwd = 3)

Interpretación del gráfico Q-Q

El gráfico Q-Q permite comparar la distribución de los residuos del modelo con una distribución normal teórica. En este caso, se observa que la mayoría de los puntos se encuentran alineados cerca de la línea de referencia, lo que sugiere que el supuesto de normalidad de los residuos podría considerarse razonable.

No obstante, se observan algunas desviaciones en los extremos del gráfico, lo cual es relativamente común en muestras de datos reales y puede indicar la presencia de algunos valores extremos o colas ligeramente más pesadas.

Homocedasticidad

El supuesto de homocedasticidad establece que la varianza de los residuos debe ser aproximadamente constante para todos los valores ajustados del modelo.

plot(modelo1$fitted.values,
     residuals(modelo1),
     xlab = "Valores ajustados",
     ylab = "Residuos",
     main = "Residuos vs valores ajustados")

abline(h = 0, col = "darkorange")

El análisis del gráfico de residuos versus valores ajustados muestra un patrón con forma de embudo al inicio de la distribución. Este comportamiento sugiere la posible presencia de heterocedasticidad, es decir, que la varianza de los residuos no se mantiene completamente constante a lo largo del rango de valores ajustados. En particular, se observa una mayor dispersión de los residuos en ciertos niveles del modelo, lo cual puede indicar que el supuesto de homocedasticidad se cumple solo parcialmente.

A pesar de la presencia de heterocedasticidad, los coeficientes del modelo siguen siendo insesgados bajo el método de Mínimos Cuadrados Ordinarios, aunque los errores estándar podrían estar subestimados o sobreestimados.

Homocedasticidad

car::ncvTest(modelo1)
## Non-constant Variance Score Test 
## Variance formula: ~ fitted.values 
## Chisquare = 322.3962, Df = 1, p = < 2.22e-16

Con el fin de evaluar si el modelo cumple con el supuesto de varianza constante de los errores (homocedasticidad), se aplicó la prueba Non-constant Variance Score Test.

Los resultados obtenidos fueron los siguientes: • Chi-cuadrado: 322.396 • Grados de libertad: 1 • Valor p: < 2.22e-16

Dado que el valor p es significativamente menor que 0.05, se rechaza la hipótesis nula de varianza constante de los residuos. Esto indica evidencia estadística de heterocedasticidad en el modelo, es decir, la varianza de los errores no se mantiene constante a lo largo de los valores ajustados.

Este resultado es consistente con el análisis gráfico de los residuos, donde se observa un patrón con forma de embudo, lo cual sugiere que la dispersión de los residuos aumenta o disminuye dependiendo del nivel de los valores predichos.

La presencia de heterocedasticidad no invalida el modelo, pero puede afectar la precisión de los errores estándar y de las pruebas de significancia de los coeficientes. Por esta razón, una posible mejora consiste en utilizar errores estándar robustos o aplicar transformaciones a algunas variables con el fin de estabilizar la varianza de los residuos.

Multicolinealidad

Otro aspecto importante en los modelos de regresión es evaluar si las variables explicativas están altamente correlacionadas entre sí, lo cual podría afectar la estabilidad de los coeficientes estimados.

Para analizar este problema se utiliza el Factor de Inflación de la Varianza (VIF).

vif(modelo1)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     1.518290     1.345045     1.815634     1.218174     2.117885

Para evaluar la posible presencia de multicolinealidad entre las variables explicativas del modelo, se calculó el Factor de Inflación de la Varianza (VIF). Este indicador permite identificar si existe una alta correlación entre las variables independientes, lo cual podría afectar la estabilidad y precisión de las estimaciones del modelo.

Los valores obtenidos fueron los siguientes:

Variable VIF areaconst 1.52 estrato 1.35 habitaciones 1.82 parqueaderos 1.22 banios 2.12

En general, valores de VIF superiores a 5 sugieren problemas moderados de multicolinealidad, mientras que valores superiores a 10 indican problemas severos.

En este caso, todos los valores de VIF se encuentran muy por debajo de los umbrales comúnmente aceptados, con valores entre 1.22 y 2.12. Esto indica que no existe evidencia de multicolinealidad significativa entre las variables explicativas del modelo.

Por lo tanto, las variables incluidas en la regresión pueden considerarse estadísticamente independientes entre sí en un grado adecuado, lo que permite interpretar los coeficientes estimados con mayor confianza.

Diagnóstico gráfico general del modelo

Finalmente, se pueden observar los gráficos de diagnóstico estándar del modelo de regresión, los cuales permiten analizar simultáneamente diferentes aspectos del comportamiento de los residuos.

par(mfrow = c(2,2))
plot(modelo1)

Estos gráficos permiten identificar posibles observaciones influyentes, patrones no lineales o desviaciones respecto a los supuestos del modelo. El análisis visual de estos resultados puede proporcionar información útil para evaluar la calidad del ajuste del modelo estimado.

Conclusión del diagnóstico del modelo

El análisis gráfico y las pruebas exploratorias permiten evaluar de manera preliminar los supuestos del modelo de regresión lineal. En general, estos diagnósticos ayudan a identificar posibles desviaciones respecto a los supuestos clásicos y orientan sobre posibles ajustes o mejoras que podrían aplicarse al modelo en futuros análisis.

5.5 Predicción del precio de la primera vivienda

Con base en el modelo estimado, se procede a predecir el precio de la vivienda solicitada por la compañía internacional. Las características de la vivienda son:

  • Tipo: Casa
  • Área construida: 200 m²
  • Parqueaderos: 1
  • Baños: 2
  • Habitaciones: 4
  • Estrato: 4 o 5
  • Zona: Norte
  • Crédito preaprobado: 350 millones de pesos
# Crear un data frame con las características de la vivienda
primera_vivienda <- data.frame(
  areaconst = 200,
  estrato = c(4,5),  # Evaluar ambos estratos
  habitaciones = 4,
  parqueaderos = 1,
  banios = 2
)

# Realizar la predicción
precio_predicho <- predict(modelo1, newdata = primera_vivienda)

# Mostrar los resultados
data.frame(
  Estrato = primera_vivienda$estrato,
  Precio_Estimado_millones = round(precio_predicho, 2)
)
##   Estrato Precio_Estimado_millones
## 1       4                    306.8
## 2       5                    383.8

Interpretación de la predicción y selección de viviendas

El modelo predice que una vivienda con las características solicitadas en estrato 4 tendría un precio aproximado de 306.8 millones, dentro del crédito preaprobado de 350 millones.

Para estrato 5, el precio estimado promedio sería de 383.8 millones, excediendo el presupuesto. Sin embargo, al revisar el conjunto de viviendas disponible, se identifica al menos dos propiedades que cumplen con todos los requisitos y su precio está dentro del límite de crédito, lo que permite incluirla como opción viable.

Por lo tanto, la selección de viviendas puede priorizar estrato 4 pero no descarta por completo viviendas de estrato 5 e incluso estrato 3, siempre que se encuentren dentro del presupuesto y cumplan con las características estructurales solicitadas.

5.6 Identificación de viviendas potenciales para la primera solicitud

A continuación se presentan las cinco viviendas que cumplen con las características solicitadas en la primera solicitud (tipo casa, área construida cercana a 200 m², parqueaderos 1, baños 2, habitaciones 4, zona Norte).

# Calcular precio estimado de la solicitud
solicitud1 <- data.frame(
  areaconst = 200,
  parqueaderos = 1,
  banios = 2,
  habitaciones = 4,
  estrato = 4
)

solicitud1$precio_estimado <- predict(modelo1, newdata = solicitud1)

# Calcular "distancia" a las características de la solicitud
viviendas_seleccionadas <- base1_limpia %>%
  mutate(
    distancia = abs(areaconst - solicitud1$areaconst) +
                abs(parqueaderos - solicitud1$parqueaderos) +
                abs(banios - solicitud1$banios) +
                abs(habitaciones - solicitud1$habitaciones) +
                abs(preciom - solicitud1$precio_estimado)
  ) %>%
  arrange(distancia) %>%
  head(5)  # seleccionar las 5 más cercanas

viviendas_seleccionadas
## # A tibble: 5 × 14
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1   457 Zona N… <NA>        3     300       195            2      4            4
## 2  1343 Zona N… 02          5     320       200            2      4            4
## 3  1144 Zona N… <NA>        4     320       200            2      4            4
## 4  1914 Zona N… 02          5     300       205            2      5            6
## 5  1151 Zona N… <NA>        5     320       210            2      3            5
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   distancia <dbl>
viviendas_resumen <- data.frame(
  id = c(457, 1343, 1144, 1914, 1151),
  estrato = c(3,5,4,5,5),
  areaconst = c(195,200,200,205,210),
  habitaciones = c(4,4,4,6,5),
  banios = c(4,4,4,5,3),
  parqueaderos = c(2,2,2,2,2),
  preciom = c(300,320,320,300,320),
  precio_estimado_modelo = c(294.7,452.0,375.0,489.8,445.1),
  cumple_credito = c("Sí","No","No","No","No")
)

# Crear tabla con colores según estrato
viviendas_resumen %>%
  kable("html", caption = "Viviendas seleccionadas para la primera solicitud") %>%
  kable_styling("striped", full_width = F) %>%
  row_spec(0, bold = TRUE) %>%
  column_spec(2, color = "white", background = c("darkblue","darkgreen","darkorange","darkgreen","darkgreen"))
Viviendas seleccionadas para la primera solicitud
id estrato areaconst habitaciones banios parqueaderos preciom precio_estimado_modelo cumple_credito
457 3 195 4 4 2 300 294.7
1343 5 200 4 4 2 320 452.0 No
1144 4 200 4 4 2 320 375.0 No
1914 5 205 6 5 2 300 489.8 No
1151 5 210 5 3 2 320 445.1 No
# Asegurarse de que las coordenadas están incluidas
viviendas_para_mapa <- viviendas_resumen %>%
  left_join(base1_limpia %>% select(id, longitud, latitud), by = "id")

# Ahora sí se puede hacer el mapa


leaflet(viviendas_para_mapa) %>%
  addTiles() %>%
  setView(lng = -76.53, lat = 3.45, zoom = 12) %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 6,
    color = ~case_when(
      estrato == 3 ~ "darkblue",
      estrato == 4 ~ "darkorange",
      estrato == 5 ~ "darkgreen",
      TRUE ~ "gray"
    ),
    fillOpacity = 0.8,
    popup = ~paste(
      "ID:", id,
      "<br>Estrato:", estrato,
      "<br>Área:", areaconst, "m²",
      "<br>Habitaciones:", habitaciones,
      "<br>Baños:", banios,
      "<br>Parqueaderos:", parqueaderos,
      "<br>Precio Real:", preciom, "millones",
      "<br>Precio Estimado:", precio_estimado_modelo, "millones",
      "<br>Cumple Crédito:", cumple_credito
    )
  ) %>%
  addLegend(
    position = "bottomright",
    colors = c("darkblue", "darkorange", "darkgreen"),
    labels = c("Estrato 3", "Estrato 4", "Estrato 5"),
    title = "Estrato"
  )

Resumen de viviendas seleccionadas

Las cinco viviendas más cercanas a las características de la primera solicitud se presentan a continuación. Se incluye el precio estimado según el modelo y su estrato:

viviendas_resumen <- viviendas_seleccionadas %>%
  mutate(
    precio_estimado_modelo = round(predict(modelo1, newdata = .), 1),
    cumple_credito = ifelse(precio_estimado_modelo <= 350, "Sí", "No")
  ) %>%
  select(id, estrato, areaconst, habitaciones, banios, parqueaderos, preciom, precio_estimado_modelo, cumple_credito)

viviendas_resumen
## # A tibble: 5 × 9
##      id estrato areaconst habitaciones banios parqueaderos preciom
##   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>   <dbl>
## 1   457       3       195            4      4            2     300
## 2  1343       5       200            4      4            2     320
## 3  1144       4       200            4      4            2     320
## 4  1914       5       205            6      5            2     300
## 5  1151       5       210            5      3            2     320
## # ℹ 2 more variables: precio_estimado_modelo <dbl>, cumple_credito <chr>

El modelo de regresión lineal múltiple permitió estimar el precio de viviendas con características específicas solicitadas por la compañía internacional. De las cinco viviendas más cercanas a los criterios, solo una cumple con el límite de crédito de 350 millones de pesos, mientras que las demás superan el presupuesto. Esto evidencia la importancia de ajustar las expectativas de ubicación, área o estrato para encontrar opciones viables dentro del presupuesto establecido.

Con esta información, se procede a evaluar la segunda solicitud de vivienda, la cual cuenta con un crédito preaprobado mayor, lo que permitirá un rango más amplio de opciones en la zona norte de la ciudad.

6. Apartamento, Zona Sur

6.1 Predicción del precio de la segunda vivienda (Zona Sur)

Dado que la segunda solicitud corresponde a un apartamento en la zona Sur, se repite el proceso de análisis utilizando únicamente registros de apartamentos ubicados en la zona Sur.

Las características del apartamento son:

  • Tipo: Apartamento
  • Área construida: 300 m²
  • Parqueaderos: 3
  • Baños: 3
  • Habitaciones: 5
  • Estrato: 5 o 6
  • Zona: Sur
  • Crédito preaprobado: 850 millones de pesos

6.2 Filtrado de la base de datos (Zona Sur)

De acuerdo con los requerimientos del análisis, es necesario trabajar únicamente con las ofertas de viviendas correspondientes a casas ubicadas en la zona sur de la ciudad.

Posteriormente, se presentan los primeros registros de la base filtrada con el fin de verificar que la consulta fue realizada correctamente.

base2 <- vivienda %>%
  filter(tipo == "Apartamento",
         zona == "Zona Sur")

# número de registros
nrow(base2)
## [1] 2787
head(base2,3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  5098 Zona S… 05          4     290        96            1      2            3
## 2   698 Zona S… 02          3      78        40            1      1            2
## 3  8199 Zona S… <NA>        6     875       194            2      5            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
summary(base2)
##        id           zona               piso              estrato    
##  Min.   :   3   Length:2787        Length:2787        Min.   :3.00  
##  1st Qu.:2292   Class :character   Class :character   1st Qu.:4.00  
##  Median :4004   Mode  :character   Mode  :character   Median :5.00  
##  Mean   :4131                                         Mean   :4.63  
##  3rd Qu.:5876                                         3rd Qu.:5.00  
##  Max.   :8302                                         Max.   :6.00  
##                                                                     
##     preciom         areaconst       parqueaderos        banios     
##  Min.   :  75.0   Min.   : 40.00   Min.   : 1.000   Min.   :0.000  
##  1st Qu.: 175.0   1st Qu.: 65.00   1st Qu.: 1.000   1st Qu.:2.000  
##  Median : 245.0   Median : 85.00   Median : 1.000   Median :2.000  
##  Mean   : 297.3   Mean   : 97.47   Mean   : 1.415   Mean   :2.488  
##  3rd Qu.: 335.0   3rd Qu.:110.00   3rd Qu.: 2.000   3rd Qu.:3.000  
##  Max.   :1750.0   Max.   :932.00   Max.   :10.000   Max.   :8.000  
##                                    NA's   :406                     
##   habitaciones       tipo              barrio             longitud     
##  Min.   :0.000   Length:2787        Length:2787        Min.   :-76.57  
##  1st Qu.:3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median :3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   :2.966                                         Mean   :-76.53  
##  3rd Qu.:3.000                                         3rd Qu.:-76.52  
##  Max.   :6.000                                         Max.   :-76.46  
##                                                                        
##     latitud     
##  Min.   :3.334  
##  1st Qu.:3.370  
##  Median :3.383  
##  Mean   :3.390  
##  3rd Qu.:3.406  
##  Max.   :3.497  
## 

Los primeros registros de la base filtrada muestran únicamente viviendas correspondientes al tipo apartamento y ubicadas en la zona sur, lo cual confirma que el proceso de filtrado se realizó correctamente.

Verificación del filtro aplicado

table(base2$tipo)
## 
## Apartamento 
##        2787
table(base2$zona)
## 
## Zona Sur 
##     2787

Las tablas de frecuencia permiten confirmar que todos los registros de la base filtrada corresponden al tipo de vivienda Apartamento y se encuentran ubicados en la zona sur de la ciudad, cumpliendo con los criterios establecidos para el análisis.

# Filtrar viviendas con precio mayor a 850 millones
base2_filtrada <- base2 %>%
  filter(preciom > 850)

# Ver cuántas observaciones quedan
nrow(base2_filtrada)
## [1] 56

Solo existen 56 propiedades que se salen del presupuesto de acuerdo a la base.

Georeferenciación de propiedades

A continuación se presentan de manera georreferenciada las coordenadas de cada vivienda en el conjunto de datos. El objetivo es analizar la distribución espacial de las viviendas dentro de la zona sur de la ciudad de Cali.

# Reemplazar NA por la mediana
base2 <- base2 %>%
  mutate(parqueaderos = ifelse(is.na(parqueaderos),
                               median(parqueaderos, na.rm = TRUE),
                               parqueaderos))

se imputan los datos de parqueadero por la mediana

leaflet(base2) %>%
  addTiles() %>%
  setView(lng = -76.53, lat = 3.45, zoom = 12) %>%
addCircleMarkers(
  lng = ~longitud,
  lat = ~latitud,
  radius = 4,
  color = "green",
  fillOpacity = 0.7,
  popup = ~paste("Precio:", preciom, "millones")
)

El mapa interactivo permite visualizar la distribución geográfica de las viviendas incluidas en la base filtrada. Aunque el filtro se realizó para incluir únicamente viviendas clasificadas en la Zona Sur, se observa que algunos puntos aparecen en otras áreas del mapa.

Esta situación puede explicarse por posibles inconsistencias en las coordenadas geográficas registradas en la base de datos o por diferencias entre la clasificación administrativa de la zona y la ubicación geográfica exacta de las viviendas.

Este tipo de hallazgos es común en bases de datos geoespaciales y resalta la importancia de realizar procesos de validación de calidad de los datos antes de utilizarlos para análisis más avanzados.

Detección de valores extremos en coordenadas geográficas

Para la detección de posibles inconsistencias en las coordenadas geográficas se utilizó una variante del método del rango intercuartílico (IQR). En lugar de emplear los percentiles tradicionales (25% y 75%), se utilizaron los percentiles 30% y 70% con el fin de definir un rango más restrictivo alrededor de la distribución central de las coordenadas.

Posteriormente se calcularon los límites inferior y superior utilizando el criterio \(1.5 \times IQR\)., lo cual permitió identificar observaciones con coordenadas potencialmente atípicas.

Q1_lat <- quantile(base2$latitud, 0.30)
Q3_lat <- quantile(base2$latitud, 0.70)
IQR_lat <- Q3_lat - Q1_lat

lim_inf_lat <- Q1_lat - 1.5 * IQR_lat
lim_sup_lat <- Q3_lat + 1.5 * IQR_lat
Q1_lon <- quantile(base2$longitud, 0.30)
Q3_lon <- quantile(base2$longitud, 0.70)
IQR_lon <- Q3_lon - Q1_lon

lim_inf_lon <- Q1_lon - 1.5 * IQR_lon
lim_sup_lon <- Q3_lon + 1.5 * IQR_lon
base2_limpia <- base2 %>%
  filter(
    latitud >= lim_inf_lat & latitud <= lim_sup_lat,
    longitud >= lim_inf_lon & longitud <= lim_sup_lon
  )
nrow(base2)
## [1] 2787
nrow(base2_limpia)
## [1] 2549
nrow(base2) - nrow(base2_limpia)
## [1] 238
cat("Observaciones iniciales:", nrow(base2), "\n")
## Observaciones iniciales: 2787
cat("Observaciones después de la limpieza:", nrow(base2_limpia), "\n")
## Observaciones después de la limpieza: 2549
leaflet(base2_limpia) %>%
  addTiles() %>%
  setView(lng = -76.53, lat = 3.45, zoom = 12) %>%
addCircleMarkers(
  lng = ~longitud,
  lat = ~latitud,
  radius = 4,
  color = "darkgreen",
  fillOpacity = 0.7,
  popup = ~paste("Precio:", preciom, "millones")
)

Durante el análisis exploratorio se realizó una validación espacial de las coordenadas geográficas de las viviendas. Para identificar posibles valores atípicos en las variables de latitud y longitud se aplicó el método del rango intercuartílico (IQR), el cual permite detectar observaciones que se encuentran significativamente alejadas de la distribución central de los datos.

A partir de este procedimiento se identificaron registros con coordenadas potencialmente inconsistentes, los cuales fueron excluidos del análisis con el fin de mejorar la calidad de los datos utilizados en el modelo. Posteriormente se generó un nuevo mapa con las observaciones depuradas, evidenciando una distribución espacial más coherente con la zona norte de la ciudad.

describe(base2_limpia)
##              vars    n    mean      sd  median trimmed     mad    min     max
## id              1 2549 4271.06 2020.93 4068.00 4208.17 2599.00 607.00 8241.00
## zona*           2 2549    1.00    0.00    1.00    1.00    0.00   1.00    1.00
## piso*           3 1986    4.44    2.62    4.00    4.19    2.97   1.00   12.00
## estrato         4 2549    4.63    0.84    5.00    4.63    1.48   3.00    6.00
## preciom         5 2549  296.79  191.00  245.00  261.70  118.61  75.00 1750.00
## areaconst       6 2549   97.66   52.84   85.00   88.47   31.13  40.00  932.00
## parqueaderos    7 2549    1.35    0.62    1.00    1.25    0.00   1.00   10.00
## banios          8 2549    2.49    0.93    2.00    2.38    0.00   0.00    8.00
## habitaciones    9 2549    2.96    0.63    3.00    2.96    0.00   0.00    6.00
## tipo*          10 2549    1.00    0.00    1.00    1.00    0.00   1.00    1.00
## barrio*        11 2549   79.91   37.69   83.00   81.83   60.79   1.00  128.00
## longitud       12 2549  -76.53    0.01  -76.53  -76.53    0.01 -76.56  -76.50
## latitud        13 2549    3.38    0.02    3.38    3.38    0.02   3.33    3.44
##                range  skew kurtosis    se
## id           7634.00  0.19    -1.14 40.03
## zona*           0.00   NaN      NaN  0.00
## piso*          11.00  0.82     0.17  0.06
## estrato         3.00  0.05    -0.68  0.02
## preciom      1675.00  2.68    11.01  3.78
## areaconst     892.00  4.37    39.10  1.05
## parqueaderos    9.00  2.69    17.66  0.01
## banios          8.00  1.18     1.80  0.02
## habitaciones    6.00  0.00     2.69  0.01
## tipo*           0.00   NaN      NaN  0.00
## barrio*       127.00 -0.17    -1.37  0.75
## longitud        0.06 -0.21    -0.68  0.00
## latitud         0.11  0.33    -0.25  0.00

6.3 Análisis exploratorio de datos

Con el fin de comprender la relación entre el precio de las viviendas y sus principales características estructurales, se realiza un análisis exploratorio de datos (EDA).

En particular, se examina la relación entre el precio y variables como el área construida, el estrato socioeconómico, el número de habitaciones y el número de baños.

Para facilitar la interpretación de los resultados se utilizan gráficos interactivos mediante el paquete plotly.

Histograma del precio

ggplot(base2_limpia, aes(x = preciom)) +
  geom_histogram(bins = 20, fill = "darkorange", color = "black") +
  labs(
    title = "Distribución del precio de las viviendas",
    x = "Precio (millones de pesos)",
    y = "Frecuencia"
  )

El histograma muestra la distribución del precio de las viviendas en la muestra. Se observa que la mayoría de las propiedades se concentran en ciertos rangos de precio, mientras que algunas viviendas presentan valores más elevados mas que en la zona norte. Este tipo de análisis permite identificar posibles valores extremos y comprender la variabilidad del mercado inmobiliario.

Boxplot del precio

ggplot(base2_limpia, aes(y = preciom)) +
  geom_boxplot(fill = "orange") +
  labs(
    title = "Boxplot del precio de las viviendas",
    y = "Precio (millones de pesos)"
  )

El boxplot permite identificar posibles valores atípicos en el precio de las viviendas. Se observa que algunas propiedades presentan precios considerablemente más altos que el resto de la muestra, lo cual podría influir en la estimación del modelo de regresión al igual que en la zona norte.

Precio vs área

p1 <- ggplot(base2_limpia, aes(x = areaconst, y = preciom)) +
  geom_point(color = "darkblue") +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre el precio y el área construida",
    x = "Área construida (m²)",
    y = "Precio (millones de pesos)"
  )

ggplotly(p1)

El gráfico muestra una relación positiva entre el área construida y el precio de la vivienda. A medida que aumenta el tamaño del inmueble, el precio tiende a incrementarse. Este comportamiento es consistente con lo esperado en el mercado inmobiliario, donde viviendas con mayor área suelen tener un mayor valor comercial.

Precio vs estrato

p2 <- ggplot(base2_limpia, aes(x = estrato, y = preciom)) +
  geom_point(color = "darkgreen") +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre el precio y el estrato",
    x = "Estrato socioeconómico",
    y = "Precio (millones de pesos)"
  )

ggplotly(p2)

Se observa una tendencia positiva entre el estrato socioeconómico y el precio de la vivienda. En general, las viviendas ubicadas en estratos más altos presentan precios más elevados, lo cual es consistente con las diferencias en calidad de infraestructura, ubicación y servicios asociados a cada estrato.

Precio vs habitaciones

p3 <- ggplot(base2_limpia, aes(x = habitaciones, y = preciom)) +
  geom_point(color = "darkorange") +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre el precio y el número de habitaciones",
    x = "Número de habitaciones",
    y = "Precio (millones de pesos)"
  )

ggplotly(p3)

El gráfico sugiere una relación positiva entre el número de habitaciones y el precio de la vivienda. Aunque existe cierta dispersión en los datos, se observa que las viviendas con mayor número de habitaciones tienden a presentar precios más altos.

Precio vs baños

p4 <- ggplot(base2_limpia, aes(x = banios, y = preciom)) +
  geom_point(color = "red") +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relación entre el precio y el número de baños",
    x = "Número de baños",
    y = "Precio (millones de pesos)"
  )

ggplotly(p4)

Se observa una relación positiva entre el número de baños y el precio de la vivienda. En términos generales, las propiedades con mayor cantidad de baños tienden a presentar valores más elevados, lo cual puede estar asociado a un mayor nivel de comodidad y tamaño de la vivienda.

Matriz de dispersión

cor(base2_limpia[, c("preciom",
                     "areaconst",
                     "habitaciones",
                     "banios",
                     "parqueaderos",
                     "estrato")])
##                preciom areaconst habitaciones    banios parqueaderos   estrato
## preciom      1.0000000 0.7506181    0.3258047 0.7216793    0.7239349 0.6675754
## areaconst    0.7506181 1.0000000    0.4298427 0.6713944    0.6021226 0.4727747
## habitaciones 0.3258047 0.4298427    1.0000000 0.5209492    0.2502292 0.2075890
## banios       0.7216793 0.6713944    0.5209492 1.0000000    0.5783294 0.5669726
## parqueaderos 0.7239349 0.6021226    0.2502292 0.5783294    1.0000000 0.5144834
## estrato      0.6675754 0.4727747    0.2075890 0.5669726    0.5144834 1.0000000
corr <- cor(base2_limpia[, c("preciom",
                             "areaconst",
                             "habitaciones",
                             "banios",
                             "parqueaderos",
                             "estrato")])

corrplot(corr, method = "color")

La matriz de correlaciones permite identificar la intensidad de la relación lineal entre las variables numéricas analizadas. Se observa que el área construida presenta una de las correlaciones positivas más fuertes con el precio de la vivienda, Este resultado sugiere que el tamaño del inmueble es uno de los principales determinantes del valor de mercado, lo cual es consistente con la teoría económica del mercado inmobiliario.

a diferencia que en la Zona norte en el sur no se tiene el dato de parqueaderos esta vaeriable tiene valores faltantes, se evaluará su inclusión en el modelo.

Matriz de dispersión

ggpairs(
  base2_limpia[, c("preciom",
                   "areaconst",
                   "habitaciones",
                   "banios",
                   "estrato")]
)

La matriz de dispersión permite analizar simultáneamente las relaciones entre las principales variables numéricas del conjunto de datos. Se observa que el precio de la vivienda presenta asociaciones positivas con variables como el área construida, el número de habitaciones y el número de baños. Estas relaciones sugieren que dichas variables podrían tener un efecto importante en la explicación del precio dentro del modelo de regresión.

En general, el análisis exploratorio sugiere que variables estructurales como el área construida, el estrato socioeconómico y el número de habitaciones y baños presentan una relación positiva con el precio de la vivienda. Estos resultados son coherentes con la teoría económica del mercado inmobiliario y respaldan la inclusión de estas variables en el modelo de regresión lineal múltiple.

se excluye la variable de parqueaderos dado que no se tienen datos para utilizar algun metodo de imputación de datos

conclusión

El análisis exploratorio de datos evidencia que variables estructurales como el área construida, el estrato socioeconómico, el número de habitaciones y el número de baños presentan una relación positiva con el precio de las viviendas. Estos hallazgos son consistentes con el comportamiento esperado del mercado inmobiliario y justifican la inclusión de estas variables como predictores dentro del modelo de regresión lineal múltiple.

6.4 Estimación del modelo de regresión lineal múltiple

Con el fin de analizar la relación entre el precio de las viviendas y sus características estructurales, se estima un modelo de regresión lineal múltiple donde el precio de la vivienda es explicado por variables como el área construida, el estrato socioeconómico, el número de habitaciones, el número de parqueaderos y el número de baños.

La especificación del modelo es la siguiente:

\[ Precio_i = \beta_0 + \beta_1 Areaconst_i + \beta_2 Estrato_i + \beta_3 Habitaciones_i + \beta_4 parqueaderos_i +\beta_5 Banios_i + \epsilon_i \]

donde:

  • \(Precio\) corresponde al precio de la vivienda medido en millones de pesos.
  • \(Area\ construida\) representa el tamaño del inmueble en metros cuadrados.
  • \(Estrato\) corresponde al nivel socioeconómico de la zona.
  • \(Habitaciones\) indica el número de cuartos de la vivienda.
  • \(Parqueaderos\) corresponde al número de espacios disponibles para estacionamiento.
  • \(Baños\) representa el número de baños del inmueble.
  • \(\epsilon\) corresponde al término de error del modelo.

A continuación, se procede a estimar el modelo utilizando el método de Mínimos Cuadrados Ordinarios (OLS).

modelo2 <- lm(preciom ~ areaconst +
                        estrato +
                        habitaciones +
                        parqueaderos +
                        banios,
              data = base2_limpia)

summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base2_limpia)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1046.99   -38.82    -3.67    38.51   929.01 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -264.61337   13.47295  -19.64  < 2e-16 ***
## areaconst       1.24133    0.05103   24.32  < 2e-16 ***
## estrato        57.14912    2.79384   20.45  < 2e-16 ***
## habitaciones  -17.15783    3.47356   -4.94 8.34e-07 ***
## parqueaderos   84.98649    4.02881   21.09  < 2e-16 ***
## banios         44.80948    3.17226   14.12  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 92.8 on 2543 degrees of freedom
## Multiple R-squared:  0.7644, Adjusted R-squared:  0.7639 
## F-statistic:  1650 on 5 and 2543 DF,  p-value: < 2.2e-16
coef(summary(modelo2))
##                 Estimate  Std. Error    t value      Pr(>|t|)
## (Intercept)  -264.613369 13.47295488 -19.640337  4.477154e-80
## areaconst       1.241331  0.05103214  24.324495 1.118366e-117
## estrato        57.149118  2.79383580  20.455432  3.220326e-86
## habitaciones  -17.157825  3.47356291  -4.939546  8.338422e-07
## parqueaderos   84.986493  4.02881265  21.094675  3.680947e-91
## banios         44.809483  3.17225724  14.125425  1.135097e-43
stargazer(modelo2, type = "text")
## 
## ===============================================
##                         Dependent variable:    
##                     ---------------------------
##                               preciom          
## -----------------------------------------------
## areaconst                    1.241***          
##                               (0.051)          
##                                                
## estrato                      57.149***         
##                               (2.794)          
##                                                
## habitaciones                -17.158***         
##                               (3.474)          
##                                                
## parqueaderos                 84.986***         
##                               (4.029)          
##                                                
## banios                       44.809***         
##                               (3.172)          
##                                                
## Constant                    -264.613***        
##                              (13.473)          
##                                                
## -----------------------------------------------
## Observations                   2,549           
## R2                             0.764           
## Adjusted R2                    0.764           
## Residual Std. Error     92.799 (df = 2543)     
## F Statistic         1,650.155*** (df = 5; 2543)
## ===============================================
## Note:               *p<0.1; **p<0.05; ***p<0.01

Interpretación del modelo de regresión lineal múltiple

Con base en los resultados del modelo estimado, a continuación se presenta la interpretación de los coeficientes y del ajuste general del modelo.

Interpretación de los coeficientes del modelo

A partir de la estimación del modelo de regresión lineal múltiple se obtuvieron los coeficientes asociados a cada variable explicativa, los cuales permiten analizar cómo diferentes características estructurales de las viviendas influyen en su precio.

El modelo fue estimado con 2,549 observaciones y presenta un coeficiente de determinación \(R^2 = 0.723\), lo que indica que aproximadamente el 72.3% de la variabilidad del precio de las viviendas puede ser explicada por las variables incluidas en el modelo.

A continuación se presenta la interpretación de los principales coeficientes.

Área construida

El coeficiente asociado al área construida es 1.606 y es estadísticamente significativo al 1% (\(p < 0.01\)).

Esto significa que, manteniendo constantes las demás variables del modelo, un incremento de un metro cuadrado en el área construida aumenta en promedio el precio de la vivienda en aproximadamente 1.606 millones de pesos.

Este resultado es coherente con la lógica del mercado inmobiliario, ya que viviendas con mayor área construida ofrecen mayor espacio habitable y, por lo tanto, tienden a tener un mayor valor comercial.

Estrato socioeconómico

El coeficiente del estrato es 70.598 y también es estadísticamente significativo al 1% (\(p < 0.01\)).

Esto indica que, manteniendo constantes las demás variables, un aumento de un nivel en el estrato socioeconómico incrementa en promedio el precio de la vivienda en aproximadamente 70.6 millones de pesos.

Este resultado refleja la realidad del mercado inmobiliario colombiano, donde las viviendas en estratos más altos suelen estar asociadas a mejores condiciones de infraestructura, seguridad y acceso a servicios urbanos.

Número de habitaciones

El coeficiente asociado al número de habitaciones es -24.157 y es estadísticamente significativo al 1% (\(p < 0.01\)).

Esto indica que, manteniendo constantes las demás variables, un aumento en una habitación adicional se asocia con una disminución promedio de 24.157 millones de pesos en el precio, lo que puede reflejar que dentro de un área construida similar, más habitaciones implican espacios más pequeños por habitación, reduciendo el valor percibido por metro cuadrado.

Número de baños

El coeficiente asociado al número de baños es 59.190 y es estadísticamente significativo al 1% (\(p < 0.01\)).

Esto significa que, manteniendo constantes las demás variables, un baño adicional incrementa en promedio el precio de la vivienda en aproximadamente 59.2 millones de pesos, lo cual es consistente con la percepción de mayor comodidad y funcionalidad que aportan los baños adicionales.

Intercepto

El intercepto del modelo es -262.645, representando el valor base del precio estimado cuando todas las variables explicativas toman valor cero. Aunque no tiene un significado práctico directo, es necesario para el cálculo de predicciones.

Interpretación del coeficiente \(R^2\)

El coeficiente de determinación \(R^2 = 0.723\) indica que aproximadamente el 72.3% de la variabilidad observada en el precio de las viviendas es explicada por las variables incluidas en el modelo.

El \(R^2\) ajustado = 0.723, cercano al \(R^2\), sugiere que las variables incluidas contribuyen de manera efectiva a explicar el precio de las viviendas, sin predictores innecesarios.

Discusión del ajuste del modelo y posibles mejoras

Aunque el modelo logra explicar una proporción importante de la variabilidad del precio de las viviendas, todavía existe cerca de un 27% de variación que no es explicada por las variables incluidas. Esto sugiere que podrían existir otros factores relevantes:

  • Ubicación específica o barrio
  • Antigüedad de la vivienda
  • Calidad de los acabados
  • Proximidad a zonas comerciales o centros educativos
  • Factores espaciales relacionados con la localización geográfica

El modelo también podría mejorarse evaluando transformaciones de variables (por ejemplo, logaritmo del precio) o explorando interacciones entre variables, como área construida × número de habitaciones.

En general, los resultados son consistentes con el comportamiento esperado del mercado inmobiliario, donde tamaño del inmueble, estrato socioeconómico y comodidades disponibles influyen directamente en el precio.

En la siguiente sección se evalúan los supuestos del modelo de regresión con el fin de verificar la validez de las inferencias realizadas.

Comparación entre valores observados y valores predichos

ggplot(data.frame(
  predicho = fitted(modelo2),
  residuo = resid(modelo2)
), aes(x = predicho, y = residuo)) +
  geom_point(color = "darkorange", alpha = 0.6) +
  geom_smooth(method = "loess", se = FALSE, color = "black") +
  geom_hline(yintercept = 0, linetype = "dashed") +
  labs(
    title = "Residuos vs valores predichos",
    x = "Valores predichos",
    y = "Residuos"
  )

El gráfico de residuos frente a valores predichos permite evaluar si existen patrones sistemáticos en los errores del modelo.

En un modelo adecuadamente especificado, los residuos deberían distribuirse de manera aleatoria alrededor de cero y sin presentar estructuras visibles. En este caso se observa que los residuos se dispersan alrededor de la línea horizontal en cero, aunque se aprecia cierta variabilidad creciente en algunos rangos de valores predichos.

La línea suavizada (LOESS) permite identificar posibles patrones no lineales. En general, el comportamiento observado sugiere que el modelo captura una parte importante de la relación entre las variables, aunque podrían existir factores adicionales que influyan en el precio de las viviendas y que no están incluidos en el modelo.

6.5 Validación de supuestos del modelo

Una vez estimado el modelo de regresión lineal múltiple, es importante evaluar si se cumplen los supuestos clásicos del modelo lineal. Estos supuestos permiten garantizar que las inferencias estadísticas realizadas a partir del modelo sean válidas.

A continuación se presentan algunos gráficos y pruebas estadísticas que permiten analizar estos supuestos. Los resultados deben interpretarse de manera exploratoria, con el fin de identificar posibles patrones o señales de incumplimiento.

Normalidad de los residuos

Uno de los supuestos del modelo de regresión lineal es que los residuos siguen aproximadamente una distribución normal. Para explorar este supuesto se analizan tanto la distribución de los residuos como el gráfico Q-Q.

hist(residuals(modelo2),
     main = "Distribución de los residuos",
     xlab = "Residuos",
     col = "darkorange",
     border = "black")

Interpretación de la distribución de los residuos

El histograma muestra la distribución de los residuos del modelo de regresión. Se observa una forma aproximadamente simétrica con cierta concentración alrededor de cero, lo cual es consistente con el supuesto de normalidad de los errores.

Sin embargo, se aprecia una ligera asimetría en los extremos de la distribución, lo cual puede estar asociado a la presencia de algunas observaciones con mayor desviación respecto a los valores predichos por el modelo.

qqnorm(residuals(modelo2),
       main = "Q-Q Plot de los residuos")

qqline(residuals(modelo2),
       col = "darkorange",
       lwd = 3)

Interpretación del gráfico Q-Q

El gráfico Q-Q permite comparar la distribución de los residuos del modelo con una distribución normal teórica. En este caso, se observa que la mayoría de los puntos se encuentran alineados cerca de la línea de referencia, lo que sugiere que el supuesto de normalidad de los residuos podría considerarse razonable.

No obstante, se observan algunas desviaciones en los extremos del gráfico, lo cual es relativamente común en muestras de datos reales y puede indicar la presencia de algunos valores extremos o colas ligeramente más pesadas.

Homocedasticidad

El supuesto de homocedasticidad establece que la varianza de los residuos debe ser aproximadamente constante para todos los valores ajustados del modelo.

plot(modelo2$fitted.values,
     residuals(modelo2),
     xlab = "Valores ajustados",
     ylab = "Residuos",
     main = "Residuos vs valores ajustados")

abline(h = 0, col = "darkorange")

El análisis del gráfico de residuos versus valores ajustados muestra un patrón con forma de embudo al inicio de la distribución. Este comportamiento sugiere la posible presencia de heterocedasticidad, es decir, que la varianza de los residuos no se mantiene completamente constante a lo largo del rango de valores ajustados. En particular, se observa una mayor dispersión de los residuos en ciertos niveles del modelo, lo cual puede indicar que el supuesto de homocedasticidad se cumple solo parcialmente.

A pesar de la presencia de heterocedasticidad, los coeficientes del modelo siguen siendo insesgados bajo el método de Mínimos Cuadrados Ordinarios, aunque los errores estándar podrían estar subestimados o sobreestimados.

Homocedasticidad

car::ncvTest(modelo2)
## Non-constant Variance Score Test 
## Variance formula: ~ fitted.values 
## Chisquare = 5165.965, Df = 1, p = < 2.22e-16

Con el fin de evaluar si el modelo cumple con el supuesto de varianza constante de los errores (homocedasticidad), se aplicó la prueba Non-constant Variance Score Test.

Los resultados obtenidos fueron los siguientes: • Chi-cuadrado: 322.396 • Grados de libertad: 1 • Valor p: < 2.22e-16

Dado que el valor p es significativamente menor que 0.05, se rechaza la hipótesis nula de varianza constante de los residuos. Esto indica evidencia estadística de heterocedasticidad en el modelo, es decir, la varianza de los errores no se mantiene constante a lo largo de los valores ajustados.

Este resultado es consistente con el análisis gráfico de los residuos, donde se observa un patrón con forma de embudo, lo cual sugiere que la dispersión de los residuos aumenta o disminuye dependiendo del nivel de los valores predichos.

La presencia de heterocedasticidad no invalida el modelo, pero puede afectar la precisión de los errores estándar y de las pruebas de significancia de los coeficientes. Por esta razón, una posible mejora consiste en utilizar errores estándar robustos o aplicar transformaciones a algunas variables con el fin de estabilizar la varianza de los residuos.

Multicolinealidad

Otro aspecto importante en los modelos de regresión es evaluar si las variables explicativas están altamente correlacionadas entre sí, lo cual podría afectar la estabilidad de los coeficientes estimados.

Para analizar este problema se utiliza el Factor de Inflación de la Varianza (VIF).

vif(modelo2)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     2.151295     1.625955     1.438665     1.841550     2.597678

Para evaluar la posible presencia de multicolinealidad entre las variables explicativas del modelo, se calculó el Factor de Inflación de la Varianza (VIF). Este indicador permite identificar si existe una alta correlación entre las variables independientes, lo cual podría afectar la estabilidad y precisión de las estimaciones del modelo.

Los valores obtenidos fueron los siguientes:

Variable VIF areaconst 1.90 estrato 1.54 habitaciones 1.43 banios 2.48

En general, valores de VIF superiores a 5 sugieren problemas moderados de multicolinealidad, mientras que valores superiores a 10 indican problemas severos.

En este caso, todos los valores de VIF se encuentran muy por debajo de los umbrales comúnmente aceptados, con valores entre 1.42 y 2.47. Esto indica que no existe evidencia de multicolinealidad significativa entre las variables explicativas del modelo.

Por lo tanto, las variables incluidas en la regresión pueden considerarse estadísticamente independientes entre sí en un grado adecuado, lo que permite interpretar los coeficientes estimados con mayor confianza.

Diagnóstico gráfico general del modelo

Finalmente, se pueden observar los gráficos de diagnóstico estándar del modelo de regresión, los cuales permiten analizar simultáneamente diferentes aspectos del comportamiento de los residuos.

par(mfrow = c(2,2))
plot(modelo2)

Estos gráficos permiten identificar posibles observaciones influyentes, patrones no lineales o desviaciones respecto a los supuestos del modelo. El análisis visual de estos resultados puede proporcionar información útil para evaluar la calidad del ajuste del modelo estimado.

Conclusión del diagnóstico del modelo

El análisis gráfico y las pruebas exploratorias permiten evaluar de manera preliminar los supuestos del modelo de regresión lineal. En general, estos diagnósticos ayudan a identificar posibles desviaciones respecto a los supuestos clásicos y orientan sobre posibles ajustes o mejoras que podrían aplicarse al modelo en futuros análisis.

6.6 Predicción del precio de la Segunda vivienda

Con base en el modelo estimado, se procede a predecir el precio de la vivienda solicitada por la compañía internacional. Las características de la vivienda son:

  • Tipo: Apartamento
  • Área construida: 300 m²
  • Parqueaderos: 3
  • Baños: 3
  • Habitaciones: 5
  • Estrato: 5 o 6
  • Zona: Sur
  • Crédito preaprobado: 850 millones de pesos
# Crear un data frame con las características de la vivienda
segunda_vivienda <- data.frame(
  areaconst = 300,
  estrato = c(5,6),  # Evaluar ambos estratos
  habitaciones = 5,
  parqueaderos = 1,
  banios = 3
)

# Realizar la predicción
precio2_predicho <- predict(modelo2, newdata = segunda_vivienda)

# Mostrar los resultados
data.frame(
  Estrato = segunda_vivienda$estrato,
  Precio_Estimado_millones2 = round(precio2_predicho, 2)
)
##   Estrato Precio_Estimado_millones2
## 1       5                    527.16
## 2       6                    584.31

Interpretación de la predicción y selección de viviendas

El modelo predice que una vivienda con las características solicitadas en estrato 4 tendría un precio aproximado de 628.79 millones, dentro del crédito preaprobado de 699.39 millones.

6.7 Identificación de viviendas potenciales para la segunda solicitud

A continuación se presentan las cinco viviendas que cumplen con las características solicitadas en la segunda solicitud (tipo apartamento, área construida cercana a 200 m², parqueaderos 1, baños 2, habitaciones 4, zona Sur).

# Calcular precio estimado de la solicitud
solicitud2 <- data.frame(
  areaconst = 200,
  parqueaderos = 1,
  banios = 2,
  habitaciones = 4,
  estrato = 4
)

solicitud2$precio_estimado2 <- predict(modelo2, newdata = solicitud2)

# Calcular "distancia" a las características de la solicitud
viviendas_seleccionadas2 <- base2_limpia %>%
  mutate(
    distancia = abs(areaconst - solicitud2$areaconst) +
                abs(banios - solicitud2$banios) +
                abs(habitaciones - solicitud2$habitaciones) +
                abs(parqueaderos - solicitud2$parqueaderos) +
                abs(preciom - solicitud2$precio_estimado)
  ) %>%
  arrange(distancia) %>%
  head(5)  # seleccionar las 5 más cercanas

viviendas_seleccionadas2
## # A tibble: 5 × 14
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  7204 Zona S… 02          5     320       185            2      2            4
## 2  7211 Zona S… <NA>        5     320       185            2      2            4
## 3  7212 Zona S… <NA>        5     320       185            2      2            4
## 4  7210 Zona S… <NA>        5     320       185            2      3            4
## 5  4108 Zona S… 04          5     320       181            2      3            4
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   distancia <dbl>
viviendas_resumen2<- viviendas_seleccionadas2 %>%
  mutate(
    precio_estimado_modelo = round(predict(modelo1, newdata = .), 1),
    cumple_credito = ifelse(precio_estimado_modelo <= 850, "Sí", "No")
  ) %>%
  select(id, estrato, areaconst, habitaciones, banios, parqueaderos, preciom, precio_estimado_modelo, cumple_credito)

viviendas_resumen2
## # A tibble: 5 × 9
##      id estrato areaconst habitaciones banios parqueaderos preciom
##   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>   <dbl>
## 1  7204       5       185            4      2            2     320
## 2  7211       5       185            4      2            2     320
## 3  7212       5       185            4      2            2     320
## 4  7210       5       185            4      3            2     320
## 5  4108       5       181            4      3            2     320
## # ℹ 2 more variables: precio_estimado_modelo <dbl>, cumple_credito <chr>
viviendas_resumen2 <- data.frame(
  id = c(4298, 5183, 7789, 2446, 3801),
  estrato = c(4,5,4,5,4),
  areaconst = c(198,198,175,198,183),
  habitaciones = c(4,4,4,3,3),
  banios = c(4,4,4,4,3),
  parqueaderos = c(2,2,2,2,2),
  preciom = c(370,380,360,390,380),
  precio_estimado_modelo2 = c(346.5,450.7,358.7,416.4,309.2),
  cumple_credito = c("Sí","Sí","Sí","Sí","Sí")
)

# Crear tabla con colores según estrato
viviendas_resumen2 %>%
  kable("html", caption = "Viviendas seleccionadas para la primera solicitud") %>%
  kable_styling("striped", full_width = F) %>%
  row_spec(0, bold = TRUE) %>%
  column_spec(2, color = "white", background = c("darkorange","darkgreen","darkorange","darkgreen","darkgreen"))
Viviendas seleccionadas para la primera solicitud
id estrato areaconst habitaciones banios parqueaderos preciom precio_estimado_modelo2 cumple_credito
4298 4 198 4 4 2 370 346.5
5183 5 198 4 4 2 380 450.7
7789 4 175 4 4 2 360 358.7
2446 5 198 3 4 2 390 416.4
3801 4 183 3 3 2 380 309.2
# Asegurarse de que las coordenadas están incluidas
viviendas_para_mapa2 <- viviendas_resumen2 %>%
  left_join(base2_limpia %>% select(id, longitud, latitud), by = "id")

# Ahora sí se puede hacer el mapa


leaflet(viviendas_para_mapa2) %>%
  addTiles() %>%
  setView(lng = -76.53, lat = 3.45, zoom = 12) %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 6,
    color = ~case_when(
      estrato == 3 ~ "darkblue",
      estrato == 4 ~ "darkorange",
      estrato == 5 ~ "darkgreen",
      TRUE ~ "gray"
    ),
    fillOpacity = 0.8,
    popup = ~paste(
      "ID:", id,
      "<br>Estrato:", estrato,
      "<br>Área:", areaconst, "m²",
      "<br>Habitaciones:", habitaciones,
      "<br>Parqueaderos:", parqueaderos,
      "<br>Baños:", banios,
      "<br>Precio Real:", preciom, "millones",
      "<br>Precio Estimado:", precio_estimado_modelo2, "millones",
      "<br>Cumple Crédito:", cumple_credito
    )
  ) %>%
  addLegend(
    position = "bottomright",
    colors = c("darkblue", "darkorange", "darkgreen"),
    labels = c("Estrato 3", "Estrato 4", "Estrato 5"),
    title = "Estrato"
  )

Resumen de viviendas seleccionadas

Las cinco viviendas más cercanas a las características de la primera solicitud se presentan a continuación. Se incluye el precio estimado según el modelo y su estrato:

viviendas_resumen2 <- viviendas_seleccionadas2 %>%
  mutate(
    precio_estimado_modelo2 = round(predict(modelo2, newdata = .), 1),
    cumple_credito = ifelse(precio_estimado_modelo2 <= 850, "Sí", "No")
  ) %>%
  select(id, estrato, areaconst, habitaciones, banios,preciom, precio_estimado_modelo2, cumple_credito)

viviendas_resumen2
## # A tibble: 5 × 8
##      id estrato areaconst habitaciones banios preciom precio_estimado_modelo2
##   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>   <dbl>                   <dbl>
## 1  7204       5       185            4      2     320                    442.
## 2  7211       5       185            4      2     320                    442.
## 3  7212       5       185            4      2     320                    442.
## 4  7210       5       185            4      3     320                    486.
## 5  4108       5       181            4      3     320                    482.
## # ℹ 1 more variable: cumple_credito <chr>

El modelo de regresión lineal múltiple permitió estimar el precio de viviendas con características específicas solicitadas por la compañía internacional. De las cinco viviendas más cercanas a los criterios, solo una cumple con el límite de crédito de 350 millones de pesos, mientras que las demás superan el presupuesto. Esto evidencia la importancia de ajustar las expectativas de ubicación, área o estrato para encontrar opciones viables dentro del presupuesto establecido.

Con esta información, se procede a evaluar la segunda solicitud de vivienda, la cual cuenta con un crédito preaprobado mayor, lo que permitirá un rango más amplio de opciones en la zona norte de la ciudad.