Caso C&A

Problema

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.

Actualmente las ventas de bienes raíces en Cali se han visto disminuidas de manera significativa en lo corrido del año. Durante este periodo muchas instituciones bancarias de ahorro y vivienda están prestando grandes sumas de dinero para la industria y la construcción comercial y residencial. Cuando el efecto producto de las tensiones políticas y sociales disminuya, se espera que la actividad económica de este sector se reactive.

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:

Caracteristicas 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) .

## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows

Datos

Los datos de los tres últimos meses se adjuntan en la base que puede obtener con el siguiente código en R.
Variable Descripción
zona ubicación de la vivienda: Zona Centro, Zona Norte,…
piso piso que ocupa la vivienda: primer piso, segundo piso…
estrato estrato socio-económico: 3, 4, 5, 6
preciom precio de la vivienda en millones de pesos
areaconst área construida
parqueaderos número de parqueaderos
banios número de baños
habitaciones número de habitaciones
tipo tipo de vivienda: Casa, Apartamento
barrio barrio de ubicación de la vivienda: 20 de Julio, alamos,…
longitud coordenada geográfica
latitud coordenada geográfica

Pasos requeridos para la obtención de los resultados

  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?).

Limpieza de datos

Importamos los datos

#install.packages("devtools") # solo la primera vez
devtools::install_github("dgonxalex80/paqueteMODELOS", force =TRUE)
library(paqueteMODELOS)
data("vivienda")

Se verifica la clase correspondiente a cada una de las variables que contiene el set de datos.

attach(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>
# Detección del número de datos NA por variable
data(vivienda)
apply(X = is.na(vivienda), MARGIN = 2, FUN = sum)
##           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 variables con el mayor número de valores ausentes son Piso (2638) y Parqueaderos (1605). Se realizará un análisis detallado de estas variables para aplicar las medidas adecuadas.

En primer lugar, la variable Piso no aporta información relevante a las solicitudes, ya que no se especificó un número de pisos requerido para las casas ni una ubicación específica en un piso para los apartamentos. Por lo tanto, se procede a eliminarla del conjunto de datos.

vivienda = subset(vivienda, select = -piso)
head(vivienda,5)
## # A tibble: 5 × 12
##      id zona    estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <dbl> <chr>     <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1  1147 Zona O…       3     250        70            1      3            6 Casa 
## 2  1169 Zona O…       3     320       120            1      2            3 Casa 
## 3  1350 Zona O…       3     350       220            2      2            4 Casa 
## 4  5992 Zona S…       4     400       280            3      5            3 Casa 
## 5  1212 Zona N…       5     260        90            1      2            3 Apar…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>

En relación con la variable “parqueaderos”, se examinó la frecuencia de sus datos para determinar la viabilidad de imputar valores a las observaciones faltantes.

summarytools::freq(vivienda$parqueaderos)
## Frequencies  
## vivienda$parqueaderos  
## Type: Numeric  
## 
##               Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ----------- ------ --------- -------------- --------- --------------
##           1   3155    46.970         46.970    37.912         37.912
##           2   2475    36.847         83.817    29.740         67.652
##           3    520     7.742         91.559     6.248         73.901
##           4    384     5.717         97.276     4.614         78.515
##           5     68     1.012         98.288     0.817         79.332
##           6     68     1.012         99.300     0.817         80.149
##           7     18     0.268         99.568     0.216         80.365
##           8     17     0.253         99.821     0.204         80.570
##           9      4     0.060         99.881     0.048         80.618
##          10      8     0.119        100.000     0.096         80.714
##        <NA>   1605                             19.286        100.000
##       Total   8322   100.000        100.000   100.000        100.000

Con el objetivo de optimizar este conjunto de datos para la predicción de modelos, según las solicitudes planteadas, se imputará el valor 0 a las observaciones con valores faltantes en la variable “parqueaderos”.

vivienda$parqueaderos = ifelse(is.na(vivienda$parqueaderos), 0, vivienda$parqueaderos)
summarytools::freq(vivienda$parqueaderos)
## Frequencies  
## vivienda$parqueaderos  
## Type: Numeric  
## 
##               Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## ----------- ------ --------- -------------- --------- --------------
##           0   1605    19.286         19.286    19.286         19.286
##           1   3155    37.912         57.198    37.912         57.198
##           2   2475    29.740         86.938    29.740         86.938
##           3    520     6.248         93.187     6.248         93.187
##           4    384     4.614         97.801     4.614         97.801
##           5     68     0.817         98.618     0.817         98.618
##           6     68     0.817         99.435     0.817         99.435
##           7     18     0.216         99.652     0.216         99.652
##           8     17     0.204         99.856     0.204         99.856
##           9      4     0.048         99.904     0.048         99.904
##          10      8     0.096        100.000     0.096        100.000
##        <NA>      0                              0.000        100.000
##       Total   8322   100.000        100.000   100.000        100.000

Se eliminan los valores nulos restantes ya que son pocos y no limitaran la capacidad de predicción del conjunto de datos.

vivienda = na.omit(vivienda)
apply(X= is.na(vivienda), MARGIN = 2, FUN = sum)
##           id         zona      estrato      preciom    areaconst parqueaderos 
##            0            0            0            0            0            0 
##       banios habitaciones         tipo       barrio     longitud      latitud 
##            0            0            0            0            0            0
dim(vivienda)
## [1] 8319   12

Se introduce una nueva variable categórica para asignar a cada registro, ya sea de casa o apartamento, la base correspondiente en función de la zona en la que se encuentre ubicado.

#attach(vivienda)

vivienda$base <- ifelse(vivienda$zona =="Zona Norte" & vivienda$tipo =="Casa", "Base 1", 
                         ifelse(vivienda$zona =="Zona Centro" & vivienda$tipo =="Casa", "Base 2",
                          ifelse(vivienda$zona =="Zona Oeste" & vivienda$tipo =="Casa", "Base 3",
                           ifelse(vivienda$zona =="Zona Oriente" & vivienda$tipo =="Casa", "Base 4",
                            ifelse(vivienda$zona == "Zona Sur" & vivienda$tipo == "Casa", "Base 5", "NA")))))
head(vivienda,3)
## # A tibble: 3 × 13
##      id zona    estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <dbl> <chr>     <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1  1147 Zona O…       3     250        70            1      3            6 Casa 
## 2  1169 Zona O…       3     320       120            1      2            3 Casa 
## 3  1350 Zona O…       3     350       220            2      2            4 Casa 
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>

Base 1

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

head(base1, 3)
## # A tibble: 3 × 13
##      id zona    estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <dbl> <chr>     <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1  1209 Zona N…       5     320       150            2      4            6 Casa 
## 2  1592 Zona N…       5     780       380            2      3            3 Casa 
## 3  4057 Zona N…       6     750       445            0      7            6 Casa 
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>

mapa

library(leaflet)

# Se filtra el total de viviendas por la categoría Casas
vivienda_casasNorte <- subset(vivienda, tipo == "Casa" & zona == "Zona Norte")

# Se convierte la variable Base en un tipo de carácter
vivienda_casasNorte$base <- as.character(vivienda_casasNorte$base)

# se crea el mapa con las Casas según su latitud y longitud según el color marcado en el paso anterior.
mapaNorte <- leaflet(vivienda_casasNorte) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~longitud, lat = ~latitud, color = "purple", radius = 2)


mapaNorte

Como observamos en el mapa, existen puntos que no están ubicados al norte de la ciudad de Cali. Este podría deberse a posibles errores en la introducción de datos, donde el valor de la variable “zona” se ingresó de manera incorrecta, lo que resulta en ubicaciones distintas. Verifiquemos si este problema se presenta de la misma manera en las demás viviendas en cada una de las zonas.

Si observamos el mapa de todas la zonas se obtiene lo siguiente.

library(leaflet)

vivienda_casas <- subset(vivienda, tipo == "Casa")

vivienda_casas$base <- as.character(vivienda_casas$base)

colores <- colorFactor(palette = c("purple","red","blue","brown","orange"), domain = vivienda_casas$base)

mapa <- leaflet(vivienda_casas) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~colores(base), radius = 4)

mapa

Como se evidencia en el mapa anterior, la base de datos presenta una dificultad, ya que varias viviendas que indican su ubicación en una zona específica, geográficamente se reflejan en otra. Por ejemplo, las casas de la Zona Sur se representan con el color naranja, y en el mapa se observa que muchos registros con este color aparecen en otras zonas de la ciudad.

Ahora se analizaran los indicadores descriptivos de las variables cuantitativas.

library(summarytools)
summarytools::descr(vivienda[,4:8])
## Descriptive Statistics  
## vivienda  
## N: 8319  
## 
##                     areaconst    banios   habitaciones   parqueaderos   preciom
## ----------------- ----------- --------- -------------- -------------- ---------
##              Mean      174.93      3.11           3.61           1.48    433.90
##           Std.Dev      142.96      1.43           1.46           1.24    328.67
##               Min       30.00      0.00           0.00           0.00     58.00
##                Q1       80.00      2.00           3.00           1.00    220.00
##            Median      123.00      3.00           3.00           1.00    330.00
##                Q3      229.00      4.00           4.00           2.00    540.00
##               Max     1745.00     10.00          10.00          10.00   1999.00
##               MAD       84.51      1.48           1.48           1.48    207.56
##               IQR      149.00      2.00           1.00           1.00    320.00
##                CV        0.82      0.46           0.40           0.84      0.76
##          Skewness        2.69      0.93           1.63           1.65      1.85
##       SE.Skewness        0.03      0.03           0.03           0.03      0.03
##          Kurtosis       12.91      1.13           3.98           5.42      3.67
##           N.Valid     8319.00   8319.00        8319.00        8319.00   8319.00
##         Pct.Valid      100.00    100.00         100.00         100.00    100.00
  • Las viviendas en el conjunto de datos tienen áreas construidas que varían ampliamente, desde un mínimo de 30 metros cuadrados hasta un máximo de 1745 metros cuadrados.

  • La distribución de baños, habitaciones y parqueaderos también muestra variabilidad, con algunas viviendas sin baños, habitaciones o parqueaderos, y otras con cantidades significativas.

  • Los precios de las viviendas presentan una gran variación, con una media de 433.90 y un rango que va desde 58 hasta 1999.

  • Las medidas de asimetría y curtosis indican que las distribuciones de área construida y precio no son perfectamente simétricas ni tienen colas normales, mostrando cierta asimetría positiva y colas más pesadas.

library(ggplot2)
ggplot(vivienda, aes(x = areaconst, y = preciom))+ geom_point(color = "green")

El gráfico anterior ilustra la relación entre el precio de la vivienda y el área construida, sugiriendo una correlación positiva. Sin embargo, también se observa un fenómeno notable: mientras algunas viviendas tienen un área reducida y un precio elevado, también se evidencia lo contrario, con viviendas que tienen un precio inferior a 1000 millones pero áreas superiores a 500 \(m²\).

A continuación se analiza la frecuencia de las variables Zona, Estrato Socioeconómico y Número de baños.

summarytools::freq(vivienda$zona, plain.ascii = FALSE, style = "rmarkdown")
## ### Frequencies  
## #### vivienda$zona  
## **Type:** Character  
## 
## |           &nbsp; | Freq | % Valid | % Valid Cum. | % Total | % Total Cum. |
## |-----------------:|-----:|--------:|-------------:|--------:|-------------:|
## |  **Zona Centro** |  124 |    1.49 |         1.49 |    1.49 |         1.49 |
## |   **Zona Norte** | 1920 |   23.08 |        24.57 |   23.08 |        24.57 |
## |   **Zona Oeste** | 1198 |   14.40 |        38.97 |   14.40 |        38.97 |
## | **Zona Oriente** |  351 |    4.22 |        43.19 |    4.22 |        43.19 |
## |     **Zona Sur** | 4726 |   56.81 |       100.00 |   56.81 |       100.00 |
## |       **\<NA\>** |    0 |         |              |    0.00 |       100.00 |
## |        **Total** | 8319 |  100.00 |       100.00 |  100.00 |       100.00 |

Podemosn notar que la mayoría de las viviendas se encuentran en la Zona Sur, representando aproximadamente el 56.81% del total de registros. Por otro lado, la Zona Norte y Zona Oeste también tienen una presencia significativa con el 23.08% y 14.40%, respectivamente. La Zona Centro y Zona Oriente tienen proporciones menores, con 1.49% y 4.22%, respectivamente.

summarytools::freq(vivienda$estrato, plain.ascii = FALSE, style = "rmarkdown")
## ### Frequencies  
## #### vivienda$estrato  
## **Type:** Numeric  
## 
## |     &nbsp; | Freq | % Valid | % Valid Cum. | % Total | % Total Cum. |
## |-----------:|-----:|--------:|-------------:|--------:|-------------:|
## |      **3** | 1453 |   17.47 |        17.47 |   17.47 |        17.47 |
## |      **4** | 2129 |   25.59 |        43.06 |   25.59 |        43.06 |
## |      **5** | 2750 |   33.06 |        76.11 |   33.06 |        76.11 |
## |      **6** | 1987 |   23.89 |       100.00 |   23.89 |       100.00 |
## | **\<NA\>** |    0 |         |              |    0.00 |       100.00 |
## |  **Total** | 8319 |  100.00 |       100.00 |  100.00 |       100.00 |

La distribución indica que la mayoría de las viviendas se encuentran en estratos 5 y 4, representando el 33.06% y el 25.59%, respectivamente. Los estratos 3 y 6 tienen participaciones menores, con el 17.47% y el 23.89%, respectivamente.

summarytools::freq(vivienda$banios,
plain.ascii = FALSE, style = "rmarkdown")
## ### Frequencies  
## #### vivienda$banios  
## **Type:** Numeric  
## 
## |     &nbsp; | Freq | % Valid | % Valid Cum. | % Total | % Total Cum. |
## |-----------:|-----:|--------:|-------------:|--------:|-------------:|
## |      **0** |   45 |    0.54 |         0.54 |    0.54 |         0.54 |
## |      **1** |  496 |    5.96 |         6.50 |    5.96 |         6.50 |
## |      **2** | 2946 |   35.41 |        41.92 |   35.41 |        41.92 |
## |      **3** | 1993 |   23.96 |        65.87 |   23.96 |        65.87 |
## |      **4** | 1456 |   17.50 |        83.38 |   17.50 |        83.38 |
## |      **5** |  890 |   10.70 |        94.07 |   10.70 |        94.07 |
## |      **6** |  314 |    3.77 |        97.85 |    3.77 |        97.85 |
## |      **7** |  107 |    1.29 |        99.13 |    1.29 |        99.13 |
## |      **8** |   48 |    0.58 |        99.71 |    0.58 |        99.71 |
## |      **9** |   15 |    0.18 |        99.89 |    0.18 |        99.89 |
## |     **10** |    9 |    0.11 |       100.00 |    0.11 |       100.00 |
## | **\<NA\>** |    0 |         |              |    0.00 |       100.00 |
## |  **Total** | 8319 |  100.00 |       100.00 |  100.00 |       100.00 |

La mayoría de las viviendas tienen entre 2 y 3 baños, representando el 35.41% y el 23.96% respectivamente. La distribución muestra una disminución en la frecuencia a medida que aumenta el número de baños, siendo viviendas con 10 baños las menos comunes.

  1. Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio de la casa) en función del área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.

Precio de Vivienda

histograma_precio <- plot_ly(vivienda_casas, x = ~preciom, type = "histogram", marker = list(color = "lightgreen")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "Precios"), yaxis = list(title = "Frecuencia"))
histograma_precio

Se evidencia es la presencia de casas con un valor inferior a 900 millones de pesos, lo cual provoca un desplazamiento del histograma hacia la izquierda.

Baños

library(plotly)
histograma_baños <- plot_ly(vivienda_casas, x = ~banios, type = "histogram", marker = list(color = "lightpink")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "baños"), yaxis = list(title = "Frecuencia"))
histograma_baños

Podemos observar que la mayoría de las casas cuentan con 2 o hasta 4 baños. No obstante, el gráfico puede inducir a confusión al presentar valores de 0 baños. Para verificar la veracidad de estos datos, aplicamos la función de filtro. Al seleccionar viviendas con 0 baños, obtenemos una tabla vacía, corroborando así que todas las casas cuentan con al menos 1 baño.

viviendasinbanos <- filter(vivienda_casas, banios == 0)
viviendasinbanos
## # A tibble: 31 × 13
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1   243 Zona …       3     190       435            0      0            0 Casa 
##  2  3273 Zona …       3     400       324            0      0            0 Casa 
##  3  7245 Zona …       4    1200       752            0      0            0 Casa 
##  4  4995 Zona …       3     420       235            0      0            0 Casa 
##  5  1816 Zona …       3     750       183            2      0            0 Casa 
##  6  7509 Zona …       5    1200       660            0      0            0 Casa 
##  7  4393 Zona …       3     380       264            0      0            0 Casa 
##  8  1425 Zona …       5     395       220            1      0            0 Casa 
##  9  3703 Zona …       6     395       140            2      0            3 Casa 
## 10  3347 Zona …       4     950       444            1      0            0 Casa 
## # ℹ 21 more rows
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>

Habitaciones

library(plotly)
histograma_hab <- plot_ly(vivienda_casas, x = ~habitaciones, type = "histogram", marker = list(color = "lightblue")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "habitaciones"), yaxis = list(title = "Frecuencia"))
histograma_hab

Al analizar los datos, se destaca que la mayoría de las casas posee entre 2 y 4 habitaciones. No obstante, el gráfico puede inducir a confusión al presentar valores de 0 habitaciones. Para verificar la veracidad de estos datos, empleamos la función de filtro. Al seleccionar viviendas con 0 habitaciones, obtenemos una tabla con 31 registros sin habitaciones, lo que sugiere que es necesario eliminar estas casas para realizar una correlación adecuada.

viviendasinhabi <- filter(vivienda_casas, habitaciones == 0)
viviendasinhabi
## # A tibble: 45 × 13
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1   243 Zona …       3     190       435            0      0            0 Casa 
##  2  2013 Zona …       3     270       330            0      3            0 Casa 
##  3  2014 Zona …       3     270       330            0      3            0 Casa 
##  4  2741 Zona …       4     485       320            0      4            0 Casa 
##  5  3273 Zona …       3     400       324            0      0            0 Casa 
##  6  4095 Zona …       4     700       550            0      6            0 Casa 
##  7  4118 Zona …       5     620       450            0      3            0 Casa 
##  8  4329 Zona …       4     790       540            0      6            0 Casa 
##  9  4512 Zona …       4     620       300            0      8            0 Casa 
## 10  7245 Zona …       4    1200       752            0      0            0 Casa 
## # ℹ 35 more rows
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>

Zona

histograma_zona <- plot_ly(vivienda_casas, x = ~zona, type = "histogram", marker = list(color = "lightyellow")) %>%
  layout(title = "Histograma de zona", xaxis = list(title = "zona"), yaxis = list(title = "Frecuencia"))
histograma_zona

Lo que se destaca es que la mayoría de las casas, están ubicadas en la zona sur de la ciudad. Sin embargo, dada la incertidumbre generada por las observaciones del punto 1, surge la duda acerca de la veracidad de esta información.

Estrato

histograma_est<- plot_ly(vivienda_casas, x = ~estrato, type = "histogram", marker = list(color = "green")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "estrato"), yaxis = list(title = "Frecuencia"))
histograma_est

Se puede observar que la mayoría de las casas se encuentran en los estratos 3 y 5. No obstante, llama la atención la considerable cantidad de casas también presentes en los estratos 4 y 6.

Area Construida

histograma_area<- plot_ly(vivienda_casas, x = ~areaconst, type = "histogram", marker = list(color = "blue")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "area construida"), yaxis = list(title = "Frecuencia"))
histograma_area
summary(vivienda_casas)
##        id           zona              estrato         preciom    
##  Min.   :   1   Length:3219        Min.   :3.000   Min.   :  77  
##  1st Qu.:1856   Class :character   1st Qu.:3.000   1st Qu.: 300  
##  Median :4190   Mode  :character   Median :5.000   Median : 430  
##  Mean   :3963                      Mean   :4.485   Mean   : 540  
##  3rd Qu.:5862                      3rd Qu.:5.000   3rd Qu.: 670  
##  Max.   :8319                      Max.   :6.000   Max.   :1999  
##    areaconst       parqueaderos        banios        habitaciones  
##  Min.   :  30.0   Min.   : 0.000   Min.   : 0.000   Min.   : 0.00  
##  1st Qu.: 154.0   1st Qu.: 1.000   1st Qu.: 3.000   1st Qu.: 3.00  
##  Median : 240.0   Median : 2.000   Median : 4.000   Median : 4.00  
##  Mean   : 273.4   Mean   : 1.769   Mean   : 3.894   Mean   : 4.61  
##  3rd Qu.: 350.0   3rd Qu.: 2.000   3rd Qu.: 5.000   3rd Qu.: 5.00  
##  Max.   :1745.0   Max.   :10.000   Max.   :10.000   Max.   :10.00  
##      tipo              barrio             longitud         latitud     
##  Length:3219        Length:3219        Min.   :-76.59   Min.   :3.333  
##  Class :character   Class :character   1st Qu.:-76.54   1st Qu.:3.383  
##  Mode  :character   Mode  :character   Median :-76.53   Median :3.413  
##                                        Mean   :-76.53   Mean   :3.415  
##                                        3rd Qu.:-76.52   3rd Qu.:3.449  
##                                        Max.   :-76.46   Max.   :3.496  
##      base          
##  Length:3219       
##  Class :character  
##  Mode  :character  
##                    
##                    
## 
str(vivienda_casas)
## spc_tbl_ [3,219 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id          : num [1:3219] 1147 1169 1350 5992 1209 ...
##  $ zona        : chr [1:3219] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ estrato     : num [1:3219] 3 3 3 4 5 5 6 4 5 4 ...
##  $ preciom     : num [1:3219] 250 320 350 400 320 780 750 625 750 600 ...
##  $ areaconst   : num [1:3219] 70 120 220 280 150 380 445 355 237 160 ...
##  $ parqueaderos: num [1:3219] 1 1 2 3 2 2 0 3 2 1 ...
##  $ banios      : num [1:3219] 3 2 2 5 4 3 7 5 6 4 ...
##  $ habitaciones: num [1:3219] 6 3 4 3 6 3 6 5 6 5 ...
##  $ tipo        : chr [1:3219] "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr [1:3219] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  $ longitud    : num [1:3219] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:3219] 3.43 3.43 3.44 3.44 3.48 ...
##  $ base        : chr [1:3219] "Base 4" "Base 4" "Base 4" "Base 5" ...
##  - 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> 
##  - attr(*, "na.action")= 'omit' Named int [1:3] 8320 8321 8322
##   ..- attr(*, "names")= chr [1:3] "8320" "8321" "8322"

Analisis:

  • Zona: La mayoría de las casas se encuentran ubicadas en la Zona Sur de la ciudad.

  • Estrato: La distribución de las casas se concentra principalmente en los estratos 3 y 4, pero también hay una presencia considerable en los estratos 5 y 6.

  • Precio: Los precios de las casas varían significativamente, con un mínimo de 77 millones de pesos y un máximo de 1999 millones de pesos.

  • Área Construida: La superficie construida de las casas varía desde 30 hasta 1745 metros cuadrados, con una media de aproximadamente 273 metros cuadrados.

  • Parqueaderos, Baños y Habitaciones: En promedio, las casas tienen alrededor de 1.77 parqueaderos, 3.89 baños y 4.61 habitaciones.

library(GGally)
corr = vivienda_casas[, c("preciom", "areaconst", "estrato", "banios", "habitaciones")]
ggpairs(corr, title="GGally")

  1. Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deber están contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).
modelo_multi_vivi = lm(preciom ~ areaconst + estrato + parqueaderos + banios, data = vivienda_casas )
summary(modelo_multi_vivi)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + parqueaderos + banios, 
##     data = vivienda_casas)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1244.11  -114.91   -23.99    70.67  1206.55 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -409.53880   16.41653  -24.95   <2e-16 ***
## areaconst       0.78647    0.02509   31.34   <2e-16 ***
## estrato       122.22857    4.09063   29.88   <2e-16 ***
## parqueaderos   40.90423    2.79476   14.64   <2e-16 ***
## banios         29.25394    2.83243   10.33   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 204.7 on 3214 degrees of freedom
## Multiple R-squared:  0.6737, Adjusted R-squared:  0.6733 
## F-statistic:  1659 on 4 and 3214 DF,  p-value: < 2.2e-16

Los coeficientes estimados para las variables predictoras, que incluyen el área construida, el estrato, la cantidad de parqueaderos y los baños, revelan su impacto significativo en la predicción del precio de la vivienda. El modelo muestra una capacidad considerable para explicar la variabilidad en los precios, como se evidencia en el coeficiente de determinación \(R^2\) de 0.6737. La significancia estadística de los coeficientes, respaldada por bajos valores p en la prueba t, indica que estas variables son pertinentes y aportan de manera sustancial a la predicción.

  1. Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).
par(mfrow = c(2, 2))
plot(modelo_multi_vivi)

Verificación de supuestos sobre el error.

  • Los errores del modelo tienen media cero \(E[ε]=0\)
summary(modelo_multi_vivi$residuals)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## -1244.11  -114.92   -23.99     0.00    70.67  1206.55
t.test(modelo_multi_vivi$residuals, mu=0)
## 
##  One Sample t-test
## 
## data:  modelo_multi_vivi$residuals
## t = -3.8744e-15, df = 3218, p-value = 1
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  -7.071191  7.071191
## sample estimates:
##     mean of x 
## -1.397288e-14

se observa que la mediana y la media son cercanas a cero, lo que respalda la idea de que no hay sesgo sistemático en las predicciones del modelo. Además, el resultado de la prueba t para la media de los residuos confirma estadísticamente que la media de los errores no es significativamente diferente de cero, con un valor p de 1.

  • Los errores tienen varianza constante. \(V[ui]=σ2\)
lmtest::gqtest(modelo_multi_vivi) 
## 
##  Goldfeld-Quandt test
## 
## data:  modelo_multi_vivi
## GQ = 1.2142, df1 = 1605, df2 = 1604, p-value = 5.142e-05
## alternative hypothesis: variance increases from segment 1 to 2

La prueba de Goldfeld-Quandt revela un valor p significativamente bajo (5.142e-05), quiere decir que rechaza la hipótesis nula de homocedasticidad. Por lo tanto, se puede concluir que hay indicios de heterocedasticidad en el modelo de regresión.

  • Los errores del modelo se distribuyen normal \(ε∼N(0,σ2)\)
shapiro.test(modelo_multi_vivi$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo_multi_vivi$residuals
## W = 0.88197, p-value < 2.2e-16

La prueba de Shapiro-Wilk arroja un valor p extremadamente bajo (p-value < 2.2e-16), indicando que hay evidencia significativa en contra de la normalidad de los errores. Por lo tanto, se rechaza la hipótesis nula de que los errores se distribuyen normalmente. Este incumplimiento del supuesto de normalidad podría afectar la validez de algunas inferencias estadísticas basadas en el modelo.

  • Los errores del modelo son independientes \(E[εi,εj]=0\)
lmtest::dwtest(modelo_multi_vivi)
## 
##  Durbin-Watson test
## 
## data:  modelo_multi_vivi
## DW = 1.5032, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0

La prueba de Durbin-Watson (DW) arroja un valor DW de 1.5032 con un p-valor extremadamente bajo (< 2.2e-16). Este resultado indica que hay evidencia significativa en contra de la hipótesis nula de que no hay autocorrelación en los errores. En otras palabras, existe autocorrelación positiva en los residuos del modelo.

  1. Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.
predict(modelo_multi_vivi,list(areaconst=200,parqueaderos=1,estrato=4,habitaciones=4, banios=2))
##        1 
## 336.0823

Según el modelo identificado, la predicción del precio de la vivienda para la primera solicitud, con las características proporcionadas (área construida: 200, parqueaderos: 1, estrato: 4, habitaciones: 4, baños: 2), es de aproximadamente $336.08 millones.

  1. Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 1. Tenga encuentra que la empresa tiene crédito pre-aprobado de máximo 350 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.
Casa  = vivienda_casas %>% 
    dplyr::filter(areaconst >= 200, parqueaderos >= 1, banios >= 2, habitaciones >= 4, zona == "Zona Norte", estrato >= 4, estrato <= 5, preciom <= 350) 

Casa 
## # A tibble: 34 × 13
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1  4210 Zona …       5     350       200            3      3            4 Casa 
##  2  4267 Zona …       5     335       202            1      4            5 Casa 
##  3  4800 Zona …       5     340       250            2      4            4 Casa 
##  4  4209 Zona …       5     350       300            3      5            6 Casa 
##  5  4422 Zona …       5     350       240            2      3            6 Casa 
##  6  4458 Zona …       4     315       270            2      4            4 Casa 
##  7  4483 Zona …       5     342       250            1      4            6 Casa 
##  8  1009 Zona …       5     250       243            1      4            5 Casa 
##  9  1270 Zona …       5     350       203            2      2            5 Casa 
## 10  3352 Zona …       4     335       300            3      4            4 Casa 
## # ℹ 24 more rows
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>
library(leaflet)



mapaCasas <- leaflet(Casa) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~colores(base), radius = 4)

mapaCasas

  1. Realice los pasos del 1 al 6. Para la segunda solicitud que tiene un crédito pre-aprobado por valor de $850 millones.

Base 2

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

head(base2, 3)
## # A tibble: 3 × 13
##      id zona    estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <dbl> <chr>     <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1  5098 Zona S…       4     290        96            1      2            3 Apar…
## 2   698 Zona S…       3      78        40            1      1            2 Apar…
## 3  8199 Zona S…       6     875       194            2      5            3 Apar…
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>

mapa

library(leaflet)

# Se filtra el total de viviendas por la categoría Casas
vivienda_casassur<- subset(vivienda, tipo == "Apartamento" & zona == "Zona Sur")

# Se convierte la variable Base en un tipo de carácter
vivienda_casassur$base <- as.character(vivienda_casassur$base)

# se crea el mapa con las Casas según su latitud y longitud según el color marcado en el paso anterior.
mapasur <- leaflet(vivienda_casassur) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~longitud, lat = ~latitud, color = "orange", radius = 2)


mapasur

Como observamos en el mapa, existen puntos que no están ubicados al sur de la ciudad de Cali. Este podría deberse a posibles errores en la introducción de datos, donde el valor de la variable “zona” se ingresó de manera incorrecta, lo que resulta en ubicaciones distintas. Verifiquemos si este problema se presenta de la misma manera en las demás viviendas en cada una de las zonas.

  1. Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio de la casa) en función del área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.
vivienda_aprt<- subset(vivienda, tipo == "Apartamento")

vivienda_aprt$base <- as.character(vivienda_aprt$base)

Precio de Vivienda

histograma_precio <- plot_ly(vivienda_aprt, x = ~preciom, type = "histogram", marker = list(color = "lightgreen")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "Precios"), yaxis = list(title = "Frecuencia"))
histograma_precio

Se evidencia es la presencia de viviendas con un valor inferior a 700 millones de pesos, lo cual provoca un desplazamiento del histograma hacia la izquierda.

Baños

library(plotly)
histograma_baños <- plot_ly(vivienda_aprt, x = ~banios, type = "histogram", marker = list(color = "lightpink")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "baños"), yaxis = list(title = "Frecuencia"))
histograma_baños

Podemos observar que la mayoría de los apartamentos cuentan con 2 o 3 baños. No obstante, el gráfico puede inducir a confusión al presentar valores de 0 baños. Para verificar la veracidad de estos datos, aplicamos la función de filtro. Al seleccionar viviendas con 0 baños, obtenemos una tabla vacía, corroborando así que todas las casas cuentan con al menos 1 baño.

viviendasinbanos <- filter(vivienda_aprt, banios == 0)
viviendasinbanos
## # A tibble: 14 × 13
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1  6839 Zona …       6     900       250            2      0            0 Apar…
##  2  1898 Zona …       4     220        68            0      0            3 Apar…
##  3  6173 Zona …       5     380       120            2      0            0 Apar…
##  4  3553 Zona …       5     320        92            0      0            3 Apar…
##  5  5908 Zona …       5     950       280           10      0            0 Apar…
##  6  7011 Zona …       4     160        76            0      0            0 Apar…
##  7  7132 Zona …       5     310        80            1      0            1 Apar…
##  8  7884 Zona …       5     380       108            0      0            0 Apar…
##  9  7522 Zona …       3     148        87            0      0            0 Apar…
## 10  6513 Zona …       5     640       167            2      0            3 Apar…
## 11  4526 Zona …       6    1000       520            0      0            5 Apar…
## 12  4915 Zona …       4     160        84            1      0            0 Apar…
## 13  1356 Zona …       3     320       310            0      0            0 Apar…
## 14  8007 Zona …       6     410       129            0      0            0 Apar…
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>

Habitaciones

library(plotly)
histograma_hab <- plot_ly(vivienda_aprt, x = ~habitaciones, type = "histogram", marker = list(color = "lightblue")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "habitaciones"), yaxis = list(title = "Frecuencia"))
histograma_hab

Al analizar los datos, se destaca que la mayoría de las casas posee entre 3 habitaciones. No obstante, el gráfico puede inducir a confusión al presentar valores de 0 habitaciones. Para verificar la veracidad de estos datos, empleamos la función de filtro. Al seleccionar viviendas con 0 habitaciones, obtenemos una tabla con 21 registros sin habitaciones, lo que sugiere que es necesario eliminar estos apartamentos para realizar una correlación adecuada.

viviendasinhabi <- filter(vivienda_aprt, habitaciones == 0)
viviendasinhabi
## # A tibble: 21 × 13
##       id zona   estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <dbl> <chr>    <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1  6839 Zona …       6     900       250            2      0            0 Apar…
##  2  1523 Zona …       5     195        35            0      1            0 Apar…
##  3  3062 Zona …       4     285        90            0      4            0 Apar…
##  4  1524 Zona …       5     330        91            0      3            0 Apar…
##  5  5392 Zona …       4     650       270            0      4            0 Apar…
##  6  3458 Zona …       5     415       118            2      5            0 Apar…
##  7  6173 Zona …       5     380       120            2      0            0 Apar…
##  8  2532 Zona …       4     275        96            2      2            0 Apar…
##  9  3997 Zona …       4     240        73            1      2            0 Apar…
## 10  1594 Zona …       4     152        60            1      2            0 Apar…
## # ℹ 11 more rows
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>

Zona

histograma_zona <- plot_ly(vivienda_aprt, x = ~zona, type = "histogram", marker = list(color = "lightyellow")) %>%
  layout(title = "Histograma de zona", xaxis = list(title = "zona"), yaxis = list(title = "Frecuencia"))
histograma_zona

Lo que se destaca es que la mayoría de apartamentos, están ubicadas en la zona sur de la ciudad.

Estrato

histograma_est<- plot_ly(vivienda_aprt, x = ~estrato, type = "histogram", marker = list(color = "green")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "estrato"), yaxis = list(title = "Frecuencia"))
histograma_est

Se puede observar que la mayoría de los apartamentos se encuentran en los estratos 4 y 5. No obstante, llama la atención la considerable cantidad de viviendas también presentes en estrato 3.

Area Construida

histograma_area<- plot_ly(vivienda_aprt, x = ~areaconst, type = "histogram", marker = list(color = "blue")) %>%
  layout(title = "Histograma de precios", xaxis = list(title = "area construida"), yaxis = list(title = "Frecuencia"))
histograma_area
summary(vivienda_aprt)
##        id           zona              estrato         preciom      
##  Min.   :   3   Length:5100        Min.   :3.000   Min.   :  58.0  
##  1st Qu.:2180   Class :character   1st Qu.:4.000   1st Qu.: 175.0  
##  Median :4158   Mode  :character   Median :5.000   Median : 279.0  
##  Mean   :4284                      Mean   :4.727   Mean   : 366.9  
##  3rd Qu.:6556                      3rd Qu.:6.000   3rd Qu.: 430.0  
##  Max.   :8317                      Max.   :6.000   Max.   :1950.0  
##    areaconst      parqueaderos        banios       habitaciones  
##  Min.   : 35.0   Min.   : 0.000   Min.   :0.000   Min.   :0.000  
##  1st Qu.: 68.0   1st Qu.: 1.000   1st Qu.:2.000   1st Qu.:3.000  
##  Median : 90.0   Median : 1.000   Median :2.000   Median :3.000  
##  Mean   :112.8   Mean   : 1.301   Mean   :2.617   Mean   :2.971  
##  3rd Qu.:130.0   3rd Qu.: 2.000   3rd Qu.:3.000   3rd Qu.:3.000  
##  Max.   :932.0   Max.   :10.000   Max.   :8.000   Max.   :9.000  
##      tipo              barrio             longitud         latitud     
##  Length:5100        Length:5100        Min.   :-76.59   Min.   :3.334  
##  Class :character   Class :character   1st Qu.:-76.54   1st Qu.:3.380  
##  Mode  :character   Mode  :character   Median :-76.53   Median :3.419  
##                                        Mean   :-76.53   Mean   :3.419  
##                                        3rd Qu.:-76.52   3rd Qu.:3.453  
##                                        Max.   :-76.46   Max.   :3.498  
##      base          
##  Length:5100       
##  Class :character  
##  Mode  :character  
##                    
##                    
## 
str(vivienda_aprt)
## spc_tbl_ [5,100 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id          : num [1:5100] 1212 1724 2326 4386 7497 ...
##  $ zona        : chr [1:5100] "Zona Norte" "Zona Norte" "Zona Norte" "Zona Norte" ...
##  $ estrato     : num [1:5100] 5 5 4 5 6 4 5 3 3 6 ...
##  $ preciom     : num [1:5100] 260 240 220 310 520 320 385 100 175 820 ...
##  $ areaconst   : num [1:5100] 90 87 52 137 98 108 103 49 80 377 ...
##  $ parqueaderos: num [1:5100] 1 1 2 2 2 2 2 0 1 1 ...
##  $ banios      : num [1:5100] 2 3 2 3 2 3 2 1 2 4 ...
##  $ habitaciones: num [1:5100] 3 3 3 4 2 3 3 2 3 4 ...
##  $ tipo        : chr [1:5100] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
##  $ barrio      : chr [1:5100] "acopi" "acopi" "acopi" "acopi" ...
##  $ longitud    : num [1:5100] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:5100] 3.46 3.37 3.43 3.38 3.44 ...
##  $ base        : chr [1:5100] "NA" "NA" "NA" "NA" ...
##  - 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> 
##  - attr(*, "na.action")= 'omit' Named int [1:3] 8320 8321 8322
##   ..- attr(*, "names")= chr [1:3] "8320" "8321" "8322"

Analisis:

  • Zona: La mayoría de los apartamentos se encuentran ubicadas en la Zona Sur de la ciudad.

  • Estrato: tiene una media de alrededor de 4.7, indicando una distribución relativamente equitativa entre los estratos.

  • Precio: El precio medio es de aproximadamente 366.9, con un rango significativo que sugiere una variabilidad en los precios de las propiedades-

  • Área Construida: La superficie construida de los apartamentos varía desde 35 hasta 932 metros cuadrados, con una media de aproximadamente 90 metros cuadrados.

  • Parqueaderos, Baños y Habitaciones: tiene un rango de valores entre 0 y 10, con una media de aproximadamente 1.3 parqueaderos por propiedad.La mayoría de las propiedades tienen 1 o 2 parqueaderos, representando alrededor del 84% de las observaciones.

library(GGally)
corr = vivienda_aprt[, c("preciom", "areaconst", "estrato", "banios", "habitaciones")]
ggpairs(corr, title="GGally")

  1. Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deber están contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).
modelo_multi_vivi = lm(preciom ~ areaconst + estrato + parqueaderos + banios, data = vivienda_aprt )
summary(modelo_multi_vivi)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + parqueaderos + banios, 
##     data = vivienda_aprt)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1835.76   -54.33    -3.54    44.03  1059.22 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -318.78294   10.11363  -31.52   <2e-16 ***
## areaconst       2.14115    0.04219   50.75   <2e-16 ***
## estrato        57.57512    2.66194   21.63   <2e-16 ***
## parqueaderos   55.27265    3.00364   18.40   <2e-16 ***
## banios         38.28105    2.85610   13.40   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 136 on 5095 degrees of freedom
## Multiple R-squared:  0.7789, Adjusted R-squared:  0.7787 
## F-statistic:  4487 on 4 and 5095 DF,  p-value: < 2.2e-16

Los coeficientes estimados para las variables predictoras, que incluyen el área construida, el estrato, la cantidad de parqueaderos y los baños, revelan su impacto significativo en la predicción del precio de la vivienda. El modelo muestra una capacidad considerable para explicar la variabilidad en los precios, como se evidencia en el coeficiente de determinación \(R^2\) de 0.7787. La significancia estadística de los coeficientes, respaldada por bajos valores p en la prueba t, indica que estas variables son pertinentes y aportan de manera sustancial a la predicción.

  1. Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).
par(mfrow = c(2, 2))
plot(modelo_multi_vivi)

Verificación de supuestos sobre el error.

  • Los errores del modelo tienen media cero \(E[ε]=0\)
summary(modelo_multi_vivi$residuals)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## -1835.764   -54.329    -3.541     0.000    44.035  1059.222
t.test(modelo_multi_vivi$residuals, mu=0)
## 
##  One Sample t-test
## 
## data:  modelo_multi_vivi$residuals
## t = -4.2011e-16, df = 5099, p-value = 1
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  -3.733197  3.733197
## sample estimates:
##     mean of x 
## -8.000137e-16

Dado que el valor p es 1, no hay suficiente evidencia para rechazar la hipótesis nula de que la media de los residuos es igual a cero. En otras palabras, los residuos parecen seguir una distribución que no difiere significativamente de una distribución normal con media cero.

  • Los errores tienen varianza constante. \(V[ui]=σ2\)
lmtest::gqtest(modelo_multi_vivi) 
## 
##  Goldfeld-Quandt test
## 
## data:  modelo_multi_vivi
## GQ = 1.5605, df1 = 2545, df2 = 2545, p-value < 2.2e-16
## alternative hypothesis: variance increases from segment 1 to 2

La prueba de Goldfeld-Quandt revela un valor p significativamente bajo (2.2e-16), quiere decir que rechaza la hipótesis nula de homocedasticidad. Por lo tanto, se puede concluir que hay indicios de heterocedasticidad en el modelo de regresión.

  • Los errores del modelo se distribuyen normal \(ε∼N(0,σ2)\)
# Seleccionar una muestra aleatoria de tamaño 5000 de los residuos
residuos_muestra <- sample(modelo_multi_vivi$residuals, 5000)

# Realizar el test de Shapiro-Wilk en la muestra aleatoria
shapiro_test_result <- shapiro.test(residuos_muestra)

# Imprimir los resultados del test
print(shapiro_test_result)
## 
##  Shapiro-Wilk normality test
## 
## data:  residuos_muestra
## W = 0.81749, p-value < 2.2e-16

La prueba de Shapiro-Wilk arroja un valor p extremadamente bajo (p-value < 2.2e-16), indicando que hay evidencia significativa en contra de la normalidad de los errores. Por lo tanto, se rechaza la hipótesis nula de que los errores se distribuyen normalmente. Este incumplimiento del supuesto de normalidad podría afectar la validez de algunas inferencias estadísticas basadas en el modelo.

  • Los errores del modelo son independientes \(E[εi,εj]=0\)
lmtest::dwtest(modelo_multi_vivi)
## 
##  Durbin-Watson test
## 
## data:  modelo_multi_vivi
## DW = 1.5818, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0

La prueba de Durbin-Watson (DW) arroja un valor DW de 1.5032 con un p-valor extremadamente bajo (< 2.2e-16). Este resultado indica que hay evidencia significativa en contra de la hipótesis nula de que no hay autocorrelación en los errores. En otras palabras, existe autocorrelación positiva en los residuos del modelo.

  1. Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.
predict(modelo_multi_vivi,list(areaconst=300,parqueaderos=3,estrato=5,habitaciones=5, banios=3))
##     1 
## 892.1

Según el modelo identificado, la predicción del precio de la vivienda para la primera solicitud, con las características proporcionadas (área construida: 300, parqueaderos: 3, estrato: 5, habitaciones: 5, baños: 3), es de aproximadamente $892.1 millones.

  1. Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 1. Tenga encuentra que la empresa tiene crédito pre-aprobado de máximo 350 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.
Aprt  = vivienda_aprt %>% 
    dplyr::filter(areaconst >= 300, parqueaderos >= 3, banios >= 3, habitaciones >= 5, zona == "Zona Sur", estrato >= 5, estrato <= 6, preciom <= 850) 

Aprt 
## # A tibble: 2 × 13
##      id zona    estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <dbl> <chr>     <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1  7182 Zona S…       5     730       573            3      8            5 Apar…
## 2  7512 Zona S…       5     670       300            3      5            6 Apar…
## # ℹ 4 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, base <chr>
library(leaflet)



mapaaprt <- leaflet(Aprt) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~colores(base), radius = 4)

mapaaprt