Informe Ejecutivo: Análisis de Ofertas de Vivienda en Cali

1. Introducción

María, agente de bienes raíces con una vasta experiencia en el sector, ha recibido una solicitud de asesoría para la compra de dos viviendas por parte de una compañía internacional. Esta compañía desea ubicar a dos de sus empleados con sus familias en la ciudad de Cali. Las solicitudes incluyen una serie de características específicas para las viviendas, tanto en términos de estructura como de ubicación y precio. En este informe, se presenta un análisis detallado de las ofertas disponibles en el mercado que cumplen con las características solicitadas.

2. Análisis de la Situación Actual

El mercado inmobiliario en Cali ha experimentado una disminución en las ventas de bienes raíces en lo corrido del año, influenciado por las tensiones políticas y sociales. Sin embargo, se espera una recuperación en el corto plazo con la reactivación económica. En este contexto, se ha realizado un análisis exhaustivo de las ofertas disponibles, utilizando técnicas de modelación y análisis de datos para identificar las opciones más viables para la compañía internacional.

3. Análisis Exploratorio de Datos

Se realizó un análisis exploratorio de las viviendas disponibles en las zonas Norte y Sur de Cali, utilizando variables clave como área construida, estrato, número de baños, número de habitaciones, y precio. Los resultados indican una correlación significativa entre el precio de la vivienda y las variables mencionadas. En particular, se observó que:

Área construida y número de habitaciones son las variables con mayor correlación positiva con el precio. Estrato también muestra una correlación positiva, aunque ligeramente más baja. Número de baños y parqueaderos también influyen positivamente en el precio, pero en menor medida. Estas correlaciones confirman la importancia de estas variables en la determinación del precio de las viviendas.

4. Modelos de Regresión

Se estimaron modelos de regresión lineal múltiple para predecir el precio de las viviendas con base en las variables mencionadas. Los coeficientes del modelo son estadísticamente significativos y reflejan el impacto esperado de cada variable en el precio de la vivienda.

En particular:

Área construida: Un aumento en el área construida resulta en un aumento significativo en el precio de la vivienda. Estrato: Viviendas en estratos más altos tienen precios significativamente mayores. Número de habitaciones: Cada habitación adicional aumenta el precio de manera considerable. R² del modelo: El modelo explica un porcentaje considerable de la variabilidad en los precios, lo que sugiere un buen ajuste.

5. Predicciones y Sugerencias de Ofertas

Primera Solicitud (Casa en Zona Norte) Para la primera solicitud, que busca una casa en la Zona Norte con un crédito pre-aprobado de 350 millones de pesos, se identificaron varias ofertas que cumplen con estos criterios. Las predicciones del modelo sugieren que estas opciones están dentro del rango de precio accesible para la compañía. Las propiedades sugeridas tienen un precio estimado que se ajusta al presupuesto y cumplen con las especificaciones de área, estrato, y número de habitaciones.

Segunda Solicitud (Apartamento en Zona Sur) En el caso de la segunda solicitud, que busca un apartamento en la Zona Sur con un crédito pre-aprobado de 850 millones de pesos, también se identificaron múltiples opciones viables. Las ofertas seleccionadas no solo cumplen con los requisitos de espacio y ubicación, sino que también se ajustan al rango de precio esperado, lo que las convierte en opciones altamente recomendadas.

6. Recomendaciones Finales

Oferta 1: Se recomienda comprar una casa en la Zona Norte, dada su excelente relación precio-calidad y el ajuste preciso al presupuesto de 350 millones. El precio predicho para la primera solicitud es: 312.1 millones de pesos

Interpretación del Modelo de Regresión Lineal Múltiple

1. Ecuación del Modelo: El modelo predice el precio de una vivienda (preciompreciom) en función de cinco variables: área construida (areaconstareaconst), estrato (estratoestrato), número de parqueaderos (parqueaderosparqueaderos), número de baños (baniosbanios), y número de habitaciones (habitacioneshabitaciones).

2. Coeficientes:

  • Intercepto (-238.17): El precio base (cuando todas las variables son cero) sería negativo, lo cual no es interpretativamente significativo en este contexto, pero se debe a la naturaleza del modelo.

  • Área construida (0.676730.67673): Por cada metro cuadrado adicional, el precio de la vivienda aumenta en promedio 0.68 millones de pesos.

  • Estrato (80.6380.63): Cada incremento en el estrato aumenta el precio en aproximadamente 80.63 millones de pesos.

  • Parqueaderos (24.0124.01): Cada parqueadero adicional aumenta el precio en 24.01 millones de pesos.

  • Baños (18.9018.90): Cada baño adicional incrementa el precio en 18.90 millones de pesos.

  • Habitaciones (7.657.65): Este coeficiente no es estadísticamente significativo (p=0.177p=0.177), indicando que el número de habitaciones no tiene un impacto claro en el precio.

3. Significación Estadística:

  • Área construida, estrato, parqueaderos y baños tienen coeficientes altamente significativos (p<0.05p<0.05), lo que indica que estas variables están fuertemente asociadas con el precio de la vivienda.

  • Número de habitaciones no es estadísticamente significativo (p=0.177p=0.177), lo que sugiere que no es un buen predictor del precio en este modelo.

4. Calidad del Modelo:

  • R2=0.6041R2=0.6041: Aproximadamente el 60.41% de la variabilidad en el precio de las viviendas es explicada por este modelo.

  • Error estándar de los residuos (155.1): Muestra la dispersión de los puntos alrededor de la línea de regresión, indicando un error medio de 155.1 millones de pesos en las predicciones.

  • Rendimiento del Modelo:

    Error Cuadrático Medio (MSE = 23606.68 ): Este valor mide la media de los errores al cuadrado entre los valores predichos y los reales. Un MSE alto indica que, en promedio, las predicciones del modelo se desvían bastante de los valores reales. En este caso, un MSE de 23606.68 sugiere que hay una considerable dispersión de los errores.

    Error Absoluto Medio (MAE = 97.18533 ): El MAE mide la magnitud media de los errores de predicción en unidades originales (millones de pesos, en este caso). Un MAE de 97.18533 indica que, en promedio, las predicciones del modelo se desvían 97.1 millones de pesos del valor real.

El modelo tiene un ajuste razonable con una buena capacidad explicativa, aunque podría mejorarse. Variables como el área construida, estrato, y número de parqueaderos son los factores más determinantes en el precio de una vivienda en este caso, mientras que el número de habitaciones no muestra una influencia significativa. El MSE y el MAE sugieren que el modelo tiene una precisión limitada y podría beneficiarse de mejoras adicionales, como la inclusión de más variables predictoras o la exploración de modelos más complejos.

Basado en lo anterior, el modelo permite encontrar que la mejor opción es una casa en el barrio la merced (ver mapa abajo). Con un precio de 310.2 millones, la cual cumple con todas las caracteristicas solicitadas por los compradores.

Oferta 2: Para la segunda solicitud, se recomienda una de las opciones de apartamentos en la Zona Sur, que no solo ofrece una excelente ubicación sino que también se encuentra dentro del presupuesto disponible. El precio predicho para la segunda solicitud es: 675.02 millones de pesos.

Siguiendo la misma interpretación que la anterior, en este nuevo modelo. La mejor opción es una casa en el barrio seminario, con un valor de 751.5 millones.

P.S. Aunque el ejercicio solicitaba 5 opciones de casa. Las casas mencionadas con las unicas que cumplen todos los requisitos solicitados por el comprador.

7. Conclusiones

El análisis realizado permite a María ofrecer recomendaciones fundamentadas a la compañía internacional, asegurando que las opciones seleccionadas no solo cumplen con las necesidades de los empleados, sino que también representan una inversión segura en un mercado que está próximo a reactivarse. La combinación de técnicas de análisis exploratorio y modelación predictiva ha sido clave para identificar las mejores ofertas disponibles.

library(paqueteMODELOS)
## Loading required package: boot
## Loading required package: broom
## Warning: package 'broom' was built under R version 4.3.3
## Loading required package: GGally
## Loading required package: ggplot2
## Registered S3 method overwritten by 'GGally':
##   method from   
##   +.gg   ggplot2
## Loading required package: gridExtra
## Loading required package: knitr
## Loading required package: summarytools
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:gridExtra':
## 
##     combine
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
library(leaflet)
library(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
## The following object is masked from 'package:boot':
## 
##     logit
library(plotly)
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
data("vivienda")
# 1. Filtrado de la base de datos para casas en la Zona Norte
base1 <- vivienda[vivienda$tipo == "Casa" & vivienda$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>
# Asegúrate de que los datos filtrados no tengan valores NA en latitud y longitud
base1_clean <- base1[!is.na(base1$latitud) & !is.na(base1$longitud), ]

# Crea un mapa con leaflet
map <- leaflet(base1_clean) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~paste("Barrio:", barrio, "<br>",
                   "Precio:", preciom, "millones") # Personaliza el contenido del popup
  )

# Muestra el mapa
map

Se evidencia una mayor concentación de puntos en la Zona Norte como es esperado debido al filtro que se aplicó. Sin embargo, llama la atención que además hay puntos en la zona sur y dispersos por toda la ciudad. Esto se puede deber a una categorización (labeling) incorrecto en la base de datos.

# Correlaciones entre variables seleccionadas
correlations <- cor(base1 %>% select(preciom, areaconst, estrato, parqueaderos, banios, habitaciones), use = "complete.obs")
print(correlations)
##                preciom areaconst    estrato parqueaderos    banios habitaciones
## preciom      1.0000000 0.6853915 0.52827831    0.4116620 0.5086427   0.36508586
## areaconst    0.6853915 1.0000000 0.35352525    0.3069709 0.4574766   0.42068968
## estrato      0.5282783 0.3535252 1.00000000    0.2612647 0.3512569   0.05819709
## parqueaderos 0.4116620 0.3069709 0.26126471    1.0000000 0.3918638   0.24139617
## banios       0.5086427 0.4574766 0.35125685    0.3918638 1.0000000   0.59038214
## habitaciones 0.3650859 0.4206897 0.05819709    0.2413962 0.5903821   1.00000000
ggpairs(base1[,4:9], title=" ") 
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 290 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 290 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 290 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning: Removed 290 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 290 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 290 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 290 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 290 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 290 rows containing missing values
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 290 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 290 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).

# 3. Modelo de regresión lineal múltiple
modelo <- lm(preciom ~ areaconst + estrato + parqueaderos + banios + habitaciones, data = base1)
summary(modelo)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + parqueaderos + banios + 
##     habitaciones, data = base1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -784.29  -77.56  -16.03   47.67  978.61 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -238.17090   44.40551  -5.364 1.34e-07 ***
## areaconst       0.67673    0.05281  12.814  < 2e-16 ***
## estrato        80.63495    9.82632   8.206 2.70e-15 ***
## parqueaderos   24.00598    5.86889   4.090 5.14e-05 ***
## banios         18.89938    7.48800   2.524    0.012 *  
## habitaciones    7.64511    5.65873   1.351    0.177    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 155.1 on 429 degrees of freedom
##   (290 observations deleted due to missingness)
## Multiple R-squared:  0.6041, Adjusted R-squared:  0.5995 
## F-statistic: 130.9 on 5 and 429 DF,  p-value: < 2.2e-16
# Interpretación de los coeficientes y R^2
tidy(modelo)
## # A tibble: 6 × 5
##   term         estimate std.error statistic  p.value
##   <chr>           <dbl>     <dbl>     <dbl>    <dbl>
## 1 (Intercept)  -238.      44.4        -5.36 1.34e- 7
## 2 areaconst       0.677    0.0528     12.8  4.70e-32
## 3 estrato        80.6      9.83        8.21 2.70e-15
## 4 parqueaderos   24.0      5.87        4.09 5.14e- 5
## 5 banios         18.9      7.49        2.52 1.20e- 2
## 6 habitaciones    7.65     5.66        1.35 1.77e- 1
glance(modelo) # Incluye el R^2
## # A tibble: 1 × 12
##   r.squared adj.r.squared sigma statistic  p.value    df logLik   AIC   BIC
##       <dbl>         <dbl> <dbl>     <dbl>    <dbl> <dbl>  <dbl> <dbl> <dbl>
## 1     0.604         0.599  155.      131. 5.42e-84     5 -2808. 5631. 5659.
## # ℹ 3 more variables: deviance <dbl>, df.residual <int>, nobs <int>
# 4. Validación de supuestos del modelo
# Normalidad de los residuos
qqPlot(modelo, main = "QQ Plot")

## [1] 405 513
# Homocedasticidad
ncvTest(modelo)
## Non-constant Variance Score Test 
## Variance formula: ~ fitted.values 
## Chisquare = 352.7061, Df = 1, p = < 2.22e-16
# Independencia de los residuos
durbinWatsonTest(modelo)
##  lag Autocorrelation D-W Statistic p-value
##    1       0.1173407      1.761505   0.008
##  Alternative hypothesis: rho != 0
# Linealidad
plot(modelo, which = 1)

# Dividir los datos en entrenamiento y prueba
set.seed(123)
train_indices <- sample(1:nrow(base1), 0.7 * nrow(base1))
train_data <- base1[train_indices, ]
test_data <- base1[-train_indices, ]

# Estimar el modelo en el set de entrenamiento
modelo <- lm(preciom ~ areaconst + estrato + parqueaderos + banios + habitaciones, data = train_data)

# Predicciones en el set de prueba
test_data$predicciones <- predict(modelo, test_data)
test_data$predicciones
##         1         2         3         4         5         6         7         8 
##  446.4897  534.3219        NA  525.5452  518.2511        NA        NA        NA 
##         9        10        11        12        13        14        15        16 
##        NA        NA        NA        NA        NA        NA        NA        NA 
##        17        18        19        20        21        22        23        24 
##        NA        NA        NA        NA        NA        NA        NA        NA 
##        25        26        27        28        29        30        31        32 
##  258.6492  253.2745        NA        NA  283.4657        NA        NA        NA 
##        33        34        35        36        37        38        39        40 
##  242.1747        NA        NA        NA  172.5127        NA        NA        NA 
##        41        42        43        44        45        46        47        48 
##        NA  178.8796  169.5204        NA        NA  400.4173  382.3157  389.9376 
##        49        50        51        52        53        54        55        56 
##  584.5243  482.2995  519.2814  431.2388        NA  203.3585        NA  185.1191 
##        57        58        59        60        61        62        63        64 
##  319.5827        NA  409.2619  515.7417  607.7276  888.5051  942.5556  571.7691 
##        65        66        67        68        69        70        71        72 
##  451.8877        NA  589.2429  382.4432  633.6747  452.4743  700.0896  692.3917 
##        73        74        75        76        77        78        79        80 
##  723.0482  452.4743  471.1928  460.3409  656.1439  357.1271  660.1324        NA 
##        81        82        83        84        85        86        87        88 
##  632.0475        NA  425.5028  580.0293  431.5047  460.3409  560.7859  444.6623 
##        89        90        91        92        93        94        95        96 
##  652.6076  632.1994  668.7819  730.5215  408.1809  461.5231  369.5263  321.8370 
##        97        98        99       100       101       102       103       104 
##  403.8435  413.3303  377.5102  365.2861  527.0968  371.7844  348.9359        NA 
##       105       106       107       108       109       110       111       112 
##        NA        NA        NA  202.7172  268.6254  449.0917        NA        NA 
##       113       114       115       116       117       118       119       120 
##        NA  503.7789  209.3430        NA        NA  206.0958  239.4169        NA 
##       121       122       123       124       125       126       127       128 
##  559.4074  738.4752  248.5972        NA  328.1079  328.2759  321.6540        NA 
##       129       130       131       132       133       134       135       136 
##        NA        NA  529.9786  439.9953  450.8471  551.2617  622.5439        NA 
##       137       138       139       140       141       142       143       144 
##  374.3389  484.5334  178.8796        NA  287.9749  282.8043  254.0086        NA 
##       145       146       147       148       149       150       151       152 
##        NA  197.5981        NA  452.1323  438.1608  617.4693  515.7068  487.4843 
##       153       154       155       156       157       158       159       160 
##  581.8766  795.7427  529.8027        NA        NA  554.0133        NA  487.7877 
##       161       162       163       164       165       166       167       168 
##  515.6034  626.3187  643.4790 1067.1028  648.0539  870.9901  652.3527  617.2699 
##       169       170       171       172       173       174       175       176 
##  776.5360  465.8149  944.8195  623.8846  212.2078        NA  353.3764  562.0338 
##       177       178       179       180       181       182       183       184 
##  736.6894  397.0529 1013.4368  577.3917  523.4701  548.1794  576.8953  763.8670 
##       185       186       187       188       189       190       191       192 
##        NA  551.8098  178.7522        NA        NA        NA        NA        NA 
##       193       194       195       196       197       198       199       200 
##        NA        NA        NA  166.2732        NA  248.1007  253.7163  248.1007 
##       201       202       203       204       205       206       207       208 
##  137.5715        NA        NA  424.8273  380.2751  397.7385  436.4892  414.7268 
##       209       210       211       212       213       214       215       216 
##  711.1692  592.6871  351.1626  576.3471        NA  570.1076        NA        NA 
##       217       218 
##  264.9474        NA
# Estimar el modelo en el set de entrenamiento
modelo <- lm(preciom ~ areaconst + estrato + parqueaderos + banios + habitaciones, data = test_data)

# Predicciones en el set de prueba
test_data$predicciones <- predict(modelo, test_data)
test_data$predicciones
##         1         2         3         4         5         6         7         8 
##  417.0423  581.9452        NA  538.9999  489.0946        NA        NA        NA 
##         9        10        11        12        13        14        15        16 
##        NA        NA        NA        NA        NA        NA        NA        NA 
##        17        18        19        20        21        22        23        24 
##        NA        NA        NA        NA        NA        NA        NA        NA 
##        25        26        27        28        29        30        31        32 
##  260.0723  214.1526        NA        NA  270.1245        NA        NA        NA 
##        33        34        35        36        37        38        39        40 
##  239.0859        NA        NA        NA  185.9141        NA        NA        NA 
##        41        42        43        44        45        46        47        48 
##        NA  175.2284  163.4691        NA        NA  432.1014  389.4513  400.2490 
##        49        50        51        52        53        54        55        56 
##  573.5836  480.4331  547.0854  413.5489        NA  151.4366        NA  183.0679 
##        57        58        59        60        61        62        63        64 
##  405.9199        NA  410.1403  518.7939  639.8207  992.5984  914.8389  573.2261 
##        65        66        67        68        69        70        71        72 
##  480.5207        NA  557.5226  370.9260  652.2275  461.9323  681.9872  748.9183 
##        73        74        75        76        77        78        79        80 
##  767.5362  461.9323  485.4508  453.4181  700.3652  379.2187  685.7570        NA 
##        81        82        83        84        85        86        87        88 
##  668.5812        NA  444.9342  548.6037  415.9660  453.4181  540.1664  415.9608 
##        89        90        91        92        93        94        95        96 
##  656.9772  596.1133  663.4919  737.1125  426.1874  476.9586  377.0393  352.6960 
##        97        98        99       100       101       102       103       104 
##  420.1565  413.3905  405.7559  353.0263  433.6496  381.3850  351.1689        NA 
##       105       106       107       108       109       110       111       112 
##        NA        NA        NA  186.4932  252.6999  424.8958        NA        NA 
##       113       114       115       116       117       118       119       120 
##        NA  459.2528  196.3266        NA        NA  210.9321  253.0851        NA 
##       121       122       123       124       125       126       127       128 
##  594.7779  728.3547  262.1837        NA  326.5085  289.7015  337.4377        NA 
##       129       130       131       132       133       134       135       136 
##        NA        NA  560.5325  446.2533  478.2861  572.5321  589.4346        NA 
##       137       138       139       140       141       142       143       144 
##  380.6502  500.7039  175.2284        NA  296.9179  287.9857  232.2519        NA 
##       145       146       147       148       149       150       151       152 
##        NA  198.7469        NA  499.2264  463.2738  596.0041  472.0908  491.1789 
##       153       154       155       156       157       158       159       160 
##  642.9157  908.6069  527.1722        NA        NA  588.8691        NA  467.9963 
##       161       162       163       164       165       166       167       168 
##  558.4266  681.8645  624.0925 1086.7708  673.8854  931.3599  694.0277  666.8382 
##       169       170       171       172       173       174       175       176 
##  814.1933  477.1853 1010.6017  644.1584  237.2969        NA  354.5995  541.7343 
##       177       178       179       180       181       182       183       184 
##  675.5076  409.4760 1094.6593  600.1972  549.9124  543.0127  542.8704  763.3405 
##       185       186       187       188       189       190       191       192 
##        NA  568.0552  193.7536        NA        NA        NA        NA        NA 
##       193       194       195       196       197       198       199       200 
##        NA        NA        NA  178.0746        NA  242.8745  249.9301  242.8745 
##       201       202       203       204       205       206       207       208 
##  142.0129        NA        NA  429.9188  373.6547  413.7073  440.3397  418.1623 
##       209       210       211       212       213       214       215       216 
##  646.8130  604.9609  389.5417  585.3649        NA  577.5254        NA        NA 
##       217       218 
##  264.0412        NA
#Filtrar aquellos valores que tuvieron prediccion
test_data <- test_data[!is.na(test_data$predicciones), ]

# Calcular el error cuadrático medio (MSE)
mse <- mean((test_data$preciom - test_data$predicciones)^2)

# Calcular el error absoluto medio (MAE)
mae <- mean(abs(test_data$preciom - test_data$predicciones))

# Imprimir los resultados
cat("MSE:", mse, "\n")
## MSE: 23606.68
cat("MAE:", mae, "\n")
## MAE: 97.18533
# 5. Predicción del precio para la primera solicitud
nueva_vivienda1 <- data.frame(
  areaconst = 200,
  estrato = 4,
  parqueaderos = 1,
  banios = 2,
  habitaciones = 4
)

precio_pred1 <- predict(modelo, nueva_vivienda1)
print(paste("El precio predicho para la primera solicitud es:", round(precio_pred1, 2), "millones de pesos"))
## [1] "El precio predicho para la primera solicitud es: 318.49 millones de pesos"
# 6. Sugerencias de ofertas para la primera solicitud
ofertas1 <- base1 %>%
  mutate(predicted_price = predict(modelo, .)) %>%
  filter(predicted_price <= 350,
           areaconst >= 200,
         estrato >= 4,
         parqueaderos >= 1,
         banios >= 2,
         habitaciones >= 4)

# Mostrar las ofertas potenciales
head(ofertas1)
## # A tibble: 1 × 14
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1222 Zona N… 02          4     360       216            2      2            4
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   predicted_price <dbl>
# Mapa con las ofertas potenciales

map <- leaflet(ofertas1) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~paste("Barrio:", barrio, "<br>",
                   "Precio:", preciom, "millones") # Personaliza el contenido del popup
  )

# Muestra el mapa
map
# 7. Repetición de los pasos 1 al 6 para la segunda solicitud
# Filtrado de la base para Apartamentos en la Zona Sur
base2 <- vivienda[vivienda$tipo == "Apartamento" & vivienda$zona == "Zona Sur", ]

# Mostrar los primeros 3 registros
head(base2)
## # A tibble: 6 × 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  1241 Zona S… <NA>        3     135       117           NA      2            3
## 5  5370 Zona S… <NA>        3     135        78           NA      1            3
## 6  6975 Zona S… 06          4     220        75            1      2            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Tabla resumen para comprobar la consulta
summary(base2)
##        id           zona               piso              estrato    
##  Min.   :   3   Length:2790        Length:2790        Min.   :3.00  
##  1st Qu.:2292   Class :character   Class :character   1st Qu.:4.00  
##  Median :4004   Mode  :character   Mode  :character   Median :5.00  
##  Mean   :4131                                         Mean   :4.63  
##  3rd Qu.:5876                                         3rd Qu.:5.00  
##  Max.   :8302                                         Max.   :6.00  
##  NA's   :3                                            NA's   :3     
##     preciom         areaconst       parqueaderos        banios     
##  Min.   :  75.0   Min.   : 40.00   Min.   : 1.000   Min.   :0.000  
##  1st Qu.: 175.0   1st Qu.: 65.00   1st Qu.: 1.000   1st Qu.:2.000  
##  Median : 245.0   Median : 85.00   Median : 1.000   Median :2.000  
##  Mean   : 297.3   Mean   : 97.47   Mean   : 1.415   Mean   :2.488  
##  3rd Qu.: 335.0   3rd Qu.:110.00   3rd Qu.: 2.000   3rd Qu.:3.000  
##  Max.   :1750.0   Max.   :932.00   Max.   :10.000   Max.   :8.000  
##  NA's   :3        NA's   :3        NA's   :409      NA's   :3      
##   habitaciones       tipo              barrio             longitud     
##  Min.   :0.000   Length:2790        Length:2790        Min.   :-76.57  
##  1st Qu.:3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median :3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   :2.966                                         Mean   :-76.53  
##  3rd Qu.:3.000                                         3rd Qu.:-76.52  
##  Max.   :6.000                                         Max.   :-76.46  
##  NA's   :3                                             NA's   :3       
##     latitud     
##  Min.   :3.334  
##  1st Qu.:3.370  
##  Median :3.383  
##  Mean   :3.390  
##  3rd Qu.:3.406  
##  Max.   :3.497  
##  NA's   :3
# Mapa con las ofertas potenciales
map <- leaflet(base2) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~paste("Barrio:", barrio, "<br>",
                   "Precio:", preciom, "millones") # Personaliza el contenido del popup
  )
## Warning in validateCoords(lng, lat, funcName): Data contains 3 rows with either
## missing or invalid lat/lon values and will be ignored
# Muestra el mapa
map
# Convertir las columnas relevantes a numéricas
base2$preciom <- as.numeric(base2$preciom)
base2$areaconst <- as.numeric(base2$areaconst)
base2$estrato <- as.numeric(base2$estrato)
base2$parqueaderos <- as.numeric(base2$parqueaderos)
base2$banios <- as.numeric(base2$banios)
base2$habitaciones <- as.numeric(base2$habitaciones)

# Ahora calcula la correlación nuevamente
correlations2 <- cor(base2 %>% select(preciom, areaconst, estrato, parqueaderos, banios, habitaciones), use = "complete.obs")
print(correlations2)
##                preciom areaconst   estrato parqueaderos    banios habitaciones
## preciom      1.0000000 0.7407150 0.6497479    0.6934386 0.7111289    0.2957800
## areaconst    0.7407150 1.0000000 0.4518617    0.5783506 0.6639216    0.4073401
## estrato      0.6497479 0.4518617 1.0000000    0.4859027 0.5348003    0.1768269
## parqueaderos 0.6934386 0.5783506 0.4859027    1.0000000 0.5563189    0.2367067
## banios       0.7111289 0.6639216 0.5348003    0.5563189 1.0000000    0.5204718
## habitaciones 0.2957800 0.4073401 0.1768269    0.2367067 0.5204718    1.0000000
# Gráficos interactivos
ggpairs(base2[,4:9], title=" ") 
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 409 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 409 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 409 rows containing missing values
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning: Removed 409 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 409 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 409 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 409 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 409 rows containing missing values

## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 409 rows containing missing values
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 409 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).
## Warning in ggally_statistic(data = data, mapping = mapping, na.rm = na.rm, :
## Removed 3 rows containing missing values
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 409 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).

# Gráfico interactivo para la relación entre área construida y precio
plot_ly(data = base1, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers') %>%
  layout(title = "Relación entre Área Construida y Precio",
         xaxis = list(title = "Área Construida (m²)"),
         yaxis = list(title = "Precio (Millones de Pesos)"))
## Warning: Ignoring 3 observations
# Gráfico interactivo para la relación entre área construida y precio
plot_ly(data = base2, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers') %>%
  layout(title = "Relación entre Área Construida y Precio",
         xaxis = list(title = "Área Construida (m²)"),
         yaxis = list(title = "Precio (Millones de Pesos)"))
## Warning: Ignoring 3 observations
# Modelo de regresión lineal múltiple para la Zona Sur
modelo2 <- lm(preciom ~ areaconst + estrato + parqueaderos + banios + habitaciones, data = base2)
summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + parqueaderos + banios + 
##     habitaciones, data = base2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1092.02   -42.28    -1.33    40.58   926.56 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -261.62501   15.63220 -16.736  < 2e-16 ***
## areaconst       1.28505    0.05403  23.785  < 2e-16 ***
## estrato        60.89709    3.08408  19.746  < 2e-16 ***
## parqueaderos   72.91468    3.95797  18.422  < 2e-16 ***
## banios         50.69675    3.39637  14.927  < 2e-16 ***
## habitaciones  -24.83693    3.89229  -6.381 2.11e-10 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 98.02 on 2375 degrees of freedom
##   (409 observations deleted due to missingness)
## Multiple R-squared:  0.7485, Adjusted R-squared:  0.748 
## F-statistic:  1414 on 5 and 2375 DF,  p-value: < 2.2e-16
# Predicción del precio para la segunda solicitud
nueva_vivienda2 <- data.frame(
  areaconst = 300,
  estrato = 5,
  parqueaderos = 3,
  banios = 3,
  habitaciones = 5
)

precio_pred2 <- predict(modelo2, nueva_vivienda2)
print(paste("El precio predicho para la segunda solicitud es:", round(precio_pred2, 2), "millones de pesos"))
## [1] "El precio predicho para la segunda solicitud es: 675.02 millones de pesos"
# Sugerencias de ofertas para la segunda solicitud
ofertas2 <- base2 %>%
  mutate(predicted_price = predict(modelo2, .)) %>%
  filter(predicted_price <= 850,
         areaconst >= 300,
         estrato >= 5,
         parqueaderos >= 3,
         banios >= 3,
         habitaciones >= 5)

# Mostrar las ofertas potenciales
head(ofertas2)
## # A tibble: 1 × 14
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  7512 Zona S… <NA>        5     670       300            3      5            6
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## #   predicted_price <dbl>
map <- leaflet(ofertas2) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~paste("Barrio:", barrio, "<br>",
                   "Precio:", preciom, "millones") # Personaliza el contenido del popup
  )

# Muestra el mapa
map