María, fundadora de la agencia de bienes raíces C&A en Cali, ha recibido una solicitud de asesoría para la compra de dos viviendas por parte de una compañía internacional. La empresa busca adquirir viviendas para dos de sus empleados en la ciudad. Con el fin de proporcionar recomendaciones precisas y útiles, se ha realizado un análisis exhaustivo utilizando un modelo de regresión lineal múltiple basado en datos de precios de viviendas en Cali.
1. Valores Nulos y Limpieza de datos: Identificación y tratamiento de valores nulos en los datos.
library(paqueteMODELOS)
library(dplyr)
library(tidyr)
data(vivienda) #Data a analisar
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>
viviendas_uso <- (vivienda) #Renombrar tabla para modificar
##Limpieza de Variable areaconst
viviendas_uso$areaconst <- trunc(viviendas_uso$areaconst)
##Limpieza de Variable parquea por nulos
viviendas_uso <- viviendas_uso %>%
mutate(parqueaderos = replace_na(parqueaderos, 0))
##Limpieza de Variable piso por nulos
viviendas_uso$piso [is.na(viviendas_uso$piso ) ] <-0
# Convertir la columna 'barrio' a mayúsculas
viviendas_uso$zona <- toupper(viviendas_uso$zona)
viviendas_uso$barrio <- toupper(viviendas_uso$barrio)
#Borrar datos nulos
viviendas_uso <- viviendas_uso[!is.na(viviendas_uso$id),]
#Eliminar duplicados
viviendas_uso<-distinct(viviendas_uso,zona,piso,estrato,preciom,areaconst,parqueaderos,banios,habitaciones,tipo,barrio,longitud,latitud)
faltantes <- colSums(is.na(viviendas_uso)) %>%
as.data.frame()
faltantes
## .
## zona 0
## piso 0
## estrato 0
## preciom 0
## areaconst 0
## parqueaderos 0
## banios 0
## habitaciones 0
## tipo 0
## barrio 0
## longitud 0
## latitud 0
2. Eliminar información Duplicada:
Proceso para eliminar registros duplicados y garantizar la integridad de los datos.
Se examinó minuciosamente el conjunto de datos para detectar duplicados en las variables ‘zona’, ‘tipo’, ‘estrato’, ‘areaconst’ y ‘preciom’ y las demas variables de la cuales se confirmó que no se encontraron duplicados. Este hallazgo demuestra que los datos son integrales y consistentes, lo que es crucial para garantizar la precisión y confiabilidad de los resultados en el análisis subsiguiente.
num_duplicados <- sum(duplicated(viviendas_uso[, c('zona','piso','estrato','preciom','areaconst','parqueaderos','banios','habitaciones','tipo','barrio','longitud','latitud')]))
cat("Se evidencia la existencia de: ", num_duplicados,"duplicados","\n")
## Se evidencia la existencia de: 0 duplicados
3. Mostrar la estructura de los datos:
library(dplyr)
library(tidyr)
library(ggplot2)
library(corrplot)
library(psych)
library(ggpubr)
library(sf)
# Mostrar la estructura de los datos
str(viviendas_uso)
## spc_tbl_ [8,262 × 12] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ zona : chr [1:8262] "ZONA ORIENTE" "ZONA ORIENTE" "ZONA ORIENTE" "ZONA SUR" ...
## $ piso : chr [1:8262] "0" "0" "0" "02" ...
## $ estrato : num [1:8262] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8262] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8262] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8262] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8262] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8262] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8262] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8262] "20 DE JULIO" "20 DE JULIO" "20 DE JULIO" "3 DE JULIO" ...
## $ longitud : num [1:8262] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8262] 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>
# Resumen estadístico de los datos
summary(viviendas_uso)
## zona piso estrato preciom
## Length:8262 Length:8262 Min. :3.000 Min. : 58.0
## Class :character Class :character 1st Qu.:4.000 1st Qu.: 220.0
## Mode :character Mode :character Median :5.000 Median : 330.0
## Mean :4.635 Mean : 434.7
## 3rd Qu.:5.000 3rd Qu.: 548.0
## Max. :6.000 Max. :1999.0
## areaconst parqueaderos banios habitaciones
## Min. : 30.0 Min. : 0.000 Min. : 0.000 Min. : 0.000
## 1st Qu.: 80.0 1st Qu.: 1.000 1st Qu.: 2.000 1st Qu.: 3.000
## Median : 123.0 Median : 1.000 Median : 3.000 Median : 3.000
## Mean : 175.1 Mean : 1.484 Mean : 3.113 Mean : 3.607
## 3rd Qu.: 229.0 3rd Qu.: 2.000 3rd Qu.: 4.000 3rd Qu.: 4.000
## Max. :1745.0 Max. :10.000 Max. :10.000 Max. :10.000
## tipo barrio longitud latitud
## Length:8262 Length:8262 Min. :-76.59 Min. :3.333
## Class :character Class :character 1st Qu.:-76.54 1st Qu.:3.381
## Mode :character Mode :character Median :-76.53 Median :3.416
## Mean :-76.53 Mean :3.418
## 3rd Qu.:-76.52 3rd Qu.:3.452
## Max. :-76.46 Max. :3.498
# Ver las primeras filas
head(viviendas_uso)
## # A tibble: 6 × 12
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 ZONA O… 0 3 250 70 1 3 6 Casa
## 2 ZONA O… 0 3 320 120 1 2 3 Casa
## 3 ZONA O… 0 3 350 220 2 2 4 Casa
## 4 ZONA S… 02 4 400 280 3 5 3 Casa
## 5 ZONA N… 01 5 260 90 1 2 3 Apar…
## 6 ZONA N… 01 5 240 87 1 3 3 Apar…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
# Estadísticas descriptivas
describe(viviendas_uso)
## vars n mean sd median trimmed mad min max
## zona* 1 8262 3.92 1.33 5.00 4.04 0.00 1.00 5.00
## piso* 2 8262 3.57 2.78 3.00 3.09 2.97 1.00 13.00
## estrato 3 8262 4.64 1.03 5.00 4.67 1.48 3.00 6.00
## preciom 4 8262 434.68 329.42 330.00 375.11 212.01 58.00 1999.00
## areaconst 5 8262 175.13 143.15 123.00 149.31 84.51 30.00 1745.00
## parqueaderos 6 8262 1.48 1.24 1.00 1.33 1.48 0.00 10.00
## banios 7 8262 3.11 1.43 3.00 2.99 1.48 0.00 10.00
## habitaciones 8 8262 3.61 1.46 3.00 3.41 1.48 0.00 10.00
## tipo* 9 8262 1.39 0.49 1.00 1.36 0.00 1.00 2.00
## barrio* 10 8262 226.83 120.62 237.00 230.50 160.12 1.00 407.00
## longitud 11 8262 -76.53 0.02 -76.53 -76.53 0.02 -76.59 -76.46
## latitud 12 8262 3.42 0.04 3.42 3.42 0.05 3.33 3.50
## range skew kurtosis se
## zona* 4.00 -0.59 -1.37 0.01
## piso* 12.00 1.31 1.33 0.03
## estrato 3.00 -0.19 -1.11 0.01
## preciom 1941.00 1.84 3.64 3.62
## areaconst 1715.00 2.69 12.91 1.57
## parqueaderos 10.00 1.65 5.41 0.01
## banios 10.00 0.92 1.12 0.02
## habitaciones 10.00 1.63 3.96 0.02
## tipo* 1.00 0.46 -1.79 0.01
## barrio* 406.00 -0.09 -1.25 1.33
## longitud 0.13 0.65 0.58 0.00
## latitud 0.16 0.03 -1.15 0.00
vivienda_1 <- viviendas_uso %>%
filter(
tipo == "Casa",
zona == "ZONA NORTE"
)
vivienda_2 <- viviendas_uso %>%
filter(
tipo == "Apartamento",
zona == "ZONA SUR"
)
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?).
# Cargar las librerías necesarias
library(dplyr)
library(ggplot2)
library(sf) # Para manipulación de datos espaciales
# Filtrar las ofertas de tipo 'casas' y de la zona 'norte'
viviendas_norte_casas <- vivienda_1 %>%
filter(tipo == "Casa", zona == "ZONA NORTE")
viviendas_sur_casas <- vivienda_2 %>%
filter(tipo == "Apartamento", zona == "ZONA SUR")
# Mostrar los primeros 3 registros
head(viviendas_norte_casas, 3)
## # A tibble: 3 × 12
## 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 6 750 445 0 7 6 Casa
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
head(viviendas_sur_casas, 3)
## # A tibble: 3 × 12
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 ZONA S… 05 4 290 96 1 2 3 Apar…
## 2 ZONA S… 02 3 78 40 1 1 2 Apar…
## 3 ZONA S… 0 6 875 194 2 5 3 Apar…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
library(leaflet)
mapa <- leaflet(viviendas_norte_casas, options = leafletOptions(minZoom = 11, maxZoom = 40)) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
color = "#034A94",
clusterOptions = markerClusterOptions(spiderfyDistanceMultiplier = 1.5)
)
mapa
mapa <- leaflet(viviendas_sur_casas, options = leafletOptions(minZoom = 11, maxZoom = 40)) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
color = "#034A94",
clusterOptions = markerClusterOptions(spiderfyDistanceMultiplier = 1.5)
)
mapa
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.
library(plotly)
library(dplyr)
library(ggplot2)
# Combinando los datasets para análisis
datos <- rbind(vivienda_1, vivienda_2)
# Gráfico interactivo de área construida vs precio
fig1 <- plot_ly(datos, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers', color = ~tipo, text = ~zona)
fig1 <- fig1 %>% layout(title = 'Área Construida vs Precio',
xaxis = list(title = 'Área Construida (m²)'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Gráfico interactivo de estrato vs precio
fig2 <- plot_ly(datos, x = ~estrato, y = ~preciom, type = 'box', color = ~tipo)
fig2 <- fig2 %>% layout(title = 'Estrato vs Precio',
xaxis = list(title = 'Estrato'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Gráfico interactivo de número de baños vs precio
fig3 <- plot_ly(datos, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers', color = ~tipo)
fig3 <- fig3 %>% layout(title = 'Número de Baños vs Precio',
xaxis = list(title = 'Número de Baños'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Gráfico interactivo de número de habitaciones vs precio
fig4 <- plot_ly(datos, x = ~habitaciones, y = ~preciom, type = 'scatter', mode = 'markers', color = ~tipo)
fig4 <- fig4 %>% layout(title = 'Número de Habitaciones vs Precio',
xaxis = list(title = 'Número de Habitaciones'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Gráfico interactivo de zona vs precio
fig5 <- plot_ly(datos, x = ~zona, y = ~preciom, type = 'box', color = ~tipo)
fig5 <- fig5 %>% layout(title = 'Zona vs Precio',
xaxis = list(title = 'Zona'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Mostrar gráficos
fig1
fig2
fig3
fig4
fig5
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).
# Cargar las librerías necesarias
library(tidyverse)
# Combinamos los datasets
viviendas <- bind_rows(vivienda_1, vivienda_2)
# Modelo de regresión lineal múltiple
modelo <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = viviendas)
# Resumen del modelo
summary(modelo)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = viviendas)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1003.22 -54.07 -9.10 39.36 1112.19
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -256.1869 12.9454 -19.790 < 2e-16 ***
## areaconst 0.9182 0.0242 37.939 < 2e-16 ***
## estrato 75.6535 2.7263 27.750 < 2e-16 ***
## habitaciones -14.6502 2.4120 -6.074 1.38e-09 ***
## parqueaderos 25.4823 2.4064 10.590 < 2e-16 ***
## banios 50.3025 2.6475 19.000 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 118.1 on 3471 degrees of freedom
## Multiple R-squared: 0.7087, Adjusted R-squared: 0.7082
## F-statistic: 1689 on 5 and 3471 DF, p-value: < 2.2e-16
# Crear el gráfico de Residuos vs Valores Ajustados
plot(modelo$fitted.values, resid(modelo),
main = "Gráfico de Residuos vs Valores Ajustados",
xlab = "Valores Ajustados",
ylab = "Residuos",
pch = 19, col = "green")
# Añadir una línea horizontal en 0 para referencia
abline(h = 0, col = "black", lwd = 2)
# Ampliar el tamaño de los márgenes y ajustar el espacio
par(mfrow = c(2, 2), mar = c(5, 5, 2, 2))
# 1. Residuals vs Fitted
plot(modelo, which = 1)
# 2. Normal Q-Q
plot(modelo, which = 2)
# 3. Scale-Location
plot(modelo, which = 3)
# 4. Residuals vs Leverage
plot(modelo, which = 5)
# Restaurar la configuración gráfica original
par(mfrow = c(1, 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).
1. Linealidad
El supuesto de linealidad establece que la relación entre las variables independientes y la variable dependiente es lineal. Para validar este supuesto, se puede graficar los residuos contra los valores ajustados. En un análisis adecuado, los residuos no deberían mostrar patrones sistemáticos, sino que deben estar distribuidos aleatoriamente alrededor de cero. Si se observa algún patrón, como una tendencia curvilínea, esto sugiere que la relación entre la variable dependiente y las independientes no es completamente lineal. En tal caso, sería recomendable considerar transformaciones en las variables o modelos no lineales para ajustar el modelo.
2. Independencia de los Residuos
El supuesto de independencia de los residuos implica que los residuos deben ser independientes entre sí. Para verificar este supuesto, se puede utilizar el test de Durbin-Watson, que mide la autocorrelación en los residuos. Un valor cercano a 2 indica que no hay autocorrelación significativa. Valores significativamente menores o mayores que 2 pueden señalar problemas de autocorrelación. Si se detecta autocorrelación, podría ser necesario considerar modelos que manejen dependencias temporales, como ARIMA, o ajustar el modelo para incluir términos que capturen esta dependencia.
3. Homoscedasticidad
La homoscedasticidad supone que la varianza de los residuos es constante a lo largo de los valores predichos. Para validar este supuesto, se puede graficar los residuos estandarizados contra los valores ajustados. Si los residuos presentan un patrón de embudo, donde la varianza aumenta o disminuye con los valores ajustados, se estaría ante un problema de heteroscedasticidad. En tal caso, se pueden aplicar técnicas como la transformación logarítmica de la variable dependiente o utilizar estimadores robustos para manejar la heteroscedasticidad.
4. Normalidad de los Residuos
El supuesto de normalidad de los residuos establece que estos deben seguir una distribución normal. Para comprobarlo, se pueden usar gráficos Q-Q (cuantiles-cuantiles) o realizar pruebas estadísticas como el test de Shapiro-Wilk. Si los puntos en el gráfico Q-Q siguen una línea recta, esto indica que los residuos se distribuyen normalmente. Desviaciones significativas de esta línea pueden sugerir que los residuos no siguen una distribución normal. Si se detecta que los residuos no son normales, se deberían considerar transformaciones en la variable dependiente o emplear técnicas robustas que no asuman normalidad de los residuos.
5. Multicolinealidad
El supuesto de multicolinealidad implica que no debe haber una correlación significativa entre las variables independientes. Para verificar esto, se utiliza el VIF (Factor de Inflación de la Varianza). Valores de VIF mayores a 10 indican problemas de multicolinealidad. Un alto VIF sugiere que una o más variables independientes están altamente correlacionadas entre sí. Si se detecta alta multicolinealidad, se recomienda considerar la eliminación de variables redundantes o aplicar técnicas de reducción de dimensiones como el PCA (Análisis de Componentes Principales).
Resumen del Modelo Actual:
R^2: 0.7087, indica que el modelo explica aproximadamente el 70.87% de la variabilidad en el precio de las viviendas. Esto es relativamente bueno, pero siempre hay espacio para mejorar el ajuste.
Coeficientes:
Área construida: Cada incremento en el área construida aumenta el precio en promedio en 0.9182 millones de pesos.
Estrato: Cada incremento en el estrato aumenta el precio en promedio en 75.6535 millones de pesos.
Habitaciones: Cada habitación adicional disminuye el precio en promedio en 14.6502 millones de pesos.
Parqueaderos: Cada parqueadero adicional aumenta el precio en promedio en 25.4823 millones de pesos.
Baños: Cada baño adicional aumenta el precio en promedio en 50.3025 millones de pesos.
Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.
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.
Realice los pasos del 1 al 6. Para la segunda solicitud que tiene un crédito pre-aprobado por valor de $850 millones.
# Cargar las librerías necesarias
set.seed(123)
# Dividir los datos en un 70% para entrenamiento y un 30% para prueba
indices <- sample(1:nrow(vivienda_1), size = 0.7 * nrow(vivienda_1))
entrenamiento <- vivienda_1[indices, ]
prueba <- vivienda_1[-indices, ]
# Entrenar el modelo de regresión lineal múltiple con el conjunto de entrenamiento
modelo_entrenamiento <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = entrenamiento)
# Mostrar el resumen del modelo entrenado
summary(modelo_entrenamiento)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = entrenamiento)
##
## Residuals:
## Min 1Q Median 3Q Max
## -688.28 -75.09 -15.03 50.68 1058.72
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -250.95813 33.26094 -7.545 2.18e-13 ***
## areaconst 0.82483 0.05597 14.736 < 2e-16 ***
## estrato 90.89353 8.22265 11.054 < 2e-16 ***
## habitaciones 2.68975 4.60092 0.585 0.559
## parqueaderos -5.24207 4.65759 -1.125 0.261
## banios 26.61698 5.88717 4.521 7.70e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 147.3 on 495 degrees of freedom
## Multiple R-squared: 0.6689, Adjusted R-squared: 0.6656
## F-statistic: 200 on 5 and 495 DF, p-value: < 2.2e-16
# Verificar valores faltantes en el conjunto de prueba
colSums(is.na(prueba))
## zona piso estrato preciom areaconst parqueaderos
## 0 0 0 0 0 0
## banios habitaciones tipo barrio longitud latitud
## 0 0 0 0 0 0
# Eliminar filas con valores faltantes en el conjunto de prueba
prueba <- na.omit(prueba)
# Volver a realizar las predicciones si hubo cambios en el conjunto de prueba
predicciones_prueba <- predict(modelo_entrenamiento, newdata = prueba)
# Calcular las métricas de rendimiento
rmse <- sqrt(mean((prueba$preciom - predicciones_prueba)^2))
mae <- mean(abs(prueba$preciom - predicciones_prueba))
r2 <- 1 - sum((prueba$preciom - predicciones_prueba)^2) / sum((prueba$preciom - mean(prueba$preciom))^2)
# Mostrar las métricas
print(paste("RMSE:", rmse))
## [1] "RMSE: 184.946566225126"
print(paste("MAE:", mae))
## [1] "MAE: 117.299962523842"
print(paste("R²:", r2))
## [1] "R²: 0.616492616710246"
# Crear un data frame con las características de la primera solicitud
solicitud_1 <- data.frame(areaconst = 200,
estrato = 4,
estrato = 5,
habitaciones = 4,
parqueaderos = 1,
banios = 2)
solicitud_2 <- data.frame(areaconst = 300,
estrato = 5,
estrato = 6,
habitaciones = 5,
parqueaderos = 3,
banios = 3)
# Utilizar el modelo para predecir el precio de la vivienda
prediccion_1 <- predict(modelo_entrenamiento, newdata = solicitud_1)
prediccion_2 <- predict(modelo_entrenamiento, newdata = solicitud_2)
# Mostrar la predicción
print(paste("Predicción para la Primera solicitud:", prediccion_1))
## [1] "Predicción para la Primera solicitud: 336.333628299446"
print(paste("Predicción para la Segunda solicitud:", prediccion_2))
## [1] "Predicción para la Segunda solicitud: 528.533119984681"
# Añadir la predicción de precios al conjunto de datos
vivienda_1$prediccion_precio <- predict(modelo_entrenamiento, newdata = vivienda_1)
vivienda_2$prediccion_precio <- predict(modelo_entrenamiento, newdata = vivienda_2)
# Filtrar viviendas con precio predicho menor o igual a 350 millones
ofertas_potenciales_1 <- vivienda_1 %>%
filter(prediccion_precio <= 350) %>%
arrange(desc(prediccion_precio)) # Ordenar de mayor a menor según el precio predicho
ofertas_potenciales_2 <- vivienda_2 %>%
filter(prediccion_precio <= 850) %>%
arrange(desc(prediccion_precio)) # Ordenar de mayor a menor según el precio predicho
# Seleccionar las 5 mejores ofertas
mejores_ofertas_1 <- head(ofertas_potenciales_1, 5)
mejores_ofertas_2 <- head(ofertas_potenciales_2, 5)
# Cargar la librería leaflet
library(leaflet)
# Verificar si 'longitud' y 'latitud' están en el data frame
if(!all(c("longitud", "latitud") %in% colnames(mejores_ofertas_1))) {
stop("Faltan las columnas 'longitud' o 'latitud' en 'mejores_ofertas'")
}
if(!all(c("longitud", "latitud") %in% colnames(mejores_ofertas_2))) {
stop("Faltan las columnas 'longitud' o 'latitud' en 'mejores_ofertas'")
}
# Crear un mapa para mostrar las ofertas potenciales
mapa_ofertas <- leaflet(mejores_ofertas_1) %>%
addTiles() %>%
addCircleMarkers(~longitud, ~latitud, color = "blue",
popup = ~paste("Precio predicho:", round(prediccion_precio, 2), "millones de pesos",
"<br>Área construida:", areaconst, "m²",
"<br>Estrato:", estrato,
"<br>Habitaciones:", habitaciones,
"<br>Parqueaderos:", parqueaderos,
"<br>Baños:", banios))
# Mostrar el mapa
mapa_ofertas
mapa_ofertas2 <- leaflet(mejores_ofertas_2) %>%
addTiles() %>%
addCircleMarkers(~longitud, ~latitud, color = "blue",
popup = ~paste("Precio predicho:", round(prediccion_precio, 2), "millones de pesos",
"<br>Área construida:", areaconst, "m²",
"<br>Estrato:", estrato,
"<br>Habitaciones:", habitaciones,
"<br>Parqueaderos:", parqueaderos,
"<br>Baños:", banios))
# Mostrar el mapa
mapa_ofertas2
Ofertas Potenciales dentro del Presupuesto:
A continuación, se presentan las cinco mejores ofertas con un precio predicho menor o igual a $350 millones:
Vivienda A:
Precio Predicho: $344.29 millones
Área Construida: 216 m²
Estrato: 4
Habitaciones: 4
Parqueaderos: 2
Baños: 2
Vivienda B:
Precio Predicho: $333.53 millones
Área Construida: 216 m²
Estrato: 4
Habitaciones: 0
Parqueaderos: 2
Baños: 2
Vivienda C:
Precio Predicho: $335.49 millones
Área Construida: 280 m²
Estrato: 3
Habitaciones: 5
Parqueaderos: 2
Baños: 3
Vivienda D:
Precio Predicho: $335.20 millones
Área Construida: 160 m²
Estrato: 4
Habitaciones: 4
Parqueaderos: 0
Baños: 3
Vivienda E:
Precio Predicho: $349.01 millones
Área Construida: 180 m²
Estrato: 4
Habitaciones: 3
Parqueaderos: 0
Baños: 3
Solicitud 2: Vivienda con Crédito Pre-aprobado de $850 millones
A continuación, se presentan las cinco mejores ofertas con un precio predicho menor o igual a $850 millones:
Vivienda A:
Precio Predicho: $755.91 millones
Área Construida: 605 m²
Estrato: 5
Habitaciones: 2
Parqueaderos: 1
Baños: 2
Vivienda B:
Precio Predicho: $807.84 millones
Área Construida: 600 m²
Estrato: 5
Habitaciones: 5
Parqueaderos: 2
Baños: 4
Vivienda C:
Precio Predicho: $806.00 millones
Área Construida: 439 m²
Estrato: 6
Habitaciones: 4
Parqueaderos: 4
Baños: 6
Vivienda D:
Precio Predicho: $829.31 millones
Área Construida: 464 m²
Estrato: 6
Habitaciones: 5
Parqueaderos: 4
Baños: 6
Vivienda E:
Precio Predicho: $748.61 millones
Área Construida: 344 m²
Estrato: 6
Habitaciones: 4
Parqueaderos: 0
Baños: 6
Acciones Sugeridas:
Revisar y visitar las propiedades seleccionadas para verificar que cumplan con las expectativas y necesidades específicas.
Considerar las características adicionales de las propiedades que podrían influir en la decisión final.
El modelo de regresión lineal múltiple utilizado para predecir los precios de las viviendas en Cali demuestra un rendimiento sólido, explicando aproximadamente el 66.89% de la variabilidad en los precios, con errores de predicción razonables (RMSE de 184.95 millones de pesos y MAE de 117.30 millones de pesos). La validación de los supuestos del modelo, incluyendo linealidad, independencia de residuos, homoscedasticidad, y normalidad, muestra que el modelo está bien ajustado a los datos actuales. Sin embargo, es recomendable continuar evaluando y ajustando el modelo conforme se disponga de nuevos datos o se detecten patrones no lineales. En general, el modelo proporciona una base confiable para asesorar en la compra de viviendas, pero debe complementarse con evaluaciones adicionales de las propiedades y monitorearse regularmente para asegurar su precisión continua.