Preparación Data


El primer paso para desarrollar este análisis, se llevó a cabo con la carga de las librerías necesarias para realizar este informe.

Posteriormente, se cargaron los datos proporcionados por la inmobiliaria; los cuales constan de zona, cantidad de pisos, estrato y otras características de los inmuebles.

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>


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


Se guarda la base en un datafrme.

vivienda_df = as.data.frame(vivienda)


Filtro la base


base1 = vivienda_df %>%
  filter(tipo == 'Casa' & zona == 'Zona Norte')
base1sna <- na.omit(base1)


Observo las primeras filas de la base1


head(base1sna)
    id       zona piso estrato preciom areaconst parqueaderos banios
1 1209 Zona Norte   02       5     320       150            2      4
2 1592 Zona Norte   02       5     780       380            2      3
4 4460 Zona Norte   02       4     625       355            3      5
5 6081 Zona Norte   02       5     750       237            2      6
6 7824 Zona Norte   02       4     600       160            1      4
7 7987 Zona Norte   02       5     420       200            4      4
  habitaciones tipo barrio  longitud latitud
1            6 Casa  acopi -76.51341 3.47968
2            3 Casa  acopi -76.51674 3.48721
4            5 Casa  acopi -76.53179 3.40590
5            6 Casa  acopi -76.54044 3.36862
6            5 Casa  acopi -76.55210 3.42125
7            5 Casa  acopi -76.55363 3.40050


Creo mapa de la base1


# Crea un mapa
map <- leaflet(base1sna) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~as.character(latitud) # Puedes personalizar el contenido del popup aquí
  )

map # Muestra el mapa


Es evidente que no todas las viviendas están ubicadas en la zona norte, lo cual podría estar relacionado con posibles errores en la digitación de los datos o en el levantamiento de las coordenadas geográficas, como latitudes y longitudes. Debido a esta posible imprecisión en la recolección de la información geográfica, llevar a cabo un análisis que incluya estas variables podría resultar poco confiable o inexacto. Por ello, se recomienda proceder con precaución al considerar estas variables en el estudio, ya que podrían distorsionar los resultados.


Paso 2

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.


Grafico de matriz de correlaciones entre precio, area construida, estrato, baños y habitaiones

correlaciones <- cor(base1sna[,c( 'preciom','areaconst', 'estrato', 'banios', 'habitaciones')], use = "complete.obs")

# Visualización de la matriz 
plot_ly(z = correlaciones, x = colnames(correlaciones), y = colnames(correlaciones), type = "heatmap")
  • El precio, Tiene una correlación alta (cerca de 1) con la área construida (areaconst), lo que indica que a medida que el tamaño del área construida aumenta, el precio también aumenta.

  • El area construida, además de la fuerte correlación positiva con el precio, tiene correlación significativa con el número de baños (probablemente porque casas más grandes suelen tener más baños)

  • El estrato, tiene una correlación positiva con precio y una correlación negativa débil con número de habitaciones. El estrato socioeconómico parece influir más en el valor del inmueble que en su tamaño en términos de habitaciones.

  • Habitaciones y baños, Tienen una correlación baja entre sí, lo que indica que el número de baños no necesariamente está relacionado con el número de habitaciones en la muestra de datos.

Paso 3

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

base1_modelo=lm(preciom ~ areaconst + parqueaderos + banios + habitaciones + estrato, data=base1sna)

summary(base1_modelo)

Call:
lm(formula = preciom ~ areaconst + parqueaderos + banios + habitaciones + 
    estrato, data = base1sna)

Residuals:
    Min      1Q  Median      3Q     Max 
-761.11  -84.10  -16.36   52.22  925.67 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -245.62878   60.86958  -4.035 7.27e-05 ***
areaconst       0.66444    0.06703   9.913  < 2e-16 ***
parqueaderos   28.05949    6.77575   4.141 4.74e-05 ***
banios         11.49860    9.51130   1.209    0.228    
habitaciones    8.91428    7.14129   1.248    0.213    
estrato        85.58184   13.17690   6.495 4.51e-10 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 152.8 on 248 degrees of freedom
Multiple R-squared:  0.5952,    Adjusted R-squared:  0.587 
F-statistic: 72.92 on 5 and 248 DF,  p-value: < 2.2e-16

R-cuadrado (0.5952): El modelo captura el 59.52% de la variabilidad en los precios de los inmuebles. Sin embargo, aún queda un 40.48% sin explicar, lo que sugiere la posible influencia de otras variables no incluidas.

R-cuadrado ajustado (0.587): Considerando el número de predictores, este valor es un poco menor que el R-cuadrado, pero sigue indicando un ajuste aceptable del modelo.

Error estándar residual (152.8): Refleja el promedio de los errores del modelo. Un error estándar más bajo indica un mejor ajuste entre los valores observados y predichos.

Paso 4

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

Validación de supuestos

# Gráfico de residuos base1_model

plot(base1_modelo)



Supuesto Normalidad de los errores

Test Shapiro

shapiro.test(base1_modelo$residuals)

    Shapiro-Wilk normality test

data:  base1_modelo$residuals
W = 0.87822, p-value = 2.263e-13

El valor de \(\alpha\) > 2.263e-13 indica que los residuos no siguen una distribución normal


Supuesto de no autocorrelación de errores

Durbin-Watson test

dwtest(base1_modelo)

    Durbin-Watson test

data:  base1_modelo
DW = 1.9309, p-value = 0.268
alternative hypothesis: true autocorrelation is greater than 0

El valor de DW = 1.9309 sugiere una ligera autocorrelación positiva en los residuos, respaldada por un p-value = 0.268, lo que indica que los errores presentan autocorrelación. Por tanto este supuesto no se cumple.

Supuesto igualdad de varianza

Prueba de Goldfeld-Quandt o Levene

gqtest(base1_modelo)

    Goldfeld-Quandt test

data:  base1_modelo
GQ = 2.3584, df1 = 121, df2 = 121, p-value = 1.742e-06
alternative hypothesis: variance increases from segment 1 to 2

No cumple el suspuesto de varianzas iguales dado que el valor p es de 2.995e-09.

# se define el modelo  ingenuo  y= b0
modelo_b0<- lm(preciom ~ 1, data=base1sna)

#define model with all predictors
modelo_all <- lm(preciom ~ areaconst + parqueaderos + banios + habitaciones + estrato, data=base1sna)

# Se aplica el proceso forward stepwise regression
forward <- step(modelo_b0, direction='forward', scope=formula(modelo_all), trace=0)

# resultado final del modelo
summary(forward)

Call:
lm(formula = preciom ~ areaconst + estrato + parqueaderos + habitaciones, 
    data = base1sna)

Residuals:
    Min      1Q  Median      3Q     Max 
-782.61  -85.28  -17.01   55.92  917.88 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -248.98094   60.86272  -4.091 5.81e-05 ***
areaconst       0.67168    0.06682  10.052  < 2e-16 ***
estrato        89.51640   12.78049   7.004 2.31e-11 ***
parqueaderos   30.32674    6.51708   4.653 5.31e-06 ***
habitaciones   13.54883    6.03068   2.247   0.0255 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 153 on 249 degrees of freedom
Multiple R-squared:  0.5928,    Adjusted R-squared:  0.5862 
F-statistic: 90.62 on 4 and 249 DF,  p-value: < 2.2e-16

Por cada incremento en una unidad del estrato (una medida socioeconómica), el precio del inmueble aumenta en promedio 89.51640 millones de pesos, por cada parqueadero adicional, el precio del inmueble aumenta en promedio 30.32674 millones de pesos, por cada habitación adicional, el precio del inmueble aumenta en promedio 13.54883 millones de pesos y finalmente por cada unidad adicional de área construida, el precio del inmueble aumenta en promedio 0.67168 millones de pesos

Paso 5

Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.

# Datos solicitud 1
solicitud_1 = data.frame(
  estrato = c(4, 5),
  areaconst = 200,
  habitaciones = 4,
  banios = 2,
  parqueaderos = 1
  )

# Dataframe base1_solicitud1
kable(solicitud_1)
estrato areaconst habitaciones banios parqueaderos
4 200 4 2 1
5 200 4 2 1
# Predicción base1_model con datos solicitud1
predict(forward, solicitud_1)
       1        2 
327.9435 417.4599 

Valor estimado esta entre 327 y 417 millones

Paso 6

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.

# Filtrado dyplr ofertas potenciales base1
solicitud_2 = filter(vivienda,
                       preciom <= 350,
                       zona == 'Zona Norte',
                       tipo == 'Casa',
                       estrato %in% c(4,5),
                       areaconst >= 200, 
                       habitaciones >= 4, 
                       banios >= 2, 
                       parqueaderos >= 1
                      )

# Ordenar ofertas base1 por estrato
solicitud_2 = solicitud_2 %>%
  dplyr::arrange(estrato)
                      
kable(solicitud_2[, c(1,2,4,5,6)])
id zona estrato preciom areaconst
4458 Zona Norte 4 315 270.0
3352 Zona Norte 4 335 300.0
937 Zona Norte 4 350 280.0
952 Zona Norte 4 330 275.0
1020 Zona Norte 4 230 250.0
1108 Zona Norte 4 330 260.0
1144 Zona Norte 4 320 200.0
7432 Zona Norte 4 260 280.0
5031 Zona Norte 4 350 350.0
2544 Zona Norte 4 340 264.5
7470 Zona Norte 4 340 264.0
1822 Zona Norte 4 340 295.0
4210 Zona Norte 5 350 200.0
4267 Zona Norte 5 335 202.0
4800 Zona Norte 5 340 250.0
4209 Zona Norte 5 350 300.0
4422 Zona Norte 5 350 240.0
4483 Zona Norte 5 342 250.0
1009 Zona Norte 5 250 243.0
1270 Zona Norte 5 350 203.0
3453 Zona Norte 5 340 240.0
819 Zona Norte 5 350 264.0
1343 Zona Norte 5 320 200.0
3053 Zona Norte 5 320 230.0
766 Zona Norte 5 321 249.0
1163 Zona Norte 5 350 216.0
3043 Zona Norte 5 330 275.0
1849 Zona Norte 5 330 246.0
3101 Zona Norte 5 340 355.0
1151 Zona Norte 5 320 210.0
1887 Zona Norte 5 340 203.0
1842 Zona Norte 5 350 240.0
1914 Zona Norte 5 300 205.0
1943 Zona Norte 5 350 346.0
# Mapa ofertas base 1
map1 = leaflet(data = solicitud_2[c(1,2,4,5,6),]) %>%
  addTiles() %>%
  addMarkers(lng = ~longitud, lat = ~latitud, 
             label = ~paste('Precio = ', solicitud_2$preciom, 'MCOP'), 
             popup = ~paste('Tipo = ', solicitud_2$tipo,
                            ' / Barrio = ', solicitud_2$barrio,
                            ' / Precio = ', solicitud_2$preciom)
  )

map1

#Solicitud 2

Paso 7

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

7.1

# Filtrar base de datos
vivienda2 = vivienda_df %>%
  filter(tipo == 'Apartamento' & zona == 'Zona Sur')

# Estructura base2
str(vivienda2)
'data.frame':   2787 obs. of  13 variables:
 $ id          : num  5098 698 8199 1241 5370 ...
 $ zona        : chr  "Zona Sur" "Zona Sur" "Zona Sur" "Zona Sur" ...
 $ piso        : chr  "05" "02" NA NA ...
 $ estrato     : num  4 3 6 3 3 4 3 3 3 4 ...
 $ preciom     : num  290 78 875 135 135 220 210 105 115 220 ...
 $ areaconst   : num  96 40 194 117 78 75 72 68 58 84 ...
 $ parqueaderos: num  1 1 2 NA NA 1 2 NA 1 NA ...
 $ banios      : num  2 1 5 2 1 2 2 2 2 2 ...
 $ habitaciones: num  3 2 3 3 3 3 3 3 2 3 ...
 $ tipo        : chr  "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
 $ barrio      : chr  "acopi" "aguablanca" "aguacatal" "alameda" ...
 $ longitud    : num  -76.5 -76.5 -76.6 -76.5 -76.5 ...
 $ latitud     : num  3.45 3.4 3.46 3.44 3.44 ...
# Ver primeras filas base 2
kable(head(vivienda2))
id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
5098 Zona Sur 05 4 290 96 1 2 3 Apartamento acopi -76.53464 3.44987
698 Zona Sur 02 3 78 40 1 1 2 Apartamento aguablanca -76.50100 3.40000
8199 Zona Sur NA 6 875 194 2 5 3 Apartamento aguacatal -76.55700 3.45900
1241 Zona Sur NA 3 135 117 NA 2 3 Apartamento alameda -76.51400 3.44100
5370 Zona Sur NA 3 135 78 NA 1 3 Apartamento alameda -76.53600 3.43600
6975 Zona Sur 06 4 220 75 1 2 3 Apartamento alférez real -76.54627 3.39109
# Mapa sin agrupar base 2
map4 = leaflet(data = vivienda2) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~longitud, lat = ~latitud, radius = 0.3)

map4

7.2

correlaciones <- cor(vivienda2[,c( 'preciom','areaconst', 'estrato', 'banios', 'habitaciones')], use = "complete.obs")

# Visualización de la matriz 
plot_ly(z = correlaciones, x = colnames(correlaciones), y = colnames(correlaciones), type = "heatmap")

7.3

base2_modelo=lm(preciom ~ areaconst + parqueaderos + banios + habitaciones + estrato, data=vivienda2)

summary(base2_modelo)

Call:
lm(formula = preciom ~ areaconst + parqueaderos + banios + habitaciones + 
    estrato, data = vivienda2)

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 ***
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 ***
estrato        60.89709    3.08408  19.746  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 98.02 on 2375 degrees of freedom
  (406 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
# R2
base2_modelo2 = summary(base2_modelo)$r.squared

base2_modelo2
[1] 0.7485178

7.4

# Gráfico de residuos base2_model
plot(base2_modelo)

shapiro

# Prueba de normalidad Shapiro-Wilk base2_model
shapiro.test(base2_modelo$residuals)

    Shapiro-Wilk normality test

data:  base2_modelo$residuals
W = 0.79118, p-value < 2.2e-16

Durbin-Watson test

dwtest(base2_modelo)

    Durbin-Watson test

data:  base2_modelo
DW = 1.5333, p-value < 2.2e-16
alternative hypothesis: true autocorrelation is greater than 0
gqtest(base2_modelo)

    Goldfeld-Quandt test

data:  base2_modelo
GQ = 0.9513, df1 = 1185, df2 = 1184, p-value = 0.8048
alternative hypothesis: variance increases from segment 1 to 2

7.5

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

# Dataframe base2_solicitud2
kable(solicitud2)
estrato areaconst habitaciones banios parqueaderos
5 300 5 3 3
6 300 5 3 3
predict(base2_modelo, solicitud2)
       1        2 
675.0247 735.9218