Enunciado

Maria comenzó como agente de bienes raíces en Cali hace 10 años. Después de laborar dos años para una empresa nacional, se traslado a Bogotá y trabajó para otra agencia de bienes raíces. Sus amigos y familiares la convencieron de que con su experiencia y conocimientos del negocio debía abrir su propia agencia. Terminó por adquirir la licencia de intermediario y al poco tiempo fundó su propia compañía, C&A (Casas y Apartamentos) en Cali. Santiago y Lina, dos vendedores de la empresa anterior aceptaron trabajar en la nueva compaña. En la actualidad ocho agentes de bienes raíces colaboran con ella en C&A.

Hace dos días, María recibió una carta solicitando asesoría para la compra de dos viviendas por parte de una compañía internacional que desea ubicar a dos de sus empleados con sus familias en la ciudad. Las solicitudes incluyen las siguientes condiciones:

Características Vivienda 1 Vivienda 2 Tipo Casa Apartamento área construida 200 300 parqueaderos 1 3 baños 2 3 habitaciones 4 5 estrato 4 o 5 5 o 6 zona Norte Sur crédito preaprobado 350 millones 850 millones

Ayude a María a responder la solicitud, mediante técnicas modelación que usted conoce. Ella requiere le envíe un informe ejecutivo donde analice los dos casos y sus recomendaciones (Informe). Como soporte del informe debe anexar las estimaciones, validaciones y comparación de modelos requeridos (Anexos).

Instalación de la Base de datos

{include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(paqueteMETODOS)
## Cargando paquete requerido: dplyr
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## Cargando paquete requerido: ggplot2
## Warning: package 'ggplot2' was built under R version 4.4.2
data(vivienda)
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id          : num [1:8322] 1147 1169 1350 5992 1212 ...
##  $ zona        : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ piso        : chr [1:8322] NA NA NA "02" ...
##  $ estrato     : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
##  $ preciom     : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
##  $ areaconst   : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
##  $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
##  $ banios      : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
##  $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
##  $ tipo        : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  $ longitud    : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
##  - attr(*, "spec")=List of 3
##   ..$ cols   :List of 13
##   .. ..$ id          : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ zona        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ piso        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ estrato     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ preciom     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ areaconst   : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ parqueaderos: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ banios      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ habitaciones: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ tipo        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ barrio      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ longitud    : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ latitud     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   ..$ default: list()
##   .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
##   ..$ delim  : chr ";"
##   ..- attr(*, "class")= chr "col_spec"
##  - attr(*, "problems")=<externalptr>
#Cargamos las librerias correspondientes
#install.packages("leaflet")  
library(leaflet) 
## Warning: package 'leaflet' was built under R version 4.4.3
library(dplyr)
library(ggplot2)
library(plotly)
## 
## Adjuntando el paquete: '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
#Observamos que la base de datos se encuentre correctamente cargada en R
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>

A simple vista evidenciamos algunos datos faltantes, por los que realizaremos una limpieza y preparación de los datos para poder realizar un análisis correctamente.

#Observaremos los tipos de datos de cada una de las variables
glimpse(vivienda)
## Rows: 8,322
## Columns: 13
## $ id           <dbl> 1147, 1169, 1350, 5992, 1212, 1724, 2326, 4386, 1209, 159…
## $ zona         <chr> "Zona Oriente", "Zona Oriente", "Zona Oriente", "Zona Sur…
## $ piso         <chr> NA, NA, NA, "02", "01", "01", "01", "01", "02", "02", "02…
## $ estrato      <dbl> 3, 3, 3, 4, 5, 5, 4, 5, 5, 5, 6, 4, 5, 6, 4, 5, 5, 4, 5, …
## $ preciom      <dbl> 250, 320, 350, 400, 260, 240, 220, 310, 320, 780, 750, 62…
## $ areaconst    <dbl> 70, 120, 220, 280, 90, 87, 52, 137, 150, 380, 445, 355, 2…
## $ parqueaderos <dbl> 1, 1, 2, 3, 1, 1, 2, 2, 2, 2, NA, 3, 2, 2, 1, 4, 2, 2, 2,…
## $ banios       <dbl> 3, 2, 2, 5, 2, 3, 2, 3, 4, 3, 7, 5, 6, 2, 4, 4, 4, 3, 2, …
## $ habitaciones <dbl> 6, 3, 4, 3, 3, 3, 3, 4, 6, 3, 6, 5, 6, 2, 5, 5, 4, 3, 3, …
## $ tipo         <chr> "Casa", "Casa", "Casa", "Casa", "Apartamento", "Apartamen…
## $ barrio       <chr> "20 de julio", "20 de julio", "20 de julio", "3 de julio"…
## $ longitud     <dbl> -76.51168, -76.51237, -76.51537, -76.54000, -76.51350, -7…
## $ latitud      <dbl> 3.43382, 3.43369, 3.43566, 3.43500, 3.45891, 3.36971, 3.4…

Encontramos 3 variables cualitativas, que son: Zona, Tipo y Barrio.

#Varificaremos el numero de valores nulos por columnas
colSums(is.na(vivienda))
##           id         zona         piso      estrato      preciom    areaconst 
##            3            3         2638            3            2            3 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##         1605            3            3            3            3            3 
##      latitud 
##            3

Las dos variables con mayor cantidad de datos faltantes son: piso y parqueaderos,lo cual supone un problema, si corregimos estos datos aplicando la media o mediana de las columnas terminaríamos por crear posibles ofertas que no cumplan con los criterios de los clientes, por lo que en este caso se decide eliminar todas las filas que presenten valores nulos para poder presentar viviendas d ela sque se tenga plena certeza que cumplen con los requerimientos del cliente

#Procederemos a eliminar las columnas que no son necesarias para nuestro análisis
vivienda <- vivienda[, !(names(vivienda) %in% c('id', 'barrio'))]
vivienda <- vivienda[complete.cases(vivienda), ]
colSums(is.na(vivienda))
##         zona         piso      estrato      preciom    areaconst parqueaderos 
##            0            0            0            0            0            0 
##       banios habitaciones         tipo     longitud      latitud 
##            0            0            0            0            0

Podemos evidenciar que ya no existen valores faltantes en la base de datos y que se eliminaron columnas no necesarias para análisis.

VIVIENDA 1

Realice un filtro a la base de datos e incluya solo las ofertas de : base1: casas, de la zona norte de la ciudad. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta. (Adicional un mapa con los puntos de las bases. Discutir si todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).

# Filtrar por tipo, zona, y mostrar 3 primeros registros 
base1 <- vivienda %>%  filter(tipo == "Casa", zona == "Zona Norte")
head(base1,3)
## # A tibble: 3 × 11
##   zona    piso  estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1 Zona N… 02          5     320       150            2      4            6 Casa 
## 2 Zona N… 02          5     780       380            2      3            3 Casa 
## 3 Zona N… 02          4     625       355            3      5            5 Casa 
## # ℹ 2 more variables: longitud <dbl>, latitud <dbl>
#Mapa zona norte
mapa_zonan <- leaflet(base1) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud, lat = ~latitud, 
    radius = 5,  
    color = "blue", fillOpacity = 0.6, stroke = FALSE
  )

mapa_zonan

Con el mapa evidenciamos que no todas las casas corresponden a su ubicación por zona, es decir, las coordenadas de todas las viviendas que aparecen registradas dentro de la zona norte no corresponden a dicha ubicación, esto puede deberse a que la información de latitud y longitud está mal diligenciada, así que realizaremos un mapa que incluya todas las zonas con el objetivo de verificar si el problema es general en todo el DF.

colores <- colorFactor(palette = "Set2", domain = vivienda$zona)
mapa_completo <- leaflet(vivienda) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud, lat = ~latitud, 
    radius = 5, 
    color = ~colores(zona), 
    fillOpacity = 0.6, stroke = FALSE
  ) %>%
  addLegend("bottomright",  
            pal = colores, 
            values = ~zona, 
            title = "Zona",
            opacity = 1)
mapa_completo

Luego de verificar todas las zonas del DF podemos concluir que en efecto, la información de la latitud y longitud se encuentran erradas. La tabla podría corregirse verificando la latitud y longitud correcta de cada una de las zonas de Cali y eliminar las entradas que tengan un error en la digitación.

base1 %>%
  filter(tipo == "Casa" & zona == "Zona Norte") %>%
  group_by(tipo) %>%
  summarize(Cantidad = n())
## # A tibble: 1 × 2
##   tipo  Cantidad
##   <chr>    <int>
## 1 Casa       254

2. ANALISIS EXPLORATORIO ENFOCADO EN LA CORRELACIÓN

# Lo primero que debemos realizar es un matriz de correlación con el objetivo de observar el comportamiento de las variables, pero antes debemos convertir la variable "Estrato en vaiable dummie y que así pase de ser categórica a numérica.

vivienda$estrato <- factor(vivienda$estrato)
estrato_dummies <- model.matrix(~ estrato - 1, data = vivienda)
colnames(estrato_dummies) <- paste("estrato", levels(vivienda$estrato),sep = "_")
base1 <- cbind(vivienda, estrato_dummies)

vivienda_COR <- base1 %>% select(preciom, areaconst, estrato_3, estrato_4, estrato_5, estrato_6, banios, habitaciones, parqueaderos)
correlation_matrix <- cor(vivienda_COR, use = "complete.obs")

plot_ly(vivienda_COR,
                        type = "heatmap",
                        z = correlation_matrix,
                        x = rownames(correlation_matrix),
                        y = colnames(correlation_matrix))

Con el mapa de calor se muestran las corrlaciones entre las variables y el precio del inmueble en millones. El área construida, numero de baños, parqueaderos y estrato 6 son las variables que más presentan correlación.Este comportamiento tiene sentido si tenemos en cuenta que son las vairables explicativas que serán usadas para determinar el precio con el modelo de regresión.Es importante señalar que la variable con mayor correlación es area contruida de las viviendas (0.69), no hay correlación mayor a 0.85 con ninguna variable, pero hay correlación positiva.

library(plotly)

plot_ly(base1, x = ~areaconst, y = ~preciom, type = "scatter", mode = "markers",
        marker = list(color = "blue")) %>%
  layout(title = "Relación entre Área Construida y Precio",
         xaxis = list(title = "Área Construida (m²)"),
         yaxis = list(title = "Precio (millones de pesos)"))

Con el scatter plot podemos graficar la correlación previamente descrita, efectivamente a mayot area construida aumenta el precio del inmueble.

library(ggplot2)

ggplot(base1, aes(x = factor(banios), y = preciom)) + 
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Distribución del Precio por numero de baños",
       x = "Baños",
       y = "Precio (millones de pesos)") +
  theme_minimal()

ggplot(base1, aes(x = factor(parqueaderos), y = preciom)) + 
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Distribución del Precio por número de parqueaderos",
       x = "Numero de Parqueaderos",
       y = "Precio (millones de pesos)") +
  theme_minimal()

library(ggplot2)

ggplot(base1, aes(x = factor(habitaciones), y = preciom)) + 
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Distribución del Precio por numero de habitaciones",
       x = "Numero de habitaciones",
       y = "Precio (millones de pesos)") +
  theme_minimal()

library(ggplot2)

ggplot(vivienda, aes(x = factor(estrato), y = preciom)) + 
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Distribución del Precio por Estrato",
       x = "Estrato",
       y = "Precio (millones de pesos)") +
  theme_minimal()

En general todas las variables explicativas muestran su relación con el precio en millones, todas expresan un aumento en el precio del inmueble acorde al aumento de sus unidades de medida. Los estratos 5 y 6 evidentemente cuentan con inmuebles con mucho mayor precio, las casas con 3 habitaciones son las que más varían en precio, el numéro de baños y parqueaderos a medida que aumentan no presentan outliers, sin embargo, esto puede deberse a que hay pocos registros en las casas con grán número de baños y parqueadero.

3. ESTIMACIÓN DEL MODELO

# Modelo con variables a ajustar
modelo1 <- lm(preciom ~ areaconst  + estrato_3 + estrato_4 + estrato_5 + estrato_6 + habitaciones + parqueaderos + banios, data = base1)
summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato_3 + estrato_4 + estrato_5 + 
##     estrato_6 + habitaciones + parqueaderos + banios, data = base1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -882.72  -73.50   -7.40   47.23 1061.06 
## 
## Coefficients: (1 not defined because of singularities)
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   272.32063    9.95055   27.37   <2e-16 ***
## areaconst       0.86931    0.02585   33.63   <2e-16 ***
## estrato_3    -283.26963   10.76147  -26.32   <2e-16 ***
## estrato_4    -252.12148    7.66032  -32.91   <2e-16 ***
## estrato_5    -205.26892    6.60170  -31.09   <2e-16 ***
## estrato_6            NA         NA      NA       NA    
## habitaciones  -27.77785    2.54196  -10.93   <2e-16 ***
## parqueaderos   66.71102    2.97390   22.43   <2e-16 ***
## banios         55.73302    2.96889   18.77   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 163.2 on 4800 degrees of freedom
## Multiple R-squared:  0.7492, Adjusted R-squared:  0.7488 
## F-statistic:  2048 on 7 and 4800 DF,  p-value: < 2.2e-16

Cada metro cuadrado que aumenta una vivienda el precio aumentará 87 millones, por cada parqueadero disponible el precio subirá 66 millones y por cada baño adicional 55 millones, los estratos presentan una correlación negativa, quiere decir que el preció disminuirá dicha cantitdad de millones dependiendo de su ubicación. Con el valor R cuadrado sabemos que nuestro modelo explica el precio de las casas en la zona norte en un 74%, todas nustras variables explicativas presentan una correlación muy elevada.

4. VALIDACIÓN DE SUPUESTOS

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

La gráfica de los resuduos y los valores ajustados presenta dispersión de los residuos, lo que pod´ria significar heterocedasticidad, en el Q-Q residuals al no alinearse con la diagonal no se observa distribución normal con los residuos. Scale-Location refuerza la idea de la heterocedasticidad al evidenciar una varianza creciente y no constante al aumento de los valores ajustados.

shapiro.test(resid(modelo1))  # Si p < 0.05, los residuos no son normales.
## 
##  Shapiro-Wilk normality test
## 
## data:  resid(modelo1)
## W = 0.85034, p-value < 2.2e-16
library(car)
## Warning: package 'car' was built under R version 4.4.2
## Cargando paquete requerido: carData
## Warning: package 'carData' was built under R version 4.4.2
## 
## Adjuntando el paquete: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
durbinWatsonTest(modelo1)
##  lag Autocorrelation D-W Statistic p-value
##    1       0.1478225      1.703829       0
##  Alternative hypothesis: rho != 0

Con las pruebas de shapiro-wilk y Dubin-Watson confirmamos que los residuos no tienen una distribución normal y que existe autocorrelación entre nuestras variables. Podrías realizar una tranformación logaritmica del precio para luego verificar nuvamente si los supuestos se cumplen.

5. Estimación del precio de la vivienda

# Se debe primero crear un dataframe con la solicitud del cliente para realizar la predicción
vivienda1 <- data.frame(
  areaconst = 200,
  parqueaderos = 1,
  banios = 2,
  habitaciones = 4,
  estrato_3 = 0,
  estrato_4 = 0,
  estrato_5 = 1,
  estrato_6 = 0
)
# Predecir precio según características vivienda 1 en estrato 5
predict(modelo1, newdata = vivienda1)
##        1 
## 307.9787
predict(modelo1, newdata = vivienda1)
##        1 
## 307.9787
vivienda1 <- data.frame(
  areaconst = 200,
  parqueaderos = 1,
  banios = 2,
  habitaciones = 4,
  estrato_3 = 0,
  estrato_4 = 1,
  estrato_5 = 0,
  estrato_6 = 0
)
# Predecir precio según características vivienda 1 en estrato 4
predict(modelo1, newdata = vivienda1)
##        1 
## 261.1261

Nuestro modelo fue capaz de predecir el precio de dos casa, una en ubicada en el estrato 5 con un precio de 307.9787 y otra en estrato 4 con un valor de 261.1261, ambas por debajo del valor del crédito preaprobado.

6. OFERTAS POTENCIALES CASO 1

ofertas_caso1 <- base1 %>%
  filter(
    areaconst >= 180 & areaconst <= 220,  
    estrato_4 == 1 | estrato_5 == 1,           
    parqueaderos >= 1,                      
    banios >= 2,                            
    habitaciones >= 4,                     
    preciom <= 334 ,
    zona == "Zona Norte"
    )
library(leaflet)
paleta_colores <- colorFactor(palette = "Set1", domain = base1$preciom)
mapa_ofertas1 <- leaflet(ofertas_caso1) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud, lat = ~latitud, 
    popup = ~paste( "<br>Zona:", zona,"<br>Precio:", preciom,"<br>Parqueaderos:", parqueaderos,"<br>Baños:", banios,"<br>Habitaciones:", habitaciones),
    radius = 9,  
    color = ~paleta_colores(preciom), 
    fillOpacity = 1, stroke = FALSE
  ) 
## Warning in RColorBrewer::brewer.pal(max(3, n), palette): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(max(3, n), palette): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
mapa_ofertas1

En el gráfico notamos que solo 3 ofertas cumplen con los solicitado por el cliente.

CLIENTE 2

1. Filtrar por tipo, zona, y mostrar 3 primeros registros

base2 <- vivienda %>%  filter(tipo == "Apartamento", zona == "Zona Sur")
head(base1,3)
##         zona piso estrato preciom areaconst parqueaderos banios habitaciones
## 1   Zona Sur   02       4     400       280            3      5            3
## 2 Zona Norte   01       5     260        90            1      2            3
## 3 Zona Norte   01       5     240        87            1      3            3
##          tipo longitud latitud estrato_3 estrato_4 estrato_5 estrato_6
## 1        Casa -76.5400 3.43500         0         1         0         0
## 2 Apartamento -76.5135 3.45891         0         0         1         0
## 3 Apartamento -76.5170 3.36971         0         0         1         0
#Mapa zona sur
mapa_zonas <- leaflet(base2) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud, lat = ~latitud, 
    radius = 5,  
    color = "blue", fillOpacity = 0.6, stroke = FALSE
  )
mapa_zonas
#Mapa completo
colores <- colorFactor(palette = "Set2", domain = vivienda$zona)
mapa_completo <- leaflet(vivienda) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud, lat = ~latitud, 
    radius = 5, 
    color = ~colores(zona), 
    fillOpacity = 0.6, stroke = FALSE
  ) %>%
  addLegend("bottomright",  
            pal = colores, 
            values = ~zona, 
            title = "Zona",
            opacity = 1)
mapa_completo

Se observa el mismo problema que en el caso anterior, los datos de la zona no se encuentran bien entiquetados según la latitud y la longitud.

2. ANALISIS EXPLORATORIO ENFOCADO EN LA CORRELACIÓN

vivienda$estrato <- factor(vivienda$estrato)
estrato_dummies <- model.matrix(~ estrato - 1, data = vivienda)
colnames(estrato_dummies) <- paste("estrato", levels(vivienda$estrato),sep = "_")
base2 <- cbind(vivienda, estrato_dummies)

vivienda_COR <- base2 %>% select(preciom, areaconst, estrato_3, estrato_4, estrato_5, estrato_6, banios, habitaciones, parqueaderos)
correlation_matrix <- cor(vivienda_COR, use = "complete.obs")

plot_ly(vivienda_COR,
                        type = "heatmap",
                        z = correlation_matrix,
                        x = rownames(correlation_matrix),
                        y = colnames(correlation_matrix))
#Area construida y Precio
library(plotly)

plot_ly(base2, x = ~areaconst, y = ~preciom, type = "scatter", mode = "markers",
        marker = list(color = "blue")) %>%
  layout(title = "Relación entre Área Construida y Precio",
         xaxis = list(title = "Área Construida (m²)"),
         yaxis = list(title = "Precio (millones de pesos)"))

Evidenciamos correlación positiva, entre el precio y las variables explicativas y correlación negativa dependiendo del tipo de estrato, este comportamiento puede ser explicado con más detalle en el modelo de regresión. Las riables más correlacionadas son: área construida, número de parqueaderos y número de baños.

boxplot demás variables

ggplot(base2, aes(x = factor(banios), y = preciom)) + 
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Distribución del Precio por numero de baños",
       x = "Baños",
       y = "Precio (millones de pesos)") +
  theme_minimal()

ggplot(base2, aes(x = factor(parqueaderos), y = preciom)) + 
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Distribución del Precio por número de parqueaderos",
       x = "Numero de Parqueaderos",
       y = "Precio (millones de pesos)") +
  theme_minimal()

library(ggplot2)

ggplot(base2, aes(x = factor(habitaciones), y = preciom)) + 
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Distribución del Precio por numero de habitaciones",
       x = "Numero de habitaciones",
       y = "Precio (millones de pesos)") +
  theme_minimal()

library(ggplot2)

ggplot(vivienda, aes(x = factor(estrato), y = preciom)) + 
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Distribución del Precio por Estrato",
       x = "Estrato",
       y = "Precio (millones de pesos)") +
  theme_minimal()

Los estratos más altos presentan mayores orecios en las viviendas, el numero de habitaciones, de baños y de parqueaderos presentan un comportamiento particular, los valores más altos se centra en los valores del 1-3 y van disminuyendo mientras va aumentando el número de unidades de la variable, probablemente a se deba a que existen pocos apartamentos que cuenten con tales resgistros de habitaciones, baños y parqueaderos. 3. ESTIMACIÓN DEL MODELO

# Modelo con variables a ajustar
modelo2 <- lm(preciom ~ areaconst  + estrato_3 + estrato_4 + estrato_5 + estrato_6 + habitaciones + parqueaderos + banios, data = base2)
summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato_3 + estrato_4 + estrato_5 + 
##     estrato_6 + habitaciones + parqueaderos + banios, data = base2)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -882.72  -73.50   -7.40   47.23 1061.06 
## 
## Coefficients: (1 not defined because of singularities)
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   272.32063    9.95055   27.37   <2e-16 ***
## areaconst       0.86931    0.02585   33.63   <2e-16 ***
## estrato_3    -283.26963   10.76147  -26.32   <2e-16 ***
## estrato_4    -252.12148    7.66032  -32.91   <2e-16 ***
## estrato_5    -205.26892    6.60170  -31.09   <2e-16 ***
## estrato_6            NA         NA      NA       NA    
## habitaciones  -27.77785    2.54196  -10.93   <2e-16 ***
## parqueaderos   66.71102    2.97390   22.43   <2e-16 ***
## banios         55.73302    2.96889   18.77   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 163.2 on 4800 degrees of freedom
## Multiple R-squared:  0.7492, Adjusted R-squared:  0.7488 
## F-statistic:  2048 on 7 and 4800 DF,  p-value: < 2.2e-16

Cada metro cuadrado que aumenta una vivienda el precio aumentará 87 millones, por cada parqueadero disponible el precio subirá 66 millones y por cada baño adicional 55 millones, los estratos presentan una correlación negativa, quiere decir que el preció disminuirá dicha cantitdad de millones dependiendo de su ubicación. Con el valor R cuadrado sabemos que nuestro modelo explica el precio de las casas en la zona norte en un 74%, todas nustras variables explicativas presentan una correlación muy elevada.

4. VALIDACIÓN DE SUPUESTOS

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

La gráfica de los resuduos y los valores ajustados presenta dispersión de los residuos, lo que pod´ria significar heterocedasticidad, en el Q-Q residuals al no alinearse con la diagonal no se observa distribución normal con los residuos. Scale-Location refuerza la idea de la heterocedasticidad al evidenciar una varianza creciente y no constante al aumento de los valores ajustados.

shapiro.test(resid(modelo1))  # Si p < 0.05, los residuos no son normales.
## 
##  Shapiro-Wilk normality test
## 
## data:  resid(modelo1)
## W = 0.85034, p-value < 2.2e-16
library(car)
durbinWatsonTest(modelo2)
##  lag Autocorrelation D-W Statistic p-value
##    1       0.1478225      1.703829       0
##  Alternative hypothesis: rho != 0

Con las pruebas de shapiro-wilk y Dubin-Watson confirmamos que los residuos no tienen una distribución normal y que existe autocorrelación (ligera pero presente) entre nuestras variables. Podría realizar una tranformación logaritmica del precio para luego verificar nuevamente si los supuestos se cumplen.

5. Estimación del precio de la vivienda

# Se debe primero crear un dataframe con la solicitud del cliente para realizar la predicción
vivienda2 <- data.frame(
  areaconst = 300,
  parqueaderos = 3,
  banios = 3,
  habitaciones = 5,
  estrato_3 = 0,
  estrato_4 = 0,
  estrato_5 = 1,
  estrato_6 = 0
)
# Predecir precio según características vivienda 2 en estrato 5
predict(modelo2, newdata = vivienda2)
##        1 
## 556.2865
# Se debe primero crear un dataframe con la solicitud del cliente para realizar la predicción
vivienda2 <- data.frame(
  areaconst = 300,
  parqueaderos = 3,
  banios = 3,
  habitaciones = 5,
  estrato_3 = 0,
  estrato_4 = 0,
  estrato_5 = 0,
  estrato_6 = 1
)
# Predecir precio según características vivienda 2 en estrato 6
predict(modelo2, newdata = vivienda2)
##        1 
## 761.5554

En ambos casos nuestro modelo realizó predicciones por debajo del crédito disponible por el cliente.

6. OFERTAS POTENCIALES CASO 2

ofertas_caso2 <- base2 %>%
  filter(
    areaconst >= 280 & areaconst <= 320,  
    estrato_5 == 1 | estrato_6 == 1,           
    parqueaderos >= 3,                      
    banios >= 3,                            
    habitaciones >= 5,                     
    preciom <= 849 ,
    zona == "Zona Sur"
    )
library(leaflet)
paleta_colores <- colorFactor(palette = "Set1", domain = base2$preciom)
mapa_ofertas2 <- leaflet(ofertas_caso2) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud, lat = ~latitud, 
    popup = ~paste( "<br>Zona:", zona,"<br>Precio:", preciom,"<br>Parqueaderos:", parqueaderos,"<br>Baños:", banios,"<br>Habitaciones:", habitaciones),
    radius = 9,  
    color = ~paleta_colores(preciom), 
    fillOpacity = 1, stroke = FALSE
  ) 
## Warning in RColorBrewer::brewer.pal(max(3, n), palette): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(max(3, n), palette): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
mapa_ofertas2