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