Presentado por: Valentina Villa

Introducción

El objetivo de este trabajo es realizar un modelo de regresión lineal múltiple utilizando la base de datos de viviendas de la ciudad de Cali, con el fin de analizar dos solicitudes realizadas por una compañía internacional que desea ubicar a dos de sus empleados y sus familias en la ciudad.

Para la primera solicitud se busca una casa en la zona norte, con un área construida de 200 m², 1 parqueadero, 2 baños, 4 habitaciones, estrato 4 o 5 y un crédito preaprobado máximo de 350 millones de pesos. Para la segunda solicitud se busca un apartamento en la zona sur, con un área construida de 300 m², 3 parqueaderos, 3 baños, 5 habitaciones, estrato 5 o 6 y un crédito preaprobado máximo de 850 millones de pesos. A partir de estas características se realizarán los filtros correspondientes, el análisis de los datos y la estimación de los modelos, para finalmente identificar potenciales ofertas que se ajusten a las necesidades y al presupuesto de cada solicitud.

Preparación y limpieza de la base de datos original

A continuación, se carga la base de datos con la que se trabajará durante el desarrollo de esta actividad.

library(paqueteMODELOS)
library(dplyr)
library(leaflet)
library("plotly")
library(factoextra)
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>

La base de datos cuenta con 8322 registros y 13 variables que describen diferentes características de las viviendas registradas. A continuación, se presentan las variables junto con su clasificación según el tipo de dato.

Antes de realizar el filtro, se verifican los valores registrados en las variables tipo y zona ( varibles cualitativas), con el fin de identificar posibles errores de digitación o diferencias en la forma en que fueron registradas las categorías.Adicionalmente, se verifica la presencia de valores faltantes (NA) en las variables tipo y zona antes de realizar el filtro.

unique(vivienda$tipo)
## [1] "Casa"        "Apartamento" NA
unique(vivienda$zona)
## [1] "Zona Oriente" "Zona Sur"     "Zona Norte"   "Zona Oeste"   "Zona Centro" 
## [6] NA
sum(is.na(vivienda$tipo))
## [1] 3
sum(is.na(vivienda$zona))
## [1] 3
vivienda %>%
  filter(is.na(tipo))
## # A tibble: 3 × 13
##      id zona  piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr> <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1    NA <NA>  <NA>       NA      NA        NA           NA     NA           NA
## 2    NA <NA>  <NA>       NA      NA        NA           NA     NA           NA
## 3    NA <NA>  <NA>       NA     330        NA           NA     NA           NA
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
vivienda %>%
  filter(is.na(zona))
## # A tibble: 3 × 13
##      id zona  piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr> <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1    NA <NA>  <NA>       NA      NA        NA           NA     NA           NA
## 2    NA <NA>  <NA>       NA      NA        NA           NA     NA           NA
## 3    NA <NA>  <NA>       NA     330        NA           NA     NA           NA
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
#Calculemos la proporcion que representan esos 3 datos respecto a la base completa
n_total <- nrow(vivienda)
n_incompletos <- sum(is.na(vivienda$tipo) & is.na(vivienda$zona))

porcentaje <- (n_incompletos / n_total) * 100

n_total
## [1] 8322
n_incompletos
## [1] 3
porcentaje
## [1] 0.03604903

Se identificaron 3 registros con valores faltantes en las variables tipo y zona. Estos registros corresponden a las mismas observaciones y presentan además ausencia de información en la mayoría de las variables. Representan aproximadamente el 0.03 % del total de la base, por lo cual se decide excluirlos del análisis. Se procede entonces a crear una base vivienda limpia.

# Nuestra base de datos completa depurada ahora es vivienda_limpia
vivienda_limpia <- vivienda %>%
  filter(!(is.na(tipo) & is.na(zona)))
sum(is.na(vivienda_limpia$tipo))
## [1] 0
sum(is.na(vivienda_limpia$zona))
## [1] 0
unique(vivienda_limpia$tipo)
## [1] "Casa"        "Apartamento"
unique(vivienda_limpia$zona)
## [1] "Zona Oriente" "Zona Sur"     "Zona Norte"   "Zona Oeste"   "Zona Centro"
length(unique(vivienda_limpia$id))
## [1] 8319
# Verificamos registros vivienda limpia
nrow(vivienda_limpia)
## [1] 8319

Al eliminar estos tres registros, tenemos entonces un total de 8319 observaciones, sin valores faltantes y con categorias unicas para las variables de tipo y zona. Finalmente, se revisan los valores mínimos y máximos de las variables numéricas y para la varibale estrato ( que es cualitativa ordinal, registrada como cuantitativa), con el fin de identificar posibles valores fuera de los rangos esperados.

summary(vivienda_limpia)
##        id           zona               piso              estrato     
##  Min.   :   1   Length:8319        Length:8319        Min.   :3.000  
##  1st Qu.:2080   Class :character   Class :character   1st Qu.:4.000  
##  Median :4160   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :4160                                         Mean   :4.634  
##  3rd Qu.:6240                                         3rd Qu.:5.000  
##  Max.   :8319                                         Max.   :6.000  
##                                                                      
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 220.0   1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 330.0   Median : 123.0   Median : 2.000   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.835   Mean   : 3.111  
##  3rd Qu.: 540.0   3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1745.0   Max.   :10.000   Max.   :10.000  
##                                    NA's   :1602                     
##   habitaciones        tipo              barrio             longitud     
##  Min.   : 0.000   Length:8319        Length:8319        Min.   :-76.59  
##  1st Qu.: 3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median : 3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   : 3.605                                         Mean   :-76.53  
##  3rd Qu.: 4.000                                         3rd Qu.:-76.52  
##  Max.   :10.000                                         Max.   :-76.46  
##                                                                         
##     latitud     
##  Min.   :3.333  
##  1st Qu.:3.381  
##  Median :3.416  
##  Mean   :3.418  
##  3rd Qu.:3.452  
##  Max.   :3.498  
## 

Al revisar la base de datos se identificaron algunos aspectos que deben tenerse en cuenta antes de realizar el análisis:

Caso 1. Casa - Zona Norte

Para el caso 1 se busca una vivienda tipo casa, con un area construida de 200 metros cuadrados, 1 parqueadero, 2 baños, 4 habitaciones, estrato 4 o 5, en zona norte y con un credito pre aprobado de 350 millones.

Filtro de casas de la Zona Norte (base 1) y verificación de la base filtrada

Para analizar la primera solicitud se realiza un filtro de la base, seleccionando únicamente las viviendas de tipo Casa ubicadas en la Zona Norte de la ciudad.

base1 <- vivienda_limpia %>%
  filter(tipo == "Casa",
         zona == "Zona Norte")
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>
dim(base1)
## [1] 722  13

En resumen, para la base 1, correspondiente a viviendas tipo Casa ubicadas en la Zona Norte de la ciudad, se obtienen 722 registros y 13 variables. Como verificación del filtro realizado, se presentan los tres primeros registros de la base 1.

Ubicación geográfica de las viviendas

A continuación, se presenta la ubicación geográfica de las viviendas correspondientes a la base 1, utilizando las coordenadas de latitud y longitud disponibles en la base de datos. Esto permite verificar visualmente la distribución de las ofertas registradas como pertenecientes a la Zona Norte de Cali. Adicionalmente, se identificaron los valores mínimo y máximo de la variable latitud ( circulos rojos), ya que esta coordenada permite observar la variación de los puntos en dirección norte-sur. Estos dos puntos se resaltan en el mapa con el fin de observar qué tan alejadas se encuentran las viviendas ubicadas en los extremos de la base 1.

extremos_latitud <- base1 %>%
  filter(
    latitud == min(latitud, na.rm = TRUE) |
    latitud == max(latitud, na.rm = TRUE)
  )

extremos_latitud
## # A tibble: 2 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1   655 Zona N… <NA>        3     280       148            2      4            4
## 2  6906 Zona N… 02          6    1080       650            2      0            7
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
leaflet(base1) %>%
  addTiles() %>%
  
  # Todas las viviendas
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 2
  ) %>%
  
  # Puntos con latitud mínima y máxima
  addCircleMarkers(
    data = extremos_latitud,
    lng = ~longitud,
    lat = ~latitud,
    radius = 7,
    color = "red",
    fillColor = "red",
    fillOpacity = 1,
    popup = ~paste(
      "Latitud:", latitud,
      "<br>Longitud:", longitud
    )
  )

Al observar el mapa se puede ver que una gran cantidad de los puntos se encuentran localizados en la Zona Norte de Cali; sin embargo, también se observa una proporción considerable de puntos ubicados en otras zonas de la ciudad, a pesar de estar clasificados en la base como Zona Norte.al comparar los extremos de la latitud, se tiene un valor máximo de 3.49584 y un mínimo de 3.33308, presentando una variación aproximada de 0.16°. Esta diferencia permite observar qué tan dispersos se encuentran los registros en dirección norte-sur. La presencia de puntos en otras zonas podría deberse a errores en las coordenadas de algunos registros o a una asignación incorrecta de la zona al momento de construir la base de datos. Debido a esto, es necesario realizar un filtro de la base 1, puesto que el objetivo del caso 1 es una vivienda localizada en la Zona Norte.

Para realizar un correcto filtrado de la base, se procede a realizar un analisis de conglomerados con el fin de observar agrupaciones de vivienda de acuerdo a las variables longitud y latitud. Pirmeramente se realizara el metodo del codo con el fin de elegir correctamente la cantidad de clusters y posteriomente se procede a realizar el PCA.

fviz_nbclust(
  base1[, c("longitud", "latitud")],
  kmeans,
  method = "wss",
  k.max = 10
) +
  labs(
    title = "Método del codo",
    x = "Número de conglomerados",
    y = "Suma de cuadrados dentro de los grupos"
  )

El método del codo sugiere, en primera instancia, trabajar con 2 conglomerados. Esta selección resulta conveniente para el propósito del análisis, ya que se busca identificar un grupo que represente las viviendas realmente ubicadas en la Zona Norte y separar aquellas observaciones que, aunque se encuentran categorizadas como Zona Norte en la base de datos, presentan una ubicación geográfica diferente.

set.seed(123)

conglomerados1 <- kmeans(
  base1[, c("longitud", "latitud")],
  centers = 2
)

base1$conglomerado <- as.factor(conglomerados1$cluster)

table(base1$conglomerado)
## 
##   1   2 
## 606 116

Al representar los conglomerados sobre el mapa con la ubicación geográfica de las observaciones de la base 1, se evidencia una clara separación entre los registros realmente ubicados en la Zona Norte de Cali y aquellos que se encuentran en otras zonas de la ciudad. De esta manera, es posible identificar el conglomerado que debe conservarse y excluir las observaciones que no cumplen con la ubicación requerida para el caso 1.

Por esta razón, se procede a excluir de la base 1 los registros pertenecientes al conglomerado que no corresponde geográficamente a la Zona Norte de Cali. De esta forma, la base queda conformada únicamente por las viviendas ubicadas en el sector de interés, y sobre esta nueva base se continuará con la revisión de calidad de los datos, el análisis exploratorio y la estimación del modelo de regresión.

## [1] 606  13

Limpieza base 1

Con base en los problemas de calidad de los datos detectados al inicio del documento, se procederá a evaluar si existen valores faltantes (NA) en las variables de interés de la base 1, así como datos inconsistentes en el número de baños y habitaciones.

# Valores faltantes
sum(is.na(base1$preciom))
## [1] 0
sum(is.na(base1$areaconst))
## [1] 0
sum(is.na(base1$estrato))
## [1] 0
sum(is.na(base1$parqueaderos))
## [1] 209
sum(is.na(base1$banios))
## [1] 0
sum(is.na(base1$habitaciones))
## [1] 0
# Valores iguales a cero
sum(base1$parqueaderos == 0, na.rm = TRUE)
## [1] 0
sum(base1$banios == 0, na.rm = TRUE)
## [1] 7
sum(base1$habitaciones == 0, na.rm = TRUE)
## [1] 11

Al analizar las variables predictoras de la base 1, se identificaron algunos aspectos relacionados con la calidad de los datos:

  • Se encontraron 209 valores faltantes (NA) en la variable parqueaderos.
  • Se identificaron 7 registros con 0 baños.
  • Se identificaron 11 registros con 0 habitaciones.
  • No se encontraron registros con 0 parqueaderos.

Las demás variables predictoras analizadas no presentan valores faltantes. Estos resultados serán tenidos en cuenta para definir posteriormente el tratamiento más adecuado antes de estimar el modelo de regresión.

Variable parqueaderos

Para los 209 valores faltantes encontrados en la variable parqueaderos se plantean tres posibles opciones para su tratamiento:

  1. Utilizar la mediana general: reemplazar los valores faltantes por la mediana de parqueaderos de todas las viviendas de la base 1.
  2. Utilizar la mediana por estrato: calcular la mediana de parqueaderos para cada estrato y reemplazar los valores faltantes de acuerdo con el estrato al que pertenece cada vivienda.
  3. Reemplazar los NA por 0: teniendo en cuenta que no existen valores iguales a 0 en la variable parqueaderos, se podría considerar que los NA corresponden a viviendas que no cuentan con parqueadero. Sin embargo, esta opción parte de un supuesto que no se puede confirmar directamente con la información disponible en la base. A continuación, se evaluarán estas opciones para determinar cuál resulta más adecuada para el tratamiento de los valores faltantes.

Para elegir entre la opción 1 y la opción 2, se procede a calcular la mediana del número de parqueaderos para cada estrato presente en la base 1 y, adicionalmente, la mediana general de toda la base. Esto con el fin de verificar qué tanto varía la mediana entre los diferentes estratos y determinar cuál de los dos métodos de imputación resulta más adecuado.

base1 %>%
  group_by(estrato) %>%
  summarise(
    n = n(),
    NA_parqueaderos = sum(is.na(parqueaderos)),
    mediana_parqueaderos = median(parqueaderos, na.rm = TRUE)
  )
## # A tibble: 4 × 4
##   estrato     n NA_parqueaderos mediana_parqueaderos
##     <dbl> <int>           <int>                <dbl>
## 1       3   210             136                  1  
## 2       4   129              36                  2  
## 3       5   233              29                  2  
## 4       6    34               8                  2.5
median(base1$parqueaderos, na.rm = TRUE)
## [1] 2

Los resultados muestran que la mediana del número de parqueaderos presenta algunas diferencias entre los estratos. Para el estrato 3 se obtiene una mediana de 1 parqueadero, para los estratos 4 y 5 una mediana de 2 y para el estrato 6 una mediana de 2.5. Por otro lado, la mediana general de la base 1 es de 2 parqueaderos. Debido a estas diferencias, se considera más adecuado realizar la imputación de los valores faltantes utilizando la mediana correspondiente a cada estrato, ya que de esta manera se tienen en cuenta las características de cada grup.Para el estrato 6 se obtuvo una mediana de 2.5 parqueaderos. Debido a que el número de parqueaderos es una variable discreta y no puede tomar este valor en la práctica, se revisó la distribución de los datos del estrato 6. El valor más frecuente corresponde a 3 parqueaderos, por lo que se utilizará este valor para imputar los registros faltantes de este estrato.

base1 <- base1 %>%
  mutate(
    parqueaderos = case_when(
      is.na(parqueaderos) & estrato == 3 ~ 1,
      is.na(parqueaderos) & estrato == 4 ~ 2,
      is.na(parqueaderos) & estrato == 5 ~ 2,
      is.na(parqueaderos) & estrato == 6 ~ 3,
      TRUE ~ parqueaderos
    )
  )
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0          279            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##            0            0            0            0            0            0 
##      latitud 
##            0

Después de realizar la imputación de la variable parqueaderos, se verificó nuevamente la presencia de valores faltantes. Se encontraron 279 valores NA correspondientes a la variable piso; sin embargo, debido a que esta variable no será utilizada como predictora en el modelo, estos valores no requieren ningún tratamiento adicional para el presente análisis.

Variable baños y habitaciones

AAhora bien, se debe resolver la situación de los registros que presentan 0 baños y/o 0 habitaciones, ya que estos valores no son usuales para una casa. Para analizar estos casos, se revisará cuántos registros presentan 0 baños y 0 habitaciones al mismo tiempo, cuántos tienen 0 baños pero sí tienen habitaciones y cuántos tienen 0 habitaciones pero sí tienen baños.

# 0 baños y 0 habitaciones
sum(base1$banios == 0 & base1$habitaciones == 0)
## [1] 6
# 0 baños pero sí tiene habitaciones
sum(base1$banios == 0 & base1$habitaciones > 0)
## [1] 1
# 0 habitaciones pero sí tiene baños
sum(base1$habitaciones == 0 & base1$banios > 0)
## [1] 5
registros_cero <- sum(
  base1$banios == 0 | base1$habitaciones == 0
)

registros_cero
## [1] 12
porcentaje_cero <- registros_cero / nrow(base1) * 100

porcentaje_cero
## [1] 1.980198

En total se identificaron 12 registros con valores iguales a 0 en baños y/o habitaciones. Estos representan aproximadamente el 2 % de las 606 observaciones de la base 1. Debido a que estos valores no son usuales para una vivienda y corresponden a una proporción pequeña de la base, se decide eliminar estos registros, considerando que su exclusión no representa una pérdida considerable de información.

base1 <- base1 %>%
  filter(banios > 0,
         habitaciones > 0)
sum(base1$banios == 0)
## [1] 0
sum(base1$habitaciones == 0)
## [1] 0
dim(base1)
## [1] 594  13
summary(base1)
##        id             zona               piso              estrato     
##  Min.   :  88.0   Length:594         Length:594         Min.   :3.000  
##  1st Qu.: 627.5   Class :character   Class :character   1st Qu.:3.000  
##  Median :1644.5   Mode  :character   Mode  :character   Median :4.000  
##  Mean   :2206.1                                         Mean   :4.158  
##  3rd Qu.:3587.5                                         3rd Qu.:5.000  
##  Max.   :8319.0                                         Max.   :6.000  
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  89.0   Min.   :  30.0   Min.   : 1.000   Min.   : 1.000  
##  1st Qu.: 240.8   1st Qu.: 138.5   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 380.0   Median : 238.5   Median : 2.000   Median : 3.000  
##  Mean   : 429.6   Mean   : 260.5   Mean   : 1.909   Mean   : 3.557  
##  3rd Qu.: 547.5   3rd Qu.: 336.8   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1940.0   Max.   :1440.0   Max.   :10.000   Max.   :10.000  
##   habitaciones       tipo              barrio             longitud     
##  Min.   : 1.00   Length:594         Length:594         Min.   :-76.59  
##  1st Qu.: 3.00   Class :character   Class :character   1st Qu.:-76.53  
##  Median : 4.00   Mode  :character   Mode  :character   Median :-76.52  
##  Mean   : 4.67                                         Mean   :-76.51  
##  3rd Qu.: 5.00                                         3rd Qu.:-76.50  
##  Max.   :10.00                                         Max.   :-76.48  
##     latitud     
##  Min.   :3.437  
##  1st Qu.:3.465  
##  Median :3.473  
##  Mean   :3.472  
##  3rd Qu.:3.483  
##  Max.   :3.496

Análisis exploratorio de los datos

A continuación, se realiza un análisis exploratorio de la base 1 con el fin de observar la relación entre el precio de las viviendas y algunas de sus principales características, como el área construida, estrato, número de baños, habitaciones y parqueaderos.

Distribución del precio

A continuación se grafica el histograma de la variable objetivo precio con el fin de observar graficamente sy distribución. Asi mismo, se realiza la prueba Shapiro-Wilk con el fin de evaluar si los datos se comportan como una distribucion normal. Se plantea para esta: Ho: los datos siguen una distibucion normal H1: los datos no siguen una distribucion normal

plot_ly(
  base1,
  x = ~preciom,
  type = "histogram"
)
shapiro.test(base1$preciom)
## 
##  Shapiro-Wilk normality test
## 
## data:  base1$preciom
## W = 0.85179, p-value < 2.2e-16

La base 1 está conformada por 594 viviendas, cuyos precios varían entre 89 y 1.940 millones de pesos. La mediana del precio es de 380 millones y la media de 429,6 millones. Se observa que la mayor parte de las viviendas se concentra en los rangos de precios más bajos y medios, mientras que existen algunas viviendas con precios considerablemente altos. Esto genera una distribución asimétrica hacia la derecha, lo cual también se observa en el histograma.La prueba de Shapiro-Wilk obtuvo un valor p menor a 0,05, por lo que rechazamos H0 y se concluye que la variable precio no presenta una distribución normal.

Debido a que la prueba de Shapiro-Wilk indicó que la variable precio no presenta una distribución normal (p < 0.05), para el análisis de las relaciones entre las variables se utilizará el coeficiente de correlación de Kendall, siguiendo un enfoque no paramétrico.

Precio y área construida

Se analiza la relacion entre el precio de las viviendas y el area construida.

plot_ly(base1, 
        x = ~areaconst, 
        y = ~preciom,
        type = "scatter",
        mode = "markers")
cor(base1$areaconst, base1$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.6566387

Se observa una relación positiva entre el área construida y el precio de las viviendas. Debido a que la variable precio no presenta una distribución normal, se utilizó el coeficiente de correlación de Kendall, obteniendo un valor de 0.65. Este resultado indica una relación positiva relativamente fuerte, es decir, en general las viviendas con mayor área construida tienden a presentar precios más altos. También se observan algunos datos que se alejan del comportamiento general. También se observan dos datos que se alejan bastante del comportamiento general.

Precio y estrato

Debido a que la variable estrato es cualitativa ordinal, realizar un gráfico de dispersión no es lo más adecuado. Para observar si existe alguna relación entre el estrato y el precio, se realizarán diagramas de cajas para cada uno de los estratos, comparándolos con el precio de las viviendas.

plot_ly(base1, 
        x = ~factor(estrato), 
        y = ~preciom,
        type = "box")
cor(base1$estrato, base1$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.5665472

Se observa una relación positiva moderada entre el estrato y el precio. La correlación de Kendall fue de 0.56, indicando que, en general, a medida que aumenta el estrato también tiende a aumentar el precio de las viviendas. También se observan algunos valores que se alejan considerablemente del comportamiento general.

Precio y número de baños

Debido a que el número de baños es una variable cuantitativa discreta, se realiza un diagrama de cajas para observar cómo cambia el precio de las viviendas según el número de baños.

plot_ly(base1,
        x = ~factor(banios),
        y = ~preciom,
        type = "box")
cor(base1$banios, base1$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.5238742
table(base1$banios)
## 
##   1   2   3   4   5   6   7   8   9  10 
##  15 145 156 140  83  37   6   9   1   2

Aunque existe bastante variación en los precios, se observa una tendencia de aumento del precio a medida que aumenta el número de baños. La correlación de Kendall fue de 0.52, lo que indica una relación positiva moderada. También se observa que existen muy pocos registros de viviendas con 9 y 10 baños, con solo 1 y 2 viviendas respectivamente.

Precio y número de habitaciones

plot_ly(base1,
        x = ~factor(habitaciones),
        y = ~preciom,
        type = "box")
cor(base1$habitaciones, base1$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.3569346

Se observa que la relación entre el número de habitaciones y el precio no es muy fuerte. La correlación de Kendall fue de 0.35, lo que indica una relación positiva baja.

Precio y parqueaderos

plot_ly(base1,
        x = ~factor(parqueaderos),
        y = ~preciom,
        type = "box")
cor(base1$parqueaderos, base1$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.4638594
table(base1$parqueaderos)
## 
##   1   2   3   4   5   6   7   8   9  10 
## 279 205  50  34  11   7   5   1   1   1

La correlación de Kendall fue de 0.46, lo que indica una relación positiva moderada entre el número de parqueaderos y el precio. Sin embargo, en el gráfico no se observa una tendencia tan clara, especialmente para las viviendas con mayor número de parqueaderos, debido a que existen muy pocos registros en estas categorías. La mayoría de las viviendas cuenta con 1 o 2 parqueaderos.

Análisis de correlaciones

Antes de realizar el modelo de regresión lineal múltiple, se analizará la correlación entre las variables predictoras con el fin de identificar si existen relaciones fuertes entre ellas que puedan afectar el modelo.

library(corrplot)

cor_predictoras <- cor(
  base1[, c(
    "areaconst",
    "estrato",
    "habitaciones",
    "parqueaderos",
    "banios"
  )],
  method = "kendall",
  use = "complete.obs"
)

corrplot(
  cor_predictoras,
  method = "color",
  type = "upper",
  addCoef.col = "black",
  tl.col = "black",
  tl.srt = 45,
  diag = FALSE
)

Entre las variables predictoras se espera encontrar correlaciones que no sean demasiado altas, con el fin de evitar posibles problemas de multicolinealidad. En este caso, las correlaciones obtenidas mediante Kendall son bajas o moderadas. Las mayores se presentan entre estrato y parqueaderos, y entre habitaciones y baños, ambas con un valor de 0.51. Estos valores no parecen lo suficientemente altos como para considerar inicialmente la eliminación de alguna variable.

Modelo de regresión lineal múltiple

A continuación, se presenta el modelo de regresión lineal múltiple correspondiente a la base 1. Para evaluar los resultados del modelo se tendrá en cuenta la significancia individual de las variables mediante la prueba t y la significancia global del modelo mediante la prueba F.

Para la prueba t de cada coeficiente se plantean las siguientes hipótesis: H₀: βⱼ = 0: la variable no es estadísticamente significativa en el modelo. H₁: βⱼ ≠ 0: la variable es estadísticamente significativa en el modelo.

Para la prueba F global se plantean las siguientes hipótesis: H₀: β₁ = β₂ = β₃ = β₄ = β₅ = 0: ninguna de las variables predictoras es significativa en el modelo. H₁: al menos un βⱼ ≠ 0: al menos una de las variables predictoras es significativa en el modelo.

Para ambas pruebas se utilizará un nivel de significancia de 0.05. Cuando el p-value sea menor a 0.05 se rechazará la hipótesis nula.

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

summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -908.45  -67.78  -14.11   36.82 1076.70 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -221.13740   33.88020  -6.527 1.45e-10 ***
## areaconst       0.75136    0.04929  15.245  < 2e-16 ***
## estrato        68.86834    8.28013   8.317 6.28e-16 ***
## habitaciones    9.59644    5.04910   1.901 0.057840 .  
## parqueaderos   21.04821    5.79935   3.629 0.000309 ***
## banios         23.50442    6.32594   3.716 0.000222 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 153.6 on 588 degrees of freedom
## Multiple R-squared:  0.6614, Adjusted R-squared:  0.6585 
## F-statistic: 229.7 on 5 and 588 DF,  p-value: < 2.2e-16

Con base en los resultados anteriores se puede concluir que:

  • Dentro de las variables predictoras, habitaciones es la única que no resulta estadísticamente significativa al nivel de 0.05, ya que presenta un p-value de 0.0578. Sin embargo, este valor se encuentra muy cercano al límite de significancia. Las demás variables presentan valores p menores a 0.05, por lo que se consideran estadísticamente significativas en el modelo.
  • Con respecto a los coeficientes de las variables predictoras se tiene que: Dejando constantes las demás variables, por cada m² adicional de área construida, el precio estimado aumenta aproximadamente 0.75 millones de pesos. Dejando constantes las demás variables, al aumentar un nivel de estrato, el precio estimado aumenta aproximadamente 68.87 millones de pesos. Dejando constantes las demás variables, una habitación adicional está asociada con un aumento aproximado de 9.60 millones de pesos en el precio estimado. Sin embargo, esta variable no resultó estadísticamente significativa al nivel de 0.05. Dejando constantes las demás variables, un parqueadero adicional está asociado con un aumento aproximado de 21.05 millones de pesos en el precio estimado. *Finalmente, dejando constantes las demás variables, un baño adicional está asociado con un aumento aproximado de 23.50 millones de pesos en el precio estimado de la vivienda.
  • El intercepto obtenido es negativo (-221.14 millones de pesos). Aunque matemáticamente hace parte del modelo, no tiene una interpretación práctica útil para esta actividad, ya que correspondería al precio estimado cuando todas las variables predictoras toman un valor de cero, situación que no representa una vivienda real.
  • El valor de R² es 0.6614, lo que significa que aproximadamente el 66.14 % de la variación observada en el precio de las casas puede ser explicada por las cinco variables incluidas en el modelo, mientras que aproximadamente un 33.86 % queda sin explicar. Adicionalmente, el R² ajustado es 0.6585, un valor muy cercano al R². Con base en estos resultados, se puede decir que el modelo presenta un ajuste moderadamente bueno.
  • Finalmente, la prueba F global presenta un p-value menor a 0.05, lo que indica que el modelo en conjunto es estadísticamente significativo.

intervalos de confianza de los coeficientes

confint(modelo1, level = 0.95)
##                     2.5 %       97.5 %
## (Intercept)  -287.6783255 -154.5964660
## areaconst       0.6545573    0.8481562
## estrato        52.6061152   85.1305564
## habitaciones   -0.3200344   19.5129055
## parqueaderos    9.6582491   32.4381611
## banios         11.0802326   35.9286066

Los intervalos de confianza al 95 % muestran que los coeficientes de área construida, estrato, parqueaderos y baños no incluyen el valor cero, lo cual es consistente con su significancia estadística. Por el contrario, el intervalo correspondiente a habitaciones se encuentra entre -0.32 y 19.51 e incluye el valor cero, lo que coincide con el resultado de la prueba t, donde esta variable presentó un p-value ligeramente superior a 0.05.

Validación de los supuestos del modelo

Una vez estimado el modelo de regresión lineal multiple, se validaran los supuestos con el fin de determinar si el modelo es confiable y si existen problremas que puedan afectar sus resultados.

Normalidad de los residuos

Se evalua el supuesto de normalidad de los residuos mediante el gráfico Q-Q, el cual permite comparar la distribucion de los residuos del modelo con una distribucion nromal. Se espera que los residuos se acerquen a la linea recta, para confirmar su distribucion normal.

qqnorm(
  residuals(modelo1),
  main = "Gráfico Q-Q de los residuos"
)

qqline(
  residuals(modelo1),
  col = "red",
  lwd = 2
)

En el gráfico Q-Q se observa que gran parte de los residuos ubicados en la zona central se encuentran sobre o cerca de la línea de referencia. Sin embargo, hacia los extremos se presentan desviaciones considerables, especialmente en la cola derecha. Por lo tanto, se puede decir que los residuos presentan un comportamiento cercano a la normalidad en la parte central, pero existen desviaciones importantes en las colas, por lo que el supuesto de normalidad no se cumple completamente.

Homocedasticidad

A continuación, se evalúa el supuesto de homocedasticidad, con el fin de verificar si la variabilidad de los residuos se mantiene aproximadamente constante a lo largo de los valores estimados por el modelo. Para este supuesto se busca residuos distribuuidos alrededor de 0 con una dispersion mas o menso constante alrededor.

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

abline(h = 0, col = "red", lwd = 2)

En el gráfico de residuos vs. valores ajustados se observa que, para los valores ajustados más bajos, los residuos se encuentran relativamente concentrados alrededor de cero. Sin embargo, a medida que aumentan los valores ajustados, la dispersión de los residuos también aumenta, formando una especie de abanico. Esto indica que la variabilidad de los errores no se mantiene constante, por lo que el supuesto de homocedasticidad no se cumple completamente y se presenta evidencia de heterocedasticidad.

Independencia de los residuos

Para evaluar la indepenencia de los residuos utilizamos el estadistico Durbin-Watson. Se espera un valor de este cercano a 2 y un p value mayor que 0.05.

library(lmtest)

dwtest(modelo1)
## 
##  Durbin-Watson test
## 
## data:  modelo1
## DW = 1.6887, p-value = 6.016e-05
## alternative hypothesis: true autocorrelation is greater than 0

Para evaluar la independencia de los residuos se realizó la prueba de Durbin-Watson. Se obtuvo un estadístico DW de 1.6887 y un p-value de 6.016e-05. Debido a que el p-value es menor a 0.05, existe evidencia de autocorrelación positiva entre los residuos, por lo que el supuesto de independencia no se cumple.

Multicolinealidad (factor VIF)

Finalmente, se evalúa la posible presencia de multicolinealidad entre las variables predictoras mediante el Factor de Inflación de la Varianza (VIF). Este análisis permite determinar si alguna de las variables predictoras presenta una relación demasiado fuerte con las demás variables incluidas en el model. Se espera un valor menor o igual a 5.

library(car)

vif(modelo1)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     1.758052     1.619879     1.921552     1.347995     2.173224

Los valores VIF obtenidos para todas las variables predictoras son inferiores a 5, encontrándose entre 1.35 y 2.17. Por lo tanto, no se evidencian problemas importantes de multicolinealidad en el modelo. Este resultado es consistente con la matriz de correlaciones, en la cual no se observaron correlaciones excesivamente altas entre las variables predictoras.

Linealidad

La linealidad sirve para comprobar que la relacion entre las variables predictoras y el precio de las viviendas puede representarse mediante una relacion lineal. Este supuesto es posbile evaluarlo con el grafico Residuals vs Fitted, evaluando que la linea roja sea mas o menos horizontal alrededor de 0

plot(modelo1, which = 1)

La línea de tendencia presenta una ligera curvatura, especialmente en los valores ajustados intermedios, aunque no se observa un patrón curvo fuertemente definido. Por lo tanto, se considera que el supuesto de linealidad se cumple de manera aproximada, aunque se presentan pequeñas desviaciones que indican que algunas relaciones podrían no ser completamente lineales.

Análisis de observaciones extremas

Adicionalmente, se realiza un análisis de observaciones extremas con el fin de identificar registros que puedan presentar comportamientos atípicos o tener una influencia importante sobre el modelo. Para esto se analizarán los residuos studentizados, el leverage y la distancia de Cook.

Residuos studentizados

Esta sección responde a que viviendas tienen un error de prediccion muy grande. Para este análisis se consideran como posibles observaciones atípicas aquellas cuyos residuos studentizados presentan un valor absoluto superior a 3.

res_student <- rstudent(modelo1)

unname(which(abs(res_student) > 3))
##  [1] 112 129 156 238 307 308 370 391 401 402 418 434 474 481 510 576

Se identificaron 16 observaciones con residuos studentizados superiores a 3 en valor absoluto. Estas representan aproximadamente el 2.7 % de las 594 viviendas analizadas, por lo que se consideran posibles observaciones atípicas que deben ser revisadas.

Leverage

El leverage permite identificar observaciones que presentan combinaciones poco comunes en las variables predictoras, es decir, viviendas cuyas características de área, estrato, habitaciones, parqueaderos o baños se alejan considerablemente del comportamiento general de los datos..

leverage <- hatvalues(modelo1)

limite_leverage <- 2 * length(coef(modelo1)) / nrow(base1)

limite_leverage
## [1] 0.02020202
unname(which(leverage > limite_leverage))
##  [1]  14  95 105 106 112 120 136 138 139 141 142 143 147 161 169 179 211 220 238
## [20] 246 251 268 306 308 311 317 321 333 334 339 349 356 358 370 373 391 392 401
## [39] 402 408 422 438 449 451 452 453 474 477 479 488 505 510 561 576 594
sum(leverage > limite_leverage)
## [1] 55
sum(leverage > limite_leverage) / nrow(base1) * 100
## [1] 9.259259

Para identificar observaciones con combinaciones poco comunes en las variables predictoras, se analiza el leverage. Como criterio de referencia se utiliza 2p/n, donde pcorresponde al número de parámetros del modelo y n al número de observaciones. Para este modelo se obtiene un límite de 0.0202; por lo tanto, las observaciones con leverage superior a este valor serán consideradas como observaciones de leverage potencialmente alto.Se identificaron 55 observaciones con valores de leverage superiores al límite de 0.0202, lo que representa aproximadamente el 9.26 % de las 594 viviendas analizadas. Estas observaciones presentan combinaciones de características predictoras que se alejan del comportamiento general de los datos, por lo que pueden considerarse observaciones con leverage potencialmente alto. Sin embargo, esto no significa necesariamente que tengan una influencia importante sobre el modelo.

Distancia de cook

Finalmente, se utiliza la distancia de Cook para identificar observaciones que pueden tener una influencia importante sobre el modelo. A diferencia del leverage, que identifica observaciones con características predictoras poco comunes, la distancia de Cook permite evaluar qué tanto puede influir una observación sobre los resultados del modelo. Se utiliza como referencia el criterio Di>4/n, por lo que Di>0.006

cook <- cooks.distance(modelo1)

limite_cook <- 4 / nrow(base1)

limite_cook
## [1] 0.006734007
unname(which(cook > limite_cook))
##  [1]  60  61  62 105 112 129 131 138 156 161 190 232 238 306 307 308 311 349 370
## [20] 391 401 402 408 418 425 428 434 437 438 474 481 486 510 563 576 594
sum(cook > limite_cook)
## [1] 36
sum(cook > limite_cook) / nrow(base1) * 100
## [1] 6.060606
plot(
  cook,
  type = "h",
  ylab = "Distancia de Cook",
  main = "Distancia de Cook"
)

abline(
  h = limite_cook,
  col = "red",
  lty = 2
)

Se identificaron 36 observaciones que superan este valor, equivalentes aproximadamente al 6.06 % de las 594 viviendas analizadas. Estas observaciones se consideran potencialmente influyentes, ya que pueden tener un efecto importante sobre el ajuste del modelo. Adicionalmente, en el gráfico se destaca una observación con una distancia de Cook considerablemente mayor que las demás (510), por lo que sería conveniente revisarla de manera particular.Misma observacion obtuvo un leverage y error de prediccion alto.

base1[510, ]
## # A tibble: 1 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1   534 Zona N… 03          3     370      1440            1      4           10
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
res_student[510]
##       510 
## -6.638335
leverage[510]
##       510 
## 0.1476063
cook[510]
##     510 
## 1.18504

Al revisar las observaciones identificadas, se destaca particularmente la observación 510, correspondiente a una vivienda con 1.440 m² de área construida, 10 habitaciones y un precio de 370 millones de pesos. Estas características se alejan considerablemente del comportamiento general de la base, especialmente por presentar un área construida muy elevada y un precio relativamente bajo para dicho tamaño. Esto ayuda a explicar la alta influencia que presenta esta observación sobre el modelo.

Sugerencias

La validación de los supuestos muestra que el modelo presenta algunas limitaciones. La normalidad de los residuos se cumple principalmente en la parte central, pero presenta desviaciones en los extremos. También se observa heterocedasticidad y la prueba de Durbin-Watson muestra que existen problemas con la independencia de los residuos. Por otro lado, no se observan problemas importantes de multicolinealidad y la linealidad se cumple de manera aproximada.

Adicionalmente, al revisar las observaciones extremas se encontraron 16 registros con residuos studentizados altos (2.7 %), 55 con leverage alto (9.26 %) y 36 observaciones potencialmente influyentes según la distancia de Cook (6.06 %).

Como posibles mejoras se podría:

  • Revisar las observaciones identificadas como atípicas o influyentes, para verificar si corresponden a errores en los datos o simplemente a viviendas con características poco comunes. Por ejemplo, la observación 510 corresponde a una casa de 1.440 m², 10 habitaciones y un precio de 370 millones, características bastante diferentes al comportamiento general de la base. Antes de eliminar este tipo de registros sería importante comprobar que la información sea correcta.
  • Revisar si existen otras variables que puedan ayudar a explicar mejor el precio, ya que algunas características importantes de las viviendas pueden no estar siendo consideradas actualmente en el modelo.
  • Probar un modelo sin la variable habitaciones, debido a que fue la única variable que no resultó estadísticamente significativa. Posteriormente se podrían comparar ambos modelos para revisar si es conveniente conservarla o trabajar con un modelo más sencillo.
  • Evaluar otras alternativas para manejar los problemas encontrados en la heterocedasticidad y en la independencia de los residuos, y posteriormente revisar si estas alternativas mejoran el comportamiento del modelo.

Predicción del precio de la Vivienda 1

La solicitud para la vivienda 1 tiene las siguientes carcaterísticas - Área construida: 200 m² - Parqueaderos: 1 - Baños: 2 - Habitaciones: 4 - Estrato: 4 o 5 - Presupuesto: 350 millones

Como hay 2 posibilidades para estrato, se realizaran 2 predicciones: una suponiendo estrato 4 y otra estrato 5.

Creamos las caracteristicas de la vivienda 1, teniendo estrato 4 y estrato 5

vivienda1_pred <- data.frame(
  areaconst = c(200, 200),
  estrato = c(4, 5),
  habitaciones = c(4, 4),
  parqueaderos = c(1, 1),
  banios = c(2, 2)
)

vivienda1_pred
##   areaconst estrato habitaciones parqueaderos banios
## 1       200       4            4            1      2
## 2       200       5            4            1      2
predict(modelo1, newdata = vivienda1_pred)
##        1        2 
## 311.0501 379.9184

Para una vivienda estrato 4 con las características solicitadas, el modelo estima un precio aproximado de 311.05 millones de pesos, valor que se encuentra dentro del crédito preaprobado de 350 millones. Para una vivienda estrato 5, el precio estimado aumenta aproximadamente a 379.92 millones de pesos, superando el presupuesto disponible. Por lo tanto, según las estimaciones del modelo, sería más viable encontrar una vivienda estrato 4 que cumpla con las características solicitadas y el presupuesto establecido.

Como estamos prediciendo el precio de una vivienda en particular, es posible obtener los intervalos de predicción para ambos estratos.

predict(
  modelo1,
  newdata = vivienda1_pred,
  interval = "prediction",
  level = 0.95
)
##        fit       lwr      upr
## 1 311.0501  8.795091 613.3051
## 2 379.9184 76.916883 682.9199

Los intervalos de predicción obtenidos son bastante amplios. Para una vivienda estrato 4, aunque el precio estimado es de 311.05 millones de pesos, el intervalo al 95 % se encuentra entre 8.80 y 613.31 millones. Para estrato 5, el precio estimado es de 379.92 millones, con un intervalo entre 76.92 y 682.92 millones. Esta amplitud muestra que existe una alta incertidumbre al estimar el precio de una vivienda individual, por lo que las predicciones puntuales deben tomarse como valores de referencia y no como precios exactos.Por esta razón, para realizar la recomendación final también se tendrán en cuenta los precios reales y las características de las viviendas disponibles en la base de datos.

Selección de ofertas para la Vivienda 1

Teniendo en cuenta que el crédito preaprobado para la Vivienda 1 es de máximo 350 millones de pesos, se realiza una búsqueda dentro de la base 1 de viviendas que se ajusten al presupuesto y presenten características cercanas a las solicitadas. Se consideran viviendas de estrato 4 y 5, de acuerdo con los requerimientos del cliente, y se establece inicialmente un rango de área construida entre 180 y 220 m², tomando como referencia los 200 m² solicitados.

ofertas1 <- base1 |>
  dplyr::filter(
    estrato %in% c(4, 5),
    preciom <= 350,
    areaconst >= 180,
    areaconst <= 220
  )

nrow(ofertas1)
## [1] 15
ofertas1
## # A tibble: 15 × 13
##       id zona   piso  estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  4511 Zona … <NA>        4     275       190            2      2            3
##  2  4210 Zona … 01          5     350       200            3      3            4
##  3  4267 Zona … 01          5     335       202            1      4            5
##  4  4313 Zona … 01          5     335       220            1      3            3
##  5   852 Zona … <NA>        5     340       208            2      6            4
##  6  1270 Zona … <NA>        5     350       203            2      2            5
##  7  1343 Zona … 02          5     320       200            2      4            4
##  8  1352 Zona … <NA>        5     350       190            1      3            3
##  9  1506 Zona … <NA>        5     340       180            2      4            4
## 10  1144 Zona … <NA>        4     320       200            2      4            4
## 11  1163 Zona … <NA>        5     350       216            2      2            4
## 12   515 Zona … <NA>        4     280       180            2      3            4
## 13  1151 Zona … <NA>        5     320       210            2      3            5
## 14  1887 Zona … 01          5     340       203            2      3            4
## 15  1914 Zona … 02          5     300       205            2      5            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

El resultado de este filtro arroja 15 registros que cumplen con el presupuesto máximo establecido, pertenecen a los estratos 4 o 5 y presentan un área construida entre 180 y 220 m². A partir de estas opciones se evaluarán las demás características solicitadas, como el número de habitaciones, baños y parqueaderos, con el fin de seleccionar las viviendas que mejor se ajusten a la solicitud.

De las 15 viviendas obtenidas inicialmente, se seleccionaron aquellas que cuentan con 4 habitaciones, al menos 2 baños y mínimo 1 parqueadero. Posteriormente, estas ofertas se ordenaron según qué tan cercana se encuentra su área construida a los 200 m² solicitados y, como criterio adicional, se tuvo en cuenta el menor precio. A partir de este procedimiento se seleccionaron las 5 ofertas que mejor se ajustan a las características requeridas.

mejores_ofertas <- ofertas1 |>
  dplyr::filter(
    habitaciones == 4,
    banios >= 2,
    parqueaderos >= 1
  )

mejores_ofertas
## # A tibble: 8 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  4210 Zona N… 01          5     350       200            3      3            4
## 2   852 Zona N… <NA>        5     340       208            2      6            4
## 3  1343 Zona N… 02          5     320       200            2      4            4
## 4  1506 Zona N… <NA>        5     340       180            2      4            4
## 5  1144 Zona N… <NA>        4     320       200            2      4            4
## 6  1163 Zona N… <NA>        5     350       216            2      2            4
## 7   515 Zona N… <NA>        4     280       180            2      3            4
## 8  1887 Zona N… 01          5     340       203            2      3            4
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
mejores_ofertas <- mejores_ofertas |>
  dplyr::mutate(
    diferencia_area = abs(areaconst - 200)
  ) |>
  dplyr::arrange(
    diferencia_area,
    preciom
  )

mejores_ofertas
## # A tibble: 8 × 14
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1343 Zona N… 02          5     320       200            2      4            4
## 2  1144 Zona N… <NA>        4     320       200            2      4            4
## 3  4210 Zona N… 01          5     350       200            3      3            4
## 4  1887 Zona N… 01          5     340       203            2      3            4
## 5   852 Zona N… <NA>        5     340       208            2      6            4
## 6  1163 Zona N… <NA>        5     350       216            2      2            4
## 7   515 Zona N… <NA>        4     280       180            2      3            4
## 8  1506 Zona N… <NA>        5     340       180            2      4            4
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   diferencia_area <dbl>
top5_ofertas <- mejores_ofertas |>
  dplyr::slice_head(n = 5)

top5_ofertas
## # A tibble: 5 × 14
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1343 Zona N… 02          5     320       200            2      4            4
## 2  1144 Zona N… <NA>        4     320       200            2      4            4
## 3  4210 Zona N… 01          5     350       200            3      3            4
## 4  1887 Zona N… 01          5     340       203            2      3            4
## 5   852 Zona N… <NA>        5     340       208            2      6            4
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   diferencia_area <dbl>

Entre las cinco ofertas seleccionadas, las viviendas con ID 1343 y 1144 son las que mejor se ajustan a las características solicitadas. Ambas tienen un precio de 320 millones de pesos, 200 m² de área construida, 4 habitaciones, 4 baños y 2 parqueaderos. La principal diferencia se encuentra en el estrato, ya que la vivienda 1343 es estrato 5 y la 1144 es estrato 4. Adicionalmente, la vivienda 1343 registra piso 2, por lo que la elección entre ambas podría depender de las preferencias del cliente. En términos de las características solicitadas y del presupuesto, ambas representan buenas opciones.

Caso 2. Apartamento - Zona Sur

El caso 2 corresponde a un apartamento en Zona Sur, 300 m², 3 parqueaderos, 3 baños, 5 habitaciones, estrato 5 o 6 y presupuesto máximo de 850 millones. Se sigue el mismo procedimiento utilizado en el caso 1, pero con las características solicitadas para este caso.

Filtro de apartamentos de la Zona Sur (base 2) y verificación de la base filtrada

Se realiza el mismo filtro para caso 1, pero cambiamos la condiciones de tipo de vivienda: apartamento y la ubicacion en Zona Sur.

base2 <- vivienda_limpia %>%
  filter(tipo == "Apartamento",
         zona == "Zona Sur")
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>
dim(base2)
## [1] 2787   13

Para base 2, correspondiente a viviendas tipo Apartamento ubicados en la Zona Sur de la ciudad, se obtienen 2787 registros y 13 variables. Como verificación del filtro realizado, se presentan los tres primeros registros de la base 2.

Ubicación geográfica de las viviendas

De manera similar que en el caso 1, se presenta la ubicación geográfica de las viviendas correspondientes a la base 2, utilizando las coordenadas de latitud y longitud disponibles en la base de datos. con este mapa es posible tener una visualización de como estan distribuidaslas ofertas de apartamentos registrados como pertenecientes a la Zona sur de Cali. Adicionalmente, se identificaron los valores mínimo y máximo de la variable latitud ( circulos rojos), ya que esta coordenada permite observar la variación de los puntos en dirección norte-sur. Estos dos puntos se resaltan en el mapa con el fin de observar qué tan alejadas se encuentran las viviendas ubicadas en los extremos de la base 2.

extremos_latitud <- base2 %>%
  filter(
    latitud == min(latitud, na.rm = TRUE) |
    latitud == max(latitud, na.rm = TRUE)
  )

extremos_latitud
## # A tibble: 2 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1   221 Zona S… 04          5     360        99            1      3            2
## 2  5008 Zona S… 11          6     635       133            3      4            4
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
leaflet(base2) %>%
  addTiles() %>%
  
  # Todas las viviendas
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 2
  ) %>%
  
  # Puntos con latitud mínima y máxima
  addCircleMarkers(
    data = extremos_latitud,
    lng = ~longitud,
    lat = ~latitud,
    radius = 7,
    color = "red",
    fillColor = "red",
    fillOpacity = 1,
    popup = ~paste(
      "Latitud:", latitud,
      "<br>Longitud:", longitud
    )
  )

Como sucedio en el caso 1, gran cantidad de los puntos se encuentran localizados en la Zona Sur de Cali; sin embargo, también se observa una proporción considerable de puntos ubicados en otras zonas de la ciudad, a pesar de estar clasificados en la base como Zona Sur.Al comparar los extremos de la latitud , se tiene un valor máximo de 3.49684 y un mínimo de 3.33367, presentando una variación aproximada de 0.16°.Es evidente que esta diferencia se ve reflejada en la dispersión que presentan los los registros en el mapa. La presencia de puntos en otras zonas podría deberse a errores en las coordenadas de algunos registros o a una asignación incorrecta de la zona al momento de construir la base de datos. Por ello se procede a realizar un filtro a la base 2 para cumplir con el objetivo de la solicitud del caso 2.

Para realizar un correcto filtrado de la base, se procede a realizar un analisis de conglomerados con el fin de observar agrupaciones de vivienda de acuerdo a las variables longitud y latitud. Pirmeramente se realizara el metodo del codo con el fin de elegir correctamente la cantidad de clusters y posteriomente se procede a realizar el PCA.

fviz_nbclust(
  base2[, c("longitud", "latitud")],
  kmeans,
  method = "wss",
  k.max = 10
) +
  labs(
    title = "Método del codo",
    x = "Número de conglomerados",
    y = "Suma de cuadrados dentro de los grupos"
  )

De manera similar a caso 1, el método del codo sugiere, en primera instancia, trabajar con 2 conglomerados. Esta selección resulta conveniente para el propósito del análisis, ya que se busca identificar un grupo que represente las viviendas realmente ubicadas en la Zona Sur y separar aquellas observaciones que, aunque se encuentran categorizadas como Zona Sur en la base de datos, presentan una ubicación geográfica diferente.

set.seed(123)

conglomerados2 <- kmeans(
  base2[, c("longitud", "latitud")],
  centers = 2
)

base2$conglomerado <- as.factor(conglomerados2$cluster)

table(base2$conglomerado)
## 
##    1    2 
## 1845  942

Representando los conglomerados obtenidos del PCA con los registros categorizados como apartamento en Zona Sur, se evidencia una clara separación entre los registros realmente ubicados en esta zona y aquellos que se encuentran en otras zonas de la ciudad. De esta manera, es posible identificar el conglomerado que debe conservarse ( para este caso el conlgomerado 1 en rojo) y excluir las observaciones que no cumplen con la ubicación requerida para el caso 2.

Por esta razón, se procede a excluir de la base 2 los registros pertenecientes al conglomerado que no corresponde geográficamente a la Zona Sur de Cali. De esta forma, la base queda conformada únicamente por las viviendas ubicadas en el sector de interés, y sobre esta nueva base se continuará con la revisión de calidad de los datos, el análisis exploratorio y la estimación del modelo de regresión.

## [1] 1845   13

Limpieza base 2

Como se analizó al inicio del documento, se procederá a evaluar si existen valores faltantes (NA) en las variables de interés de la base 2, así como datos inconsistentes en el número de baños y habitaciones.

# Valores faltantes
sum(is.na(base2$preciom))
## [1] 0
sum(is.na(base2$areaconst))
## [1] 0
sum(is.na(base2$estrato))
## [1] 0
sum(is.na(base2$parqueaderos))
## [1] 239
sum(is.na(base2$banios))
## [1] 0
sum(is.na(base2$habitaciones))
## [1] 0
# Valores iguales a cero
sum(base2$parqueaderos == 0, na.rm = TRUE)
## [1] 0
sum(base2$banios == 0, na.rm = TRUE)
## [1] 3
sum(base2$habitaciones == 0, na.rm = TRUE)
## [1] 4

Al analizar las variables predictoras de la base 2, se identificaron algunos aspectos relacionados con la calidad de los datos:

  • Se encontraron 239 valores faltantes (NA) en la variable parqueaderos.
  • Se identificaron 3 registros con 0 baños.
  • Se identificaron 4 registros con 0 habitaciones.
  • No se encontraron registros con 0 parqueaderos.

Las demás variables predictoras analizadas no presentan valores faltantes. Estos resultados serán tenidos en cuenta para definir posteriormente el tratamiento más adecuado antes de estimar el modelo de regresión.

Variable parqueaderos

De manera similar que en el caso 1, para el tratamiento de los 239 valores faltantes de la variable parqueadero, se plantean estas opciones:

  1. Utilizar la mediana general: reemplazar los valores faltantes por la mediana de parqueaderos de todas las viviendas de la base 2.
  2. Utilizar la mediana por estrato: calcular la mediana de parqueaderos para cada estrato y reemplazar los valores faltantes de acuerdo con el estrato al que pertenece cada vivienda.
  3. Reemplazar los NA por 0: teniendo en cuenta que no existen valores iguales a 0 en la variable parqueaderos, se podría considerar que los NA corresponden a viviendas que no cuentan con parqueadero. Sin embargo, esta opción parte de un supuesto que no se puede confirmar directamente con la información disponible en la base. A continuación, se evaluarán estas opciones para determinar cuál resulta más adecuada para el tratamiento de los valores faltantes.

Para elegir entre la opción 1 y la opción 2, se procede a calcular la mediana del número de parqueaderos para cada estrato presente en la base 2 y, adicionalmente, la mediana general de toda la base. Esto con el fin de verificar qué tanto varía la mediana entre los diferentes estratos y determinar cuál de los dos métodos de imputación resulta más adecuado.

base2 %>%
  group_by(estrato) %>%
  summarise(
    n = n(),
    NA_parqueaderos = sum(is.na(parqueaderos)),
    mediana_parqueaderos = median(parqueaderos, na.rm = TRUE)
  )
## # A tibble: 4 × 4
##   estrato     n NA_parqueaderos mediana_parqueaderos
##     <dbl> <int>           <int>                <dbl>
## 1       3    82              32                    1
## 2       4   651             169                    1
## 3       5   713              28                    1
## 4       6   399              10                    2
median(base2$parqueaderos, na.rm = TRUE)
## [1] 1

Al calcular la mediana del número de parqueaderos por estrato, se observa que para los estratos 3, 4 y 5 la mediana es de 1 parqueadero, mientras que para el estrato 6 es de 2. La mediana general de la base es de 1 parqueadero. Debido a que se presenta una diferencia para el estrato 6, se decide realizar la imputación teniendo en cuenta el estrato de cada vivienda.

base2 <- base2 %>%
  mutate(
    parqueaderos = case_when(
      is.na(parqueaderos) & estrato %in% c(3, 4, 5) ~ 1,
      is.na(parqueaderos) & estrato == 6 ~ 2,
      TRUE ~ parqueaderos
    )
  )
sum(is.na(base2$parqueaderos))
## [1] 0
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0          417            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##            0            0            0            0            0            0 
##      latitud 
##            0

Después de realizar la imputación de la variable parqueaderos, se verificó nuevamente la presencia de valores faltantes. Se encontraron 417 valores NA correspondientes a la variable piso; sin embargo, debido a que esta variable no será utilizada como predictora en el modelo, estos valores no requieren ningún tratamiento adicional para el presente análisis.

Variable baños y habitaciones

Como se identifico anteriormente, existen registros con 0 baños y/o 0 habitaciones, valores que no son usuales para un apartamento. Para analizar estos casos, se revisará cuántos registros presentan 0 baños y 0 habitaciones al mismo tiempo, cuántos tienen 0 baños pero sí tienen habitaciones y cuántos tienen 0 habitaciones pero sí tienen baños.

# 0 baños y 0 habitaciones
sum(base2$banios == 0 & base2$habitaciones == 0)
## [1] 2
# 0 baños pero sí tiene habitaciones
sum(base2$banios == 0 & base2$habitaciones > 0)
## [1] 1
# 0 habitaciones pero sí tiene baños
sum(base2$habitaciones == 0 & base2$banios > 0)
## [1] 2
registros_cero1 <- sum(
  base2$banios == 0 | base2$habitaciones == 0
)

registros_cero1
## [1] 5
porcentaje_cero1 <- registros_cero / nrow(base2) * 100

porcentaje_cero1
## [1] 0.6504065

De acuerdo con los resultados, se identificaron 5 registros con valores iguales a 0 en baños y/o habitaciones. Estos representan aproximadamente el 0.65 % de las 1045 observaciones de la base 2. Debido a que estos valores no son usuales para una vivienda y corresponden a una proporción pequeña de la base, se decide eliminar estos registros, considerando que su exclusión no representa una pérdida considerable de información.

base2 <- base2 %>%
  filter(banios > 0,
         habitaciones > 0)
sum(base2$banios == 0)
## [1] 0
sum(base2$habitaciones == 0)
## [1] 0
dim(base2)
## [1] 1840   13
summary(base2)
##        id           zona               piso              estrato     
##  Min.   : 793   Length:1840        Length:1840        Min.   :3.000  
##  1st Qu.:2133   Class :character   Class :character   1st Qu.:4.000  
##  Median :3566   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :3862                                         Mean   :4.775  
##  3rd Qu.:5449                                         3rd Qu.:5.000  
##  Max.   :8228                                         Max.   :6.000  
##     preciom         areaconst       parqueaderos       banios     
##  Min.   :  78.0   Min.   : 40.00   Min.   :1.000   Min.   :1.000  
##  1st Qu.: 190.0   1st Qu.: 65.00   1st Qu.:1.000   1st Qu.:2.000  
##  Median : 260.0   Median : 85.00   Median :1.000   Median :2.000  
##  Mean   : 318.3   Mean   : 98.26   Mean   :1.395   Mean   :2.564  
##  3rd Qu.: 350.0   3rd Qu.:110.00   3rd Qu.:2.000   3rd Qu.:3.000  
##  Max.   :1750.0   Max.   :932.00   Max.   :4.000   Max.   :7.000  
##   habitaciones       tipo              barrio             longitud     
##  Min.   :1.000   Length:1840        Length:1840        Min.   :-76.56  
##  1st Qu.:3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median :3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   :2.949                                         Mean   :-76.53  
##  3rd Qu.:3.000                                         3rd Qu.:-76.52  
##  Max.   :6.000                                         Max.   :-76.50  
##     latitud     
##  Min.   :3.334  
##  1st Qu.:3.366  
##  Median :3.372  
##  Mean   :3.373  
##  3rd Qu.:3.383  
##  Max.   :3.398

Análisis exploratorio de los datos

En esta sección se realizara un analisis exploratorio de la base 2 limpia, con el fin de observar la relación entre el precio de las viviendas y algunas de sus principales características, como el área construida, estrato, número de baños, habitaciones y parqueaderos.

Distribución del precio

Al igual que para el caso 1, se grafica un histograma de la variable objetivo precio con el fin de observar graficamente su distribución. Asi mismo, se realiza la prueba Shapiro-Wilk con el fin de evaluar si los datos se comportan como una distribucion normal. Se plantea las dos siguientes hipotesis: Ho: los datos siguen una distibucion normal H1: los datos no siguen una distribucion normal

plot_ly(
  base2,
  x = ~preciom,
  type = "histogram"
)
shapiro.test(base2$preciom)
## 
##  Shapiro-Wilk normality test
## 
## data:  base2$preciom
## W = 0.76366, p-value < 2.2e-16

En la base 2 se observa un comportamiento similar al encontrado en el caso 1. La distribución del precio no presenta una forma de campana simétrica, sino que se encuentra desviada hacia la derecha, debido a la presencia de algunos apartamentos con precios considerablemente altos. Los precios varían entre 78 y 1750 millones de pesos, con una mediana de 260 millones y una media de 318.3 millones. Esta diferencia entre la media y la mediana también refleja la influencia de los precios más altos sobre la distribución. La prueba de Shapiro-Wilk obtuvo un p-value menor a 0.05, por lo que se rechaza H₀ y se concluye que la variable precio no presenta una distribución normal

Debido a que la prueba de Shapiro-Wilk indicó que la variable precio no presenta una distribución normal (p < 0.05), para el análisis de las relaciones entre las variables se utilizará el coeficiente de correlación de Kendall, siguiendo un enfoque no paramétrico.

Precio y área construida

Se analiza la relacion entre el precio de las viviendas y el area construida.

plot_ly(base2, 
        x = ~areaconst, 
        y = ~preciom,
        type = "scatter",
        mode = "markers")
cor(base2$areaconst, base2$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.7545093

Se observa una relación positiva fuerte entre el área construida y el precio de los apartamentos. El coeficiente de correlación de Kendall obtenido fue de 0.75, un valor considerablemente mayor al obtenido en el caso 1. Esto indica que, para los apartamentos de la Zona Sur, a medida que aumenta el área construida, el precio tiende a aumentar de manera bastante clara. En el gráfico también se observan algunos registros que se alejan del comportamiento general.

Precio y estrato

Debido a que la variable estrato es cualitativa ordinal, realizar un gráfico de dispersión no es lo más adecuado. Para observar si existe alguna relación entre el estrato y el precio, se realizarán diagramas de cajas para cada uno de los estratos, comparándolos con el precio de las viviendas.

plot_ly(base2, 
        x = ~factor(estrato), 
        y = ~preciom,
        type = "box")
cor(base2$estrato, base2$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.6515308

Se observa una relación positiva relativamente fuerte entre el estrato y el precio. La correlación de Kendall fue de 0.65, siendo mayor que la obtenida en el caso 1. Además, en el gráfico se evidencia claramente que, a medida que aumenta el estrato, también aumenta el precio de los apartamentos. Esta tendencia es especialmente marcada en los estratos 5 y 6, aunque también se observan algunos valores que se alejan considerablemente del comportamiento general.

Precio y número de baños

Debido a que el número de baños es una variable cuantitativa discreta, se realiza un diagrama de cajas para observar cómo cambia el precio de las viviendas según el número de baños.

plot_ly(base2,
        x = ~factor(banios),
        y = ~preciom,
        type = "box")
cor(base2$banios, base2$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.6154826
table(base2$banios)
## 
##    1    2    3    4    5    6    7 
##   61 1060  453  162   95    8    1

Se observa una relación positiva relativamente fuerte entre el número de baños y el precio de los apartamentos, con una correlación de Kendall de 0.62. En el gráfico se evidencia claramente que, en general, a medida que aumenta el número de baños también aumenta el precio de las viviendas. Sin embargo, se observan algunos valores que se alejan del comportamiento general. En particular, la categoría de 7 baños presenta un único registro, por lo que este valor debe interpretarse con precaución y posteriormente podría revisarse como una posible observación atípica.

Precio y número de habitaciones

plot_ly(base2,
        x = ~factor(habitaciones),
        y = ~preciom,
        type = "box")
cor(base2$habitaciones, base2$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.3579184

Se observa una relación positiva relativamente baja entre el número de habitaciones y el precio de los apartamentos, con una correlación de Kendall de 0.36, comportamiento similar al observado en el caso 1. A partir de las 2 habitaciones se aprecia una tendencia más clara de aumento del precio a medida que aumenta el número de habitaciones. Sin embargo, para los apartamentos de 1 habitación este comportamiento no sigue la misma tendencia. Además, se observa una cantidad considerable de valores por fuera de los rangos típicos de cada grupo, especialmente en los apartamentos de 2, 3 y 4 habitaciones, lo que muestra una alta variabilidad en los precios. Por esta razón, la relación entre habitaciones y precio no es tan clara como la observada con el estrato o el número de baños.

Precio y parqueaderos

plot_ly(base2,
        x = ~factor(parqueaderos),
        y = ~preciom,
        type = "box")
cor(base2$parqueaderos, base2$preciom,
    method = "kendall",
    use = "complete.obs")
## [1] 0.5894334
table(base2$parqueaderos)
## 
##    1    2    3    4 
## 1229  523   60   28

Se observa una relación positiva relativamente fuerte entre el número de parqueaderos y el precio de los apartamentos, con una correlación de Kendall de 0.59. En el gráfico se evidencia claramente que, a medida que aumenta el número de parqueaderos, también tiende a aumentar el precio de las viviendas. Esta relación es más clara que la observada en el caso 1, tanto gráficamente como en el valor del coeficiente de correlación. También se observa que la mayoría de los apartamentos cuentan con un solo parqueadero y que la cantidad de registros disminuye considerablemente a medida que aumenta el número de parqueaderos, siendo muy pocos los apartamentos con 3 o 4. Aunque existen algunos valores por fuera de los rangos típicos, la tendencia general entre ambas variables se encuentra bastante definida.

Análisis de correlaciones

Antes de realizar el modelo de regresión lineal múltiple, se analizará la correlación entre las variables predictoras con el fin de identificar si existen relaciones fuertes entre ellas que puedan afectar el modelo.

library(corrplot)

cor_predictoras <- cor(
  base2[, c(
    "areaconst",
    "estrato",
    "habitaciones",
    "parqueaderos",
    "banios"
  )],
  method = "kendall",
  use = "complete.obs"
)

corrplot(
  cor_predictoras,
  method = "color",
  type = "upper",
  addCoef.col = "black",
  tl.col = "black",
  tl.srt = 45,
  diag = FALSE
)

En el caso 2 se observan correlaciones entre las variables predictoras más altas que las encontradas en el caso 1. La relación más alta se presenta entre el área construida y el número de baños, con un valor de 0.66, seguida por parqueaderos y baños con 0.60, y área construida y parqueaderos con 0.58. En general, estas relaciones tienen sentido, ya que apartamentos de mayor tamaño tienden a contar con más baños y parqueaderos. Aunque algunas correlaciones son relativamente altas, ninguna parece lo suficientemente fuerte como para considerar inicialmente la eliminación de alguna variable. Posteriormente se verificará esto mediante el VIF del modelo de regresión.

Modelo de regresión lineal múltiple

A continuación, se presenta el modelo de regresión lineal múltiple correspondiente a la base 2. Para evaluar los resultados del modelo se tendrá en cuenta la significancia individual de las variables mediante la prueba t y la significancia global del modelo mediante la prueba F.

Para la prueba t de cada coeficiente se plantean las siguientes hipótesis: H₀: βⱼ = 0: la variable no es estadísticamente significativa en el modelo. H₁: βⱼ ≠ 0: la variable es estadísticamente significativa en el modelo.

Para la prueba F global se plantean las siguientes hipótesis: H₀: β₁ = β₂ = β₃ = β₄ = β₅ = 0: ninguna de las variables predictoras es significativa en el modelo. H₁: al menos un βⱼ ≠ 0: al menos una de las variables predictoras es significativa en el modelo.

Para ambas pruebas se utilizará un nivel de significancia de 0.05. Cuando el p-value sea menor a 0.05 se rechazará la hipótesis nula.

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

summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1261.89   -36.60    -3.33    36.94   874.18 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -258.96922   16.51466  -15.68  < 2e-16 ***
## areaconst       1.49085    0.06261   23.81  < 2e-16 ***
## estrato        50.09751    3.44438   14.54  < 2e-16 ***
## habitaciones  -20.72863    4.36435   -4.75  2.2e-06 ***
## parqueaderos   84.76186    5.14210   16.48  < 2e-16 ***
## banios         52.44016    3.90091   13.44  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 93.56 on 1834 degrees of freedom
## Multiple R-squared:  0.7956, Adjusted R-squared:  0.795 
## F-statistic:  1427 on 5 and 1834 DF,  p-value: < 2.2e-16

Los resultados muestran que todas las variables predictoras incluidas en el modelo son estadísticamente significativas, ya que presentan valores p menores a 0.05. Esto representa una diferencia frente al caso 1, donde la variable habitaciones no resultó significativa. Manteniendo constantes las demás variables, por cada metro cuadrado adicional de área construida, el precio estimado aumenta aproximadamente 1.49 millones de pesos. Por cada nivel adicional de estrato aumenta aproximadamente 50.10 millones, por cada parqueadero adicional aumenta 84.76 millones y por cada baño adicional aumenta 52.44 millones. En el caso de las habitaciones se obtiene un coeficiente negativo de -20.73 millones. Aunque inicialmente se observó una relación positiva entre habitaciones y precio, al considerar al mismo tiempo las demás variables del modelo la relación cambia. Esto indica que, manteniendo constantes el área, estrato, parqueaderos y baños, una habitación adicional se relaciona con una disminución aproximada de 20.73 millones en el precio estimado. El modelo presenta un R² de 0.7956, lo que indica que aproximadamente el 79.56 % de la variación observada en el precio de los apartamentos puede ser explicada por las variables incluidas. El R² ajustado es de 0.795, muy cercano al R². Finalmente, la prueba F global presenta un p-value menor a 0.05, por lo que el modelo en conjunto es estadísticamente significativo.

Para analizar un poco más la situación de habitaciones, calculemos el valor VIF y el modelo de regresión tomando unicamente la variable habitaciones:

library(car)
vif(modelo2)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     2.315361     1.733426     1.412797     2.198524     2.754664
modelo_hab_solo <- lm(preciom ~ habitaciones, data = base2)
summary(modelo_hab_solo)
## 
## Call:
## lm(formula = preciom ~ habitaciones, data = base2)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -560.13 -105.03  -44.98   40.07 1425.02 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   -65.178     22.632   -2.88  0.00402 ** 
## habitaciones  130.052      7.524   17.29  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 191.7 on 1838 degrees of freedom
## Multiple R-squared:  0.1398, Adjusted R-squared:  0.1394 
## F-statistic: 298.8 on 1 and 1838 DF,  p-value: < 2.2e-16

Aunque inicialmente se observó una relación positiva entre el número de habitaciones y el precio, al analizar únicamente esta variable se obtiene un coeficiente positivo cercano a 130 millones de pesos. Sin embargo, al incluirla junto con las demás variables en el modelo múltiple, su coeficiente cambia a -20.73 millones. Esto se debe a que el modelo múltiple evalúa el efecto de las habitaciones manteniendo constantes características como el área, estrato, baños y parqueaderos. Por ejemplo, entre dos apartamentos con la misma área y características similares, aquel que tenga un mayor número de habitaciones puede presentar una mayor división del espacio. Adicionalmente, los valores VIF son inferiores a 5, por lo que este cambio de signo no parece estar relacionado con un problema importante de multicolinealidad.

Intervalos de confianza de los coeficientes

confint(modelo2, level = 0.95)
##                    2.5 %      97.5 %
## (Intercept)  -291.358733 -226.579715
## areaconst       1.368059    1.613646
## estrato        43.342194   56.852827
## habitaciones  -29.288243  -12.169011
## parqueaderos   74.676870   94.846857
## banios         44.789474   60.090844

Los intervalos de confianza al 95 % muestran que ninguno de los coeficientes de las variables predictoras incluye el valor cero, lo cual coincide con los resultados de las pruebas de significancia, donde todas las variables presentaron un p-value menor a 0.05. En el caso particular de habitaciones, el intervalo se encuentra entre -29.29 y -12.17, confirmando que su efecto dentro del modelo múltiple es negativo y estadísticamente significativo.

Validación de los supuestos del modelo

Una vez estimado el modelo de regresión lineal multiple, se validaran los supuestos con el fin de determinar si el modelo es confiable y si existen problremas que puedan afectar sus resultados.

Normalidad de los residuos

Se evalua el supuesto de normalidad de los residuos mediante el gráfico Q-Q, el cual permite comparar la distribucion de los residuos del modelo con una distribucion nromal. Se espera que los residuos se acerquen a la linea recta, para confirmar su distribucion normal.

qqnorm(
  residuals(modelo2),
  main = "Gráfico Q-Q de los residuos"
)

qqline(
  residuals(modelo2),
  col = "red",
  lwd = 2
)

En el gráfico Q-Q se observa un comportamiento similar al presentado en el caso 1. Gran parte de los residuos ubicados en la zona central se encuentran sobre o cerca de la línea de referencia. Sin embargo, hacia los extremos se presentan desviaciones considerables, especialmente en la cola derecha. Por lo tanto, los residuos presentan un comportamiento cercano a la normalidad en la parte central, pero existen desviaciones importantes en las colas, por lo que el supuesto de normalidad no se cumple completamente.

Homocedasticidad

A continuación, se evalúa el supuesto de homocedasticidad, con el fin de verificar si la variabilidad de los residuos se mantiene aproximadamente constante a lo largo de los valores estimados por el modelo. Para este supuesto se busca residuos distribuuidos alrededor de 0 con una dispersion mas o menso constante alrededor.

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

abline(h = 0, col = "red", lwd = 2)

En el gráfico de residuos vs. valores ajustados se observa un comportamiento similar al caso 1, aunque en este caso la dispersión parece ser menor. Para los valores ajustados más bajos, los residuos se encuentran relativamente concentrados alrededor de cero. Sin embargo, a medida que aumentan los valores ajustados, también aumenta la dispersión de los residuos, formando una especie de abanico. Además, se observan algunos valores extremos en la zona de precios más altos. Por lo tanto, la variabilidad de los errores no se mantiene constante y se presenta evidencia de heterocedasticidad.d.

Independencia de los residuos

Para evaluar la indepenencia de los residuos utilizamos el estadistico Durbin-Watson. Se espera un valor de este cercano a 2 y un p value mayor que 0.05.

library(lmtest)

dwtest(modelo2)
## 
##  Durbin-Watson test
## 
## data:  modelo2
## DW = 1.6561, p-value = 6.277e-14
## alternative hypothesis: true autocorrelation is greater than 0

Para evaluar la independencia de los residuos se realizó la prueba de Durbin-Watson. Se obtuvo un estadístico DW de 1.6561 y un p-value menor a 0.05. Por lo tanto, existe evidencia de autocorrelación positiva entre los residuos y el supuesto de independencia no se cumple completamente.

Multicolinealidad (factor VIF)

Finalmente, se evalúa la posible presencia de multicolinealidad entre las variables predictoras mediante el Factor de Inflación de la Varianza (VIF). Este análisis permite determinar si alguna de las variables predictoras presenta una relación demasiado fuerte con las demás variables incluidas en el model. Se espera un valor menor o igual a 5.

library(car)

vif(modelo2)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     2.315361     1.733426     1.412797     2.198524     2.754664

Los valores VIF obtenidos para todas las variables predictoras son inferiores a 5, encontrándose entre 1.35 y 2.17. Por lo tanto, no se evidencian problemas importantes de multicolinealidad en el modelo. Este resultado confirma lo observado anteriormente en la matriz de correlaciones, donde tampoco se encontraron relaciones excesivamente altas entre las variables predictoras.

Linealidad

La linealidad sirve para comprobar que la relacion entre las variables predictoras y el precio de las viviendas puede representarse mediante una relacion lineal. Este supuesto es posbile evaluarlo con el grafico Residuals vs Fitted, evaluando que la linea roja sea mas o menos horizontal alrededor de 0

plot(modelo2, which = 1)

La línea de tendencia presenta una ligera curvatura, pero no se observa un patrón curvo fuertemente definido. Por lo tanto, se considera que el supuesto de linealidad se cumple de manera aproximada. Sin embargo, se observan algunas desviaciones y valores atípicos que podrían estar afectando el comportamiento del modelo.

Analisis de observaciones extremas

Al igual que para el caso 1, se realiza un análisis de observaciones extremas con el fin de identificar registros que puedan presentar comportamientos atípicos o tener una influencia importante sobre el modelo. Para esto se analizarán los residuos studentizados, el leverage y la distancia de Cook.

Residuos studentizados

Esta sección responde a que viviendas tienen un error de prediccion muy grande. Para este análisis se consideran como posibles observaciones atípicas aquellas cuyos residuos studentizados presentan un valor absoluto superior a 3.

res_student <- rstudent(modelo2)

unname(which(abs(res_student) > 3))
##  [1]  106  107  196  197  247  280  301  303  357  495  522  596  784  821  852
## [16]  928  929  994  998  999 1021 1037 1519 1825

Se identificaron 24 observaciones con residuos studentizados superiores a 3 en valor absoluto. Estas representan aproximadamente el 1.3 % de las 1840 viviendas analizadas, por lo que se consideran posibles observaciones atípicas que deberían ser revisadas.

Leverage

El leverage permite identificar observaciones que presentan combinaciones poco comunes en las variables predictoras, es decir, viviendas cuyas características de área, estrato, habitaciones, parqueaderos o baños se alejan considerablemente del comportamiento general de los datos..

leverage <- hatvalues(modelo2)

limite_leverage2 <- 2 * length(coef(modelo2)) / nrow(base2)

limite_leverage2
## [1] 0.006521739
unname(which(leverage > limite_leverage2))
##   [1]   18   21   22  106  107  122  178  183  186  188  193  196  197  206  215
##  [16]  219  220  254  272  280  286  287  288  290  291  301  302  303  317  326
##  [31]  341  346  349  356  360  361  364  369  374  375  377  402  435  449  495
##  [46]  522  527  533  545  548  560  575  585  596  618  623  631  635  714  742
##  [61]  785  787  808  821  850  852  869  877  885  886  890  914  916  918  921
##  [76]  927  928  929  930  932  933  941  944  948  954  961  973  980  981  987
##  [91]  989  993  999 1001 1012 1014 1018 1019 1020 1021 1022 1023 1024 1028 1032
## [106] 1037 1042 1046 1047 1110 1327 1413 1519 1820 1825 1840
sum(leverage > limite_leverage2)
## [1] 116
sum(leverage > limite_leverage2) / nrow(base2) * 100
## [1] 6.304348

Para identificar observaciones con combinaciones poco comunes en las variables predictoras, se analiza el leverage. Como criterio de referencia se utiliza 2p/n. Para este modelo se obtiene un límite de 0.0065. Se identificaron 116 observaciones con valores de leverage superiores a este límite, lo que representa aproximadamente el 6.30 % de las 1840 viviendas analizadas. Estas observaciones presentan características que se alejan del comportamiento general de los datos, aunque esto no significa necesariamente que tengan una influencia importante sobre el modelo. Para ello, en la siguiente subsección analizaremos la distancia de cook, ya que permitirá evaluar cuales de esas observaciones tienene una influencia importante en el modelo.

Distancia de cook

Finalmente, se utiliza la distancia de Cook para identificar observaciones que pueden tener una influencia importante sobre el modelo. A diferencia del leverage, que identifica observaciones con características predictoras poco comunes, la distancia de Cook permite evaluar qué tanto puede influir una observación sobre los resultados del modelo. Se utiliza como referencia el criterio Di>4/n, por lo que Di>0.006

cook2 <- cooks.distance(modelo2)

limite_cook <- 4 / nrow(base2)

limite_cook
## [1] 0.002173913
unname(which(cook2 > limite_cook))
##  [1]   18   22   36   57  106  107  122  178  183  196  197  206  211  219  247
## [16]  266  269  271  280  283  286  287  288  290  291  301  303  317  320  337
## [31]  338  339  342  349  356  357  361  362  369  370  493  494  495  515  522
## [46]  527  533  537  539  541  544  569  575  596  598  618  635  743  768  784
## [61]  821  852  885  886  889  897  899  921  927  928  929  932  933  946  952
## [76]  955  956  989  994  998  999 1012 1021 1023 1028 1037 1042 1047 1058 1519
## [91] 1825 1840
sum(cook2 > limite_cook)
## [1] 92
sum(cook2 > limite_cook) / nrow(base2) * 100
## [1] 5
plot(
  cook2,
  type = "h",
  ylab = "Distancia de Cook",
  main = "Distancia de Cook"
)

abline(
  h = limite_cook,
  col = "red",
  lty = 2
)

Se identificaron 92 observaciones con una distancia de Cook superior al límite establecido de 0.00217, las cuales representan aproximadamente el 5 % de las 1840 viviendas analizadas. Estas observaciones pueden considerarse potencialmente influyentes sobre el modelo. Adicionalmente, en el gráfico se observa una observación que sobresale considerablemente respecto a las demás, ubicada alrededor del índice 1519, por lo que resulta conveniente revisarla de manera particular para determinar qué características presenta y por qué genera una influencia tan alta sobre el modelo.

A continuación revisaremos las caracteristicas de la vivienda con indice 1519.

base2[1519, ]
## # A tibble: 1 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  6121 Zona S… 07          5     299       932            1      3            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Al revisar la observación con mayor distancia de Cook, correspondiente al índice 1519 (ID 6121), se observa un apartamento con 932 m² de área construida, estrato 5, 3 habitaciones, 3 baños, 1 parqueadero y un precio de 299 millones de pesos. Este registro se aleja bastante del comportamiento general de los datos, principalmente porque presenta un área construida muy grande para un precio relativamente bajo. Esto puede explicar por qué esta observación tiene una influencia tan alta sobre el modelo.

Sugerencias

La validación de los supuestos muestra que el modelo presenta algunas limitaciones. La normalidad de los residuos se cumple principalmente en la parte central, pero presenta desviaciones importantes en los extremos. También se observa heterocedasticidad y la prueba de Durbin-Watson indica problemas con la independencia de los residuos. Por otro lado, no se encontraron problemas importantes de multicolinealidad y la linealidad se cumple de manera aproximada. Adicionalmente, se identificaron algunas observaciones atípicas o que pueden tener una influencia importante sobre el modelo. En particular, la observación con índice 1519 (ID 6121) presenta una distancia de Cook considerablemente mayor que las demás, por lo que sería importante revisar este registro.

Como posibles mejoras se podría:

  • Revisar las observaciones atípicas e influyentes, especialmente la observación 1519 (ID 6121), que corresponde a un apartamento de 932 m² con un precio de 299 millones. Antes de eliminarla sería importante verificar si la información registrada es correcta.
  • Probar el modelo sin las observaciones más influyentes y comparar los resultados con el modelo actual, para determinar qué tanto están afectando los coeficientes y el ajuste del modelo.
  • Revisar el comportamiento de la variable habitaciones, ya que aunque resulta significativa en el modelo múltiple, presenta un coeficiente negativo, contrario a la relación positiva observada cuando se analiza individualmente. Esto podría deberse a la relación que tiene esta variable con otras características de las viviendas.
  • Evaluar otras alternativas para manejar la heterocedasticidad y los problemas de independencia de los residuos, y posteriormente verificar si estas alternativas mejoran el comportamiento del modelo.

Predicción del precio de la Vivienda 2

La solicitud para la vivienda 2 tiene las siguientes características - Tipo: Apartamento - Zona: Sur de Cali -Área construida: 300 m² - Parqueaderos: 3 - Baños: 3 - Habitaciones: 5 - Estrato: 5 o 6 - Presupuesto máximo: 850 millones de pesos

Como hay 2 posibilidades para estrato, se realizaran 2 predicciones: una suponiendo estrato 5 y otra estrato 6.

Creamos las caracteristicas de la vivienda 2, teniendo estrato 5 y estrato 6

vivienda2_pred <- data.frame(
  areaconst = c(300, 300),
  estrato = c(5, 6),
  habitaciones = c(5, 5),
  parqueaderos = c(3, 3),
  banios = c(3, 3)
)

vivienda2_pred
##   areaconst estrato habitaciones parqueaderos banios
## 1       300       5            5            3      3
## 2       300       6            5            3      3

Con el modelo 2, realizamos la prediccion del precio de la vivienda 2.

predict(modelo2, newdata = vivienda2_pred)
##        1        2 
## 746.7370 796.8345

Para la vivienda 2 se realizaron dos predicciones, debido a que la solicitud permite viviendas de estrato 5 o 6. Manteniendo las demás características constantes, el modelo estima un precio de aproximadamente 746,74 millones de pesos para estrato 5 y 796,83 millones de pesos para estrato 6. Ambos valores se encuentran dentro del presupuesto máximo de 850 millones de pesos, por lo que, de acuerdo con el modelo, sería posible encontrar opciones que cumplan con las características solicitadas en ambos estratos. Además, entre las dos predicciones se presenta una diferencia aproximada de 50,10 millones de pesos, valor que coincide con el coeficiente estimado para la variable estrato en el modelo (50,10 millones por cada nivel adicional de estrato), mostrando coherencia entre los resultados de la predicción y el modelo obtenido.

Como estamos prediciendo el precio de una vivienda en particular, es posible obtener los intervalos de predicción para ambos estratos.

predict(
  modelo2,
  newdata = vivienda2_pred,
  interval = "prediction",
  level = 0.95
)
##        fit      lwr      upr
## 1 746.7370 561.3633 932.1106
## 2 796.8345 611.5133 982.1557

Los intervalos de predicción obtenidos son más estrechos que los presentados en el caso 1. Para una vivienda de estrato 5, el precio estimado es de 746.73 millones de pesos, con un intervalo entre 561.36 y 932.11 millones. Para estrato 6, el precio estimado es de 796.83 millones, con un intervalo entre 611.51 y 982.16 millones. Esta menor amplitud puede estar relacionada con que el modelo 2 presentó un mejor ajuste y una menor dispersión de los residuos, por lo que existe menos incertidumbre en las predicciones. Sin embargo, los intervalos siguen siendo amplios y deben tomarse como valores de referencia y no como precios exactos. También es importante observar que, aunque los dos precios estimados se encuentran por debajo del presupuesto máximo de 850 millones, el límite superior de ambos intervalos supera este valor. Esto indica que en la realidad podrían encontrarse apartamentos con estas mismas características cuyo precio supere el presupuesto. Por esta razón, para la recomendación final también se revisarán los precios reales y las características de las viviendas disponibles en la base de datos.

Selección de ofertas para la Vivienda 2

Teniendo en cuenta que el crédito preaprobado para la Vivienda 2 es de máximo 850millones de pesos, se realiza una búsqueda dentro de la base 2 de viviendas que se ajusten al presupuesto y presenten características cercanas a las solicitadas. Se consideran viviendas de estrato 5 y 6, de acuerdo con los requerimientos del cliente, y se establece inicialmente un rango de área construida entre 280 y 310 m², tomando como referencia los 300 m² solicitados.

Como paso inicial realicemos un filtro de los apartamentos que se encuentran en base 2 que se encuentran entre 250 metros cuadrados y 350 metros cuadrados.

base2 %>%
  filter(
    estrato %in% c(5,6),
    areaconst >= 250,
    areaconst <= 350
  ) %>%
  arrange(abs(areaconst - 300)) %>%
  select(id, estrato, preciom, areaconst,
         parqueaderos, banios, habitaciones)
## # A tibble: 26 × 7
##       id estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  3785       6    1580       296            4      4            3
##  2  4706       6     980       306            4      5            3
##  3  3809       6     980       306            4      4            3
##  4  4870       6     980       306            4      4            3
##  5  6197       6    1700       290            3      4            3
##  6  6510       6    1600       290            3      5            4
##  7  6512       6    1750       290            3      4            3
##  8  5472       6    1590       310            3      4            3
##  9  5767       6     950       287            4      5            3
## 10  5306       5     650       275            2      5            5
## # ℹ 16 more rows

Ahora realicemos un filtro de las viviendas que cumplan con el filtro anterior y además cumplan con el presupuesto máximo planteado.

base2 %>%
  filter(
    estrato %in% c(5, 6),
    areaconst >= 250,
    areaconst <= 350,
    preciom <= 850
  ) %>%
  arrange(abs(areaconst - 300)) %>%
  select(
    id, estrato, preciom, areaconst,
    parqueaderos, banios, habitaciones
  )
## # A tibble: 4 × 7
##      id estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  5306       5     650       275            2      5            5
## 2  6175       5     350       270            3      3            4
## 3  6205       5     350       260            3      3            3
## 4  4266       6     700       250            2      4            5

Después de aplicar los filtros de área construida y presupuesto máximo, se obtienen cuatro viviendas como posibles opciones preliminares. Al evaluar sus principales características, se observa que ninguna cumple exactamente con todos los requerimientos de la Vivienda 2. Sin embargo, algunas presentan condiciones bastante cercanas, por lo que se comparan aspectos como el área, número de habitaciones, baños y parqueaderos para seleccionar la alternativa más conveniente. Entre las cuatro viviendas encontradas, se considera que la vivienda ID 6175 es la opción que mejor se ajusta a la solicitud. Corresponde a un apartamento de estrato 5, con 270 m², 3 parqueaderos, 3 baños y 4 habitaciones, y un precio de 350 millones de pesos, considerablemente por debajo del presupuesto máximo de 850 millones. Esta vivienda cumple con el número de parqueaderos y baños solicitados y presenta un área relativamente cercana a los 300 m² requeridos. Su principal diferencia es que cuenta con 4 habitaciones en lugar de las 5 solicitadas. Por esta razón, podría considerarse como la mejor alternativa si el cliente está dispuesto a aceptar una habitación menos.

Conclusión final

El desarrollo de este trabajo fue retador, ya que fue necesario realizar una serie de pasos de manera ordenada para poder llegar a los resultados finales. Se partió de la revisión y limpieza de los datos, la identificación de las viviendas correspondientes a cada zona, el análisis exploratorio, la construcción de los modelos de regresión y la validación de sus supuestos, hasta llegar finalmente a la predicción de precios y selección de posibles viviendas para cada solicitud. Aunque el procedimiento aplicado en los dos casos fue prácticamente el mismo, los resultados obtenidos fueron diferentes. En el Caso 2 el modelo presentó un mejor ajuste y relaciones más claras entre varias de las características de las viviendas y su precio, lo que permitió realizar estimaciones con una menor incertidumbre en comparación con el Caso 1. Esto muestra que, aun utilizando la misma metodología, el comportamiento de los datos puede cambiar considerablemente dependiendo del tipo de vivienda y de la zona analizada.

Finalmente, el ejercicio permitió comprobar que el modelo de regresión es una herramienta útil para orientar la búsqueda y estimar precios, pero no debe utilizarse como único criterio para tomar una decisión. La selección final también debe considerar las características reales de las viviendas disponibles, el presupuesto y qué tan cerca se encuentran de las necesidades planteadas por el cliente.