Julián Andrés Pinto Montes \ Juliana Maritza Zárate Jiménez \ Luisa Fernanda Torres Beltrán
Este informe analiza la solicitud de una empresa internacional interesada en adquirir dos viviendas en Cali para sus empleados. Para ello, se emplea un enfoque basado en modelación de datos con técnicas estadísticas y aprendizaje automático en R.
Utilizando datos recientes de oferta inmobiliaria, se desarrollará un análisis exploratorio para comprender la relación entre el precio de la vivienda y sus características clave. Posteriormente, se estimará un modelo de regresión lineal múltiple para predecir el precio de las propiedades que cumplen con los criterios de la solicitud. Finalmente, se identificarán las mejores opciones de compra dentro del presupuesto preaprobado.
El estudio se estructura en siete etapas: filtrado de datos, análisis de correlación, estimación y validación del modelo, predicción de precios, selección de ofertas y recomendaciones finales. Esto permitirá optimizar la toma de decisiones y ofrecer una asesoría basada en evidencia cuantitativa.
Se cargan previamente los datos con los siguientes comandos:
install.packages(“devtools”) # solo la primera vez
devtools::install_github(“centromagis/paqueteMODELOS”, force =TRUE)
Para el desarrollo de la actividad, se implementaron las siguientes librerias:
# Resumen de la estructura de la base de datos
tabla_resumen <- tibble(
Variable = names(vivienda),
Tipo_de_Dato = sapply(vivienda, class)
)
tabla_resumen %>%
gt() %>%
tab_header(
title = md("**Resumen de Variables y Tipos de Datos**"),
subtitle = md("_Estructura de la base de datos 'vivienda'_")
) %>%
cols_label(
Variable = "Variable",
Tipo_de_Dato = "Tipo de Dato"
) %>%
opt_table_outline() %>%
opt_align_table_header(align = "center")
| Resumen de Variables y Tipos de Datos | |
| Estructura de la base de datos ‘vivienda’ | |
| Variable | Tipo de Dato |
|---|---|
| id | numeric |
| zona | character |
| piso | character |
| estrato | numeric |
| preciom | numeric |
| areaconst | numeric |
| parqueaderos | numeric |
| banios | numeric |
| habitaciones | numeric |
| tipo | character |
| barrio | character |
| longitud | numeric |
| latitud | numeric |
# Crear la tabla con los primeros 15 registros
tabla_vivienda <- vivienda %>%
head(15) %>%
gt() %>%
tab_header(title = "Primeros 15 registros del dataset 'vivienda'") %>%
opt_table_outline() %>%
tab_options(
table.font.size = px(14),
heading.title.font.size = px(18),
column_labels.font.weight = "bold"
) %>%
opt_row_striping()
# Mostrar la tabla
tabla_vivienda
| Primeros 15 registros del dataset 'vivienda' | ||||||||||||
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1147 | Zona Oriente | NA | 3 | 250 | 70 | 1 | 3 | 6 | Casa | 20 de julio | -76.51168 | 3.43382 |
| 1169 | Zona Oriente | NA | 3 | 320 | 120 | 1 | 2 | 3 | Casa | 20 de julio | -76.51237 | 3.43369 |
| 1350 | Zona Oriente | NA | 3 | 350 | 220 | 2 | 2 | 4 | Casa | 20 de julio | -76.51537 | 3.43566 |
| 5992 | Zona Sur | 02 | 4 | 400 | 280 | 3 | 5 | 3 | Casa | 3 de julio | -76.54000 | 3.43500 |
| 1212 | Zona Norte | 01 | 5 | 260 | 90 | 1 | 2 | 3 | Apartamento | acopi | -76.51350 | 3.45891 |
| 1724 | Zona Norte | 01 | 5 | 240 | 87 | 1 | 3 | 3 | Apartamento | acopi | -76.51700 | 3.36971 |
| 2326 | Zona Norte | 01 | 4 | 220 | 52 | 2 | 2 | 3 | Apartamento | acopi | -76.51974 | 3.42627 |
| 4386 | Zona Norte | 01 | 5 | 310 | 137 | 2 | 3 | 4 | Apartamento | acopi | -76.53105 | 3.38296 |
| 1209 | Zona Norte | 02 | 5 | 320 | 150 | 2 | 4 | 6 | Casa | acopi | -76.51341 | 3.47968 |
| 1592 | Zona Norte | 02 | 5 | 780 | 380 | 2 | 3 | 3 | Casa | acopi | -76.51674 | 3.48721 |
| 4057 | Zona Norte | 02 | 6 | 750 | 445 | NA | 7 | 6 | Casa | acopi | -76.52950 | 3.38527 |
| 4460 | Zona Norte | 02 | 4 | 625 | 355 | 3 | 5 | 5 | Casa | acopi | -76.53179 | 3.40590 |
| 6081 | Zona Norte | 02 | 5 | 750 | 237 | 2 | 6 | 6 | Casa | acopi | -76.54044 | 3.36862 |
| 7497 | Zona Norte | 02 | 6 | 520 | 98 | 2 | 2 | 2 | Apartamento | acopi | -76.54999 | 3.43505 |
| 7824 | Zona Norte | 02 | 4 | 600 | 160 | 1 | 4 | 5 | Casa | acopi | -76.55210 | 3.42125 |
# Gráfico 1
# Seleccionar las variables preciom y areaconst
vivienda_num1 <- vivienda %>% select(preciom, areaconst)
# Convertir a formato largo
vivienda_long1 <- vivienda_num1 %>%
pivot_longer(cols = everything(), names_to = "Variable", values_to = "Valor")
# Crear el gráfico de bigotes
ggplot(vivienda_long1, aes(x = Variable, y = Valor)) +
geom_boxplot(fill = "#69b3a2", color = "black", outlier.color = "red") +
theme_minimal() +
labs(title = "Distribución de Precio y Área Construida",
x = "Variables",
y = "Valores") +
theme(axis.text.x = element_text(size = 12))
## Warning: Removed 5 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
# Gráfico 2
# Seleccionar las variables banios, habitaciones, estrato, parqueaderos
vivienda_num2 <- vivienda %>% select(banios, habitaciones, estrato, parqueaderos)
# Convertir a formato largo
vivienda_long2 <- vivienda_num2 %>%
pivot_longer(cols = everything(), names_to = "Variable", values_to = "Valor")
# Crear el gráfico de bigotes
ggplot(vivienda_long2, aes(x = Variable, y = Valor)) +
geom_boxplot(fill = "#ffcc66", color = "black", outlier.color = "red") +
theme_minimal() +
labs(title = "Distribución de Baños, Habitaciones, Estrato y Parqueaderos",
x = "Variables",
y = "Valores") +
theme(axis.text.x = element_text(size = 12))
## Warning: Removed 1614 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
# Valores faltates por columna
colSums(is.na(vivienda))
## id zona piso estrato preciom areaconst
## 3 3 2638 3 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 1605 3 3 3 3 3
## latitud
## 3
# Crear el data frame con la cantidad de valores faltantes
missing_data <- colSums(is.na(vivienda)) %>%
as.data.frame() %>%
tibble::rownames_to_column(var = "variable") %>%
rename(missing_values = ".")
# Filtrar solo las variables que tienen valores faltantes
missing_data <- missing_data %>% filter(missing_values > 0)
# Crear el gráfico de barras con etiquetas y estilo mejorado
ggplot(missing_data, aes(x = reorder(variable, missing_values), y = missing_values)) +
geom_bar(stat = "identity", fill = "#69b3a2", color = "black", width = 0.6) +
geom_text(aes(label = missing_values), vjust = -0.5, size = 5, fontface = "bold") +
labs(title = "Cantidad de valores faltantes por variable",
x = "Variable",
y = "Cantidad de valores faltantes") +
theme_minimal(base_size = 14) +
theme(axis.text.x = element_text(angle = 45, hjust = 1, face = "bold"),
axis.text.y = element_text(face = "bold"),
plot.title = element_text(hjust = 0.5, face = "bold", size = 16)) +
coord_flip()
vivienda <- vivienda %>%
mutate(
piso = ifelse(is.na(piso), "01", piso), # Imputar con "01" (carácter)
parqueaderos = ifelse(is.na(parqueaderos), 0, parqueaderos), # Imputar con 0 (numérico)
preciom = ifelse(is.na(preciom), mean(preciom, na.rm = TRUE), preciom), # Imputar con la media
areaconst = ifelse(is.na(areaconst), mean(areaconst, na.rm = TRUE), areaconst) # Imputar con la media
)
# Eliminar registros con valores faltantes en las variables especificadas
vivienda <- vivienda %>%
filter(
!is.na(zona) & !is.na(tipo) & !is.na(latitud) & !is.na(longitud) & !is.na(id) &
!is.na(habitaciones) & !is.na(estrato) & !is.na(barrio) & !is.na(banios)
)
# Verificar que no queden valores faltantes en las variables afectadas
colSums(is.na(vivienda))
## id zona piso estrato preciom areaconst
## 0 0 0 0 0 0
## parqueaderos banios habitaciones tipo barrio longitud
## 0 0 0 0 0 0
## latitud
## 0
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?).
# 1. Filtrar la base de datos para incluir solo Casas en la Zona Norte
base1 <- vivienda %>%
filter(zona == "Zona Norte" & tipo == "Casa")
# 2. Mostrar los primeros 3 registros de base1
head(base1, 3)
## # A tibble: 3 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1209 Zona N… 02 5 320 150 2 4 6
## 2 1592 Zona N… 02 5 780 380 2 3 3
## 3 4057 Zona N… 02 6 750 445 0 7 6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# 3. Tabla resumen para verificar la consulta
table(base1$zona) # Verificar que solo hay "Zona Norte"
##
## Zona Norte
## 722
table(base1$tipo) # Verificar que solo hay "Casa"
##
## Casa
## 722
# 4. Crear un mapa con los puntos de base1
# Mapa con ggplot2
ggplot(base1, aes(x = longitud, y = latitud)) +
geom_point(color = "blue", size = 2) +
labs(title = "Ubicación de las Casas en la Zona Norte",
x = "Longitud", y = "Latitud") +
theme_minimal()
# Mapa interactivo con leaflet
leaflet(base1) %>%
addTiles() %>%
addCircleMarkers(~longitud, ~latitud,
color = "blue",
radius = 4,
label = ~paste("Precio:", preciom, "millones"))
# 5. Análisis de los puntos
# Si algún punto no está realmente en la Zona Norte, revisar si hay errores en los datos
outliers <- base1 %>% filter(latitud < min(vivienda$latitud[vivienda$zona == "Zona Norte"]) |
latitud > max(vivienda$latitud[vivienda$zona == "Zona Norte"]) |
longitud < min(vivienda$longitud[vivienda$zona == "Zona Norte"]) |
longitud > max(vivienda$longitud[vivienda$zona == "Zona Norte"]))
# Mostrar registros sospechosos si existen
if (nrow(outliers) > 0) {
print("Puntos fuera de la Zona Norte:")
print(outliers)
} else {
print("Todos los puntos están correctamente ubicados en la Zona Norte.")
}
## [1] "Todos los puntos están correctamente ubicados en la Zona Norte."
Al revisar la distribución de los puntos sobre el mapa, se evidencia que no todos los puntos se encuentran ubicados sobre la ‘Zona Norte’; por ende, se procede a realizar un ajuste a la distribución de los datos.
# Crear el polígono de la Zona Norte
zona_norte_poligono <- st_polygon(list(matrix(
c(-76.540638, 3.451404,
-76.475783, 3.468090,
-76.493340, 3.505753,
-76.538775, 3.496625,
-76.540638, 3.451404), # Cerrar el polígono
ncol = 2, byrow = TRUE
))) %>%
st_sfc(crs = 4326) # Asignar sistema de coordenadas WGS84
# Convertir base1 a un objeto espacial
base1_sf <- st_as_sf(base1, coords = c("longitud", "latitud"), crs = 4326)
# Filtrar solo los puntos dentro del polígono
base1_reclasificada <- base1_sf[st_within(base1_sf, zona_norte_poligono, sparse = FALSE), ]
# Verificar cuántos registros quedaron
nrow(base1_reclasificada)
## [1] 526
# Extraer coordenadas de base1_reclasificada
base1_reclasificada <- base1_reclasificada %>%
mutate(longitud = st_coordinates(.)[,1],
latitud = st_coordinates(.)[,2])
# Crear el mapa sin el polígono, solo con los puntos filtrados
leaflet(base1_reclasificada) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
color = "red", fillColor = "red", fillOpacity = 0.7,
radius = 4, popup = ~paste("Precio:", preciom, "millones")
) %>%
addLegend("topright", colors = "red", labels = "Casas en Zona Norte", opacity = 1)
Para mejorar el analisis, se redistribuyen todos los puntos por zonas y se crea una nueva base con la información:
# Convertir vivienda en objeto sf con CRS 4326
vivienda_sf <- st_as_sf(vivienda, coords = c("longitud", "latitud"), crs = 4326)
# Definir las zonas como polígonos en un objeto sf
zonas_sf <- st_sf(
ZonaRed = c("Zona Norte", "Zona Centro", "Zona Oriente", "Zona Oeste", "Zona Sur"),
geometry = st_sfc(
st_polygon(list(matrix(c(-76.540638, 3.451404,
-76.475783, 3.468090,
-76.493340, 3.505753,
-76.538775, 3.496625,
-76.540638, 3.451404), ncol = 2, byrow = TRUE))),
st_polygon(list(matrix(c(-76.540638, 3.451404,
-76.475783, 3.468090,
-76.522857, 3.405660,
-76.548480, 3.415723,
-76.540638, 3.451404), ncol = 2, byrow = TRUE))),
st_polygon(list(matrix(c(-76.475783, 3.468090,
-76.522857, 3.405660,
-76.509577, 3.388791,
-76.465090, 3.391528,
-76.475783, 3.468090), ncol = 2, byrow = TRUE))),
st_polygon(list(matrix(c(-76.540638, 3.451404,
-76.548480, 3.415723,
-76.540416, 3.372652,
-76.556823, 3.367932,
-76.593911, 3.470449,
-76.540638, 3.451404), ncol = 2, byrow = TRUE))),
st_polygon(list(matrix(c(-76.522857, 3.405660,
-76.509577, 3.388791,
-76.512123, 3.295108,
-76.564592, 3.305764,
-76.540416, 3.372652,
-76.548480, 3.415723,
-76.522857, 3.405660), ncol = 2, byrow = TRUE)))
),
crs = 4326 # Asegurar que el CRS sea 4326
)
# Unir cada punto de vivienda con su respectiva zona
vivienda_redistribuida <- st_join(vivienda_sf, zonas_sf, join = st_within)
# Convertir a data.frame asegurando que las coordenadas sean accesibles
vivienda_redistribuida <- vivienda_redistribuida %>%
mutate(longitud = st_coordinates(geometry)[,1],
latitud = st_coordinates(geometry)[,2]) %>%
as.data.frame()
# Definir colores para cada zona
colores_zonas <- c("Zona Norte" = "blue", "Zona Centro" = "green",
"Zona Oriente" = "orange", "Zona Oeste" = "purple",
"Zona Sur" = "red")
# Crear el mapa con Leaflet
leaflet(vivienda_redistribuida) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
color = ~colores_zonas[ZonaRed],
fillColor = ~colores_zonas[ZonaRed],
fillOpacity = 0.7,
radius = 3,
popup = ~paste("Zona:", ZonaRed)
) %>%
addLegend("topright",
colors = colores_zonas,
labels = names(colores_zonas),
title = "Zonas de Cali", opacity = 1)
## Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON.
## Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON.
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.
| Características | Caso.1 |
|---|---|
| Tipo | Casa |
| Área construida (m2) | 200 |
| Parqueaderos | 1 |
| Baños | 2 |
| Habitaciones | 4 |
| Estrato | 4 o 5 |
| Zona | Norte |
| Crédito preaprobado | 350 millones |
# Hacer una copia de la base de datos original
vivienda_casas2 <- vivienda_redistribuida
colnames(vivienda_casas2)
## [1] "id" "zona" "piso" "estrato" "preciom"
## [6] "areaconst" "parqueaderos" "banios" "habitaciones" "tipo"
## [11] "barrio" "geometry" "ZonaRed" "longitud" "latitud"
# Filtrar solo casas en la Zona Norte
vivienda_casas2 <- vivienda_casas2 %>%
filter(tipo == "Casa", ZonaRed == "Zona Norte")
str(vivienda_casas2) # Estructura de la base de datos
## 'data.frame': 578 obs. of 15 variables:
## $ id : num 1209 1592 504 604 1003 ...
## $ zona : chr "Zona Norte" "Zona Norte" "Zona Norte" "Zona Norte" ...
## $ piso : chr "02" "02" "01" "01" ...
## $ estrato : num 5 5 3 5 3 5 5 5 5 4 ...
## $ preciom : num 320 780 180 520 380 395 460 390 780 420 ...
## $ areaconst : num 150 380 120 455 300 165 319 357 380 265 ...
## $ parqueaderos: num 2 2 0 0 0 0 0 0 0 0 ...
## $ banios : num 4 3 3 5 5 4 5 3 3 6 ...
## $ habitaciones: num 6 3 3 4 8 4 4 6 3 7 ...
## $ tipo : chr "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr "acopi" "acopi" "acopi" "acopi" ...
## $ geometry :sfc_POINT of length 578; first list element: 'XY' num -76.51 3.48
## $ ZonaRed : chr "Zona Norte" "Zona Norte" "Zona Norte" "Zona Norte" ...
## $ longitud : num -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num 3.48 3.49 3.47 3.46 3.47 ...
## - attr(*, "sf_column")= chr "geometry"
## - attr(*, "agr")= Factor w/ 3 levels "constant","aggregate",..: NA NA NA NA NA NA NA NA NA NA ...
## ..- attr(*, "names")= chr [1:14] "id" "zona" "piso" "estrato" ...
summary(vivienda_casas2) # Resumen estadístico
## id zona piso estrato
## Min. : 83.0 Length:578 Length:578 Min. :3.000
## 1st Qu.: 598.8 Class :character Class :character 1st Qu.:3.000
## Median :1364.0 Mode :character Mode :character Median :4.000
## Mean :2008.9 Mean :4.197
## 3rd Qu.:3221.8 3rd Qu.:5.000
## Max. :5944.0 Max. :6.000
## preciom areaconst parqueaderos banios
## Min. : 100.0 Min. : 30.0 Min. : 0.000 Min. : 0.000
## 1st Qu.: 250.0 1st Qu.: 135.0 1st Qu.: 0.000 1st Qu.: 2.000
## Median : 380.0 Median : 239.5 Median : 1.000 Median : 3.000
## Mean : 437.2 Mean : 261.3 Mean : 1.517 Mean : 3.528
## 3rd Qu.: 550.0 3rd Qu.: 338.5 3rd Qu.: 2.000 3rd Qu.: 4.000
## Max. :1800.0 Max. :1500.0 Max. :10.000 Max. :10.000
## habitaciones tipo barrio geometry
## Min. : 0.000 Length:578 Length:578 POINT :578
## 1st Qu.: 3.000 Class :character Class :character epsg:4326 : 0
## Median : 4.000 Mode :character Mode :character +proj=long...: 0
## Mean : 4.599
## 3rd Qu.: 5.000
## Max. :10.000
## ZonaRed longitud latitud
## Length:578 Min. :-76.54 Min. :3.453
## Class :character 1st Qu.:-76.52 1st Qu.:3.467
## Mode :character Median :-76.52 Median :3.475
## Mean :-76.51 Mean :3.475
## 3rd Qu.:-76.50 3rd Qu.:3.484
## Max. :-76.48 Max. :3.496
glimpse(vivienda_casas2) # Vista rápida del contenido
## Rows: 578
## Columns: 15
## $ id <dbl> 1209, 1592, 504, 604, 1003, 1840, 2730, 2875, 2908, 3182,…
## $ zona <chr> "Zona Norte", "Zona Norte", "Zona Norte", "Zona Norte", "…
## $ piso <chr> "02", "02", "01", "01", "01", "01", "01", "01", "01", "01…
## $ estrato <dbl> 5, 5, 3, 5, 3, 5, 5, 5, 5, 4, 6, 3, 4, 3, 3, 3, 3, 3, 3, …
## $ preciom <dbl> 320, 780, 180, 520, 380, 395, 460, 390, 780, 420, 460, 28…
## $ areaconst <dbl> 150, 380, 120, 455, 300, 165, 319, 357, 380, 265, 350, 14…
## $ parqueaderos <dbl> 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 1, 0, 0, 2, …
## $ banios <dbl> 4, 3, 3, 5, 5, 4, 5, 3, 3, 6, 5, 4, 2, 3, 4, 2, 2, 4, 0, …
## $ habitaciones <dbl> 6, 3, 3, 4, 8, 4, 4, 6, 3, 7, 6, 4, 4, 4, 7, 4, 3, 4, 0, …
## $ tipo <chr> "Casa", "Casa", "Casa", "Casa", "Casa", "Casa", "Casa", "…
## $ barrio <chr> "acopi", "acopi", "acopi", "acopi", "acopi", "acopi", "ac…
## $ geometry <POINT [°]> POINT (-76.51341 3.47968), POINT (-76.51674 3.48721…
## $ ZonaRed <chr> "Zona Norte", "Zona Norte", "Zona Norte", "Zona Norte", "…
## $ longitud <dbl> -76.51341, -76.51674, -76.49768, -76.49966, -76.50743, -7…
## $ latitud <dbl> 3.47968, 3.48721, 3.47060, 3.46284, 3.46566, 3.47651, 3.4…
colSums(is.na(vivienda_casas2)) # Cuenta los NAs por columna
## id zona piso estrato preciom areaconst
## 0 0 0 0 0 0
## parqueaderos banios habitaciones tipo barrio geometry
## 0 0 0 0 0 0
## ZonaRed longitud latitud
## 0 0 0
# Seleccionar columnas de interés
df <- vivienda_casas2 %>%
select(preciom, areaconst, estrato, banios, habitaciones)
# Matriz de correlación
cor_matrix <- cor(df, use = "complete.obs")
print(cor_matrix)
## preciom areaconst estrato banios habitaciones
## preciom 1.0000000 0.7408076 0.6161823 0.5338786 0.3517152
## areaconst 0.7408076 1.0000000 0.4898166 0.5179782 0.4493405
## estrato 0.6161823 0.4898166 1.0000000 0.4540176 0.1262610
## banios 0.5338786 0.5179782 0.4540176 1.0000000 0.6210145
## habitaciones 0.3517152 0.4493405 0.1262610 0.6210145 1.0000000
# Visualizar la matriz de correlación
ggcorrplot(cor_matrix,
method = "square", # Puedes cambiar a "circle"
type = "lower",
lab = TRUE, lab_size = 4,
colors = c("red", "white", "blue"),
title = "Matriz de Correlación - Casas en Zona Norte",
ggtheme = theme_minimal())
El precio por metro cuadrado en la zona norte de Cali está fuertemente relacionado con el área construida y el estrato. Otras variables como el número de baños también influyen, pero en menor medida.
# Precio vs Área Construida
p1 <- ggplot(df, aes(x = areaconst, y = preciom)) +
geom_point(alpha = 0.5, color = 'blue') +
labs(title = "Precio vs Área Construida", x = "Área Construida (m2)", y = "Precio por metro cuadrado")
p1_plotly <- ggplotly(p1)
p1_plotly
El área construida es un buen predictor del precio por metro cuadrado, pero se deben considerar valores atípicos que podrían influir en el modelo de regresión.
# Precio vs Estrato
p2 <- ggplot(df, aes(x = factor(estrato), y = preciom)) +
geom_boxplot(fill = "skyblue") +
labs(title = "Distribución del Precio por Estrato", x = "Estrato", y = "Precio por metro cuadrado")
p2_plotly <- ggplotly(p2)
p2_plotly
# Precio vs Número de Baños
p3 <- ggplot(df, aes(x = banios, y = preciom)) +
geom_jitter(alpha = 0.5, color = 'red') +
labs(title = "Precio vs Número de Baños", x = "Número de Baños", y = "Precio por metro cuadrado")
p3_plotly <- ggplotly(p3)
p3_plotly
# Precio vs Número de Habitaciones
p4 <- ggplot(df, aes(x = habitaciones, y = preciom)) +
geom_jitter(alpha = 0.5, color = 'green') +
labs(title = "Precio vs Número de Habitaciones", x = "Número de Habitaciones", y = "Precio por metro cuadrado")
p4_plotly <- ggplotly(p4)
p4_plotly
El boxplot generado muestra la distribución del precio por metro cuadrado en diferentes estratos socioeconómicos. Se pueden observar las siguientes tendencias:
El gráfico de dispersión muestra la relación entre el precio por metro cuadrado y el número de baños en las propiedades analizadas. Los hallazgos clave son:
Estos resultados sugieren que el número de habitaciones, por sí solo, no es un fuerte predictor del precio por metro cuadrado.
Conclusiones del Análisis Exploratorio
| Características | Caso.2 |
|---|---|
| Tipo | Apartamento |
| Área construida (m2) | 300 |
| Parqueaderos | 3 |
| Baños | 3 |
| Habitaciones | 5 |
| Estrato | 5 o 6 |
| Zona | Sur |
| Crédito preaprobado | 850 millones |
# Hacer una copia de la base de datos original
vivienda_apartamentos<- vivienda_redistribuida
colnames(vivienda_apartamentos)
## [1] "id" "zona" "piso" "estrato" "preciom"
## [6] "areaconst" "parqueaderos" "banios" "habitaciones" "tipo"
## [11] "barrio" "geometry" "ZonaRed" "longitud" "latitud"
# Filtrar solo casas en la Zona Norte
vivienda_apartamentos <- vivienda_apartamentos %>%
filter(tipo == "Apartamento", ZonaRed == "Zona Sur")
str(vivienda_apartamentos) # Estructura de la base de datos
## 'data.frame': 1965 obs. of 15 variables:
## $ id : num 1724 4386 5424 6043 6412 ...
## $ zona : chr "Zona Norte" "Zona Norte" "Zona Norte" "Zona Norte" ...
## $ piso : chr "01" "01" "03" "05" ...
## $ estrato : num 5 5 4 5 6 5 4 4 5 5 ...
## $ preciom : num 240 310 320 420 620 170 220 162 225 250 ...
## $ areaconst : num 87 137 108 124 135 56 75 60 65 75 ...
## $ parqueaderos: num 1 2 2 3 2 1 0 0 0 0 ...
## $ banios : num 3 3 3 3 3 1 2 2 2 2 ...
## $ habitaciones: num 3 4 3 3 4 2 3 3 3 3 ...
## $ tipo : chr "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
## $ barrio : chr "acopi" "acopi" "acopi" "acopi" ...
## $ geometry :sfc_POINT of length 1965; first list element: 'XY' num -76.52 3.37
## $ ZonaRed : chr "Zona Sur" "Zona Sur" "Zona Sur" "Zona Sur" ...
## $ longitud : num -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num 3.37 3.38 3.41 3.41 3.34 ...
## - attr(*, "sf_column")= chr "geometry"
## - attr(*, "agr")= Factor w/ 3 levels "constant","aggregate",..: NA NA NA NA NA NA NA NA NA NA ...
## ..- attr(*, "names")= chr [1:14] "id" "zona" "piso" "estrato" ...
summary(vivienda_apartamentos) # Resumen estadístico
## id zona piso estrato
## Min. :1250 Length:1965 Length:1965 Min. :3.000
## 1st Qu.:2175 Class :character Class :character 1st Qu.:4.000
## Median :3543 Mode :character Mode :character Median :5.000
## Mean :3720 Mean :4.779
## 3rd Qu.:5240 3rd Qu.:5.000
## Max. :7346 Max. :6.000
## preciom areaconst parqueaderos banios
## Min. : 70.0 Min. : 40.00 Min. : 0.000 Min. :0.000
## 1st Qu.: 190.0 1st Qu.: 68.00 1st Qu.: 1.000 1st Qu.:2.000
## Median : 260.0 Median : 86.00 Median : 1.000 Median :2.000
## Mean : 318.5 Mean : 98.94 Mean : 1.226 Mean :2.554
## 3rd Qu.: 350.0 3rd Qu.:110.00 3rd Qu.: 2.000 3rd Qu.:3.000
## Max. :1750.0 Max. :605.00 Max. :10.000 Max. :7.000
## habitaciones tipo barrio geometry
## Min. :0.000 Length:1965 Length:1965 POINT :1965
## 1st Qu.:3.000 Class :character Class :character epsg:4326 : 0
## Median :3.000 Mode :character Mode :character +proj=long...: 0
## Mean :2.951
## 3rd Qu.:3.000
## Max. :6.000
## ZonaRed longitud latitud
## Length:1965 Min. :-76.55 Min. :3.334
## Class :character 1st Qu.:-76.54 1st Qu.:3.366
## Mode :character Median :-76.53 Median :3.372
## Mean :-76.53 Mean :3.375
## 3rd Qu.:-76.52 3rd Qu.:3.385
## Max. :-76.51 Max. :3.415
glimpse(vivienda_apartamentos) # Vista rápida del contenido
## Rows: 1,965
## Columns: 15
## $ id <dbl> 1724, 4386, 5424, 6043, 6412, 1770, 1353, 1391, 1489, 149…
## $ zona <chr> "Zona Norte", "Zona Norte", "Zona Norte", "Zona Norte", "…
## $ piso <chr> "01", "01", "03", "05", "05", "06", "01", "01", "01", "01…
## $ estrato <dbl> 5, 5, 4, 5, 6, 5, 4, 4, 5, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, …
## $ preciom <dbl> 240, 310, 320, 420, 620, 170, 220, 162, 225, 250, 325, 22…
## $ areaconst <dbl> 87, 137, 108, 124, 135, 56, 75, 60, 65, 75, 107, 84, 90, …
## $ parqueaderos <dbl> 1, 2, 2, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ banios <dbl> 3, 3, 3, 3, 3, 1, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, …
## $ habitaciones <dbl> 3, 4, 3, 3, 4, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, …
## $ tipo <chr> "Apartamento", "Apartamento", "Apartamento", "Apartamento…
## $ barrio <chr> "acopi", "acopi", "acopi", "acopi", "acopi", "acopi", "ac…
## $ geometry <POINT [°]> POINT (-76.517 3.36971), POINT (-76.53105 3.38296),…
## $ ZonaRed <chr> "Zona Sur", "Zona Sur", "Zona Sur", "Zona Sur", "Zona Sur…
## $ longitud <dbl> -76.51700, -76.53105, -76.53638, -76.54015, -76.54252, -7…
## $ latitud <dbl> 3.36971, 3.38296, 3.40770, 3.40970, 3.34299, 3.37251, 3.3…
colSums(is.na(vivienda_apartamentos)) # Cuenta los NAs por columna
## id zona piso estrato preciom areaconst
## 0 0 0 0 0 0
## parqueaderos banios habitaciones tipo barrio geometry
## 0 0 0 0 0 0
## ZonaRed longitud latitud
## 0 0 0
# Seleccionar columnas de interés
df2 <- vivienda_apartamentos %>%
select(preciom, areaconst, estrato, banios, habitaciones)
# Matriz de correlación
cor_matrix2 <- cor(df2, use = "complete.obs")
print(cor_matrix2)
## preciom areaconst estrato banios habitaciones
## preciom 1.0000000 0.8200215 0.6720870 0.7394536 0.3384449
## areaconst 0.8200215 1.0000000 0.5475383 0.6948584 0.4076364
## estrato 0.6720870 0.5475383 1.0000000 0.5969642 0.2403555
## banios 0.7394536 0.6948584 0.5969642 1.0000000 0.4894832
## habitaciones 0.3384449 0.4076364 0.2403555 0.4894832 1.0000000
# Visualizar la matriz de correlación-----
ggcorrplot(cor_matrix2,
method = "circle", # Puedes cambiar a "circle"
type = "lower",
lab = TRUE, lab_size = 4,
colors = c("red", "white", "blue"),
title = "Matriz de Correlación - Apartamentos zona Sur",
ggtheme = theme_minimal())
# Precio vs Área Construida
p12 <- ggplot(df, aes(x = areaconst, y = preciom)) +
geom_point(alpha = 0.5, color = 'blue') +
labs(title = "Precio vs Área Construida zona sur ", x = "Área Construida (m2)", y = "Precio por metro cuadrado")
p12_plotly <- ggplotly(p12)
p12_plotly
# Precio vs Estrato
p22 <- ggplot(df, aes(x = factor(estrato), y = preciom)) +
geom_boxplot(fill = "skyblue") +
labs(title = "Distribución del Precio por Estrato zona Sur", x = "Estrato", y = "Precio por metro cuadrado")
p22_plotly <- ggplotly(p22)
p22_plotly
# Precio vs Número de Baños
p32 <- ggplot(df, aes(x = banios, y = preciom)) +
geom_jitter(alpha = 0.5, color = 'red') +
labs(title = "Precio vs Número de Baños Zona Sur", x = "Número de Baños", y = "Precio por metro cuadrado")
p32_plotly <- ggplotly(p32)
p32_plotly
# Precio vs Número de Habitaciones
p42 <- ggplot(df, aes(x = habitaciones, y = preciom)) +
geom_jitter(alpha = 0.5, color = 'green') +
labs(title = "Precio vs Número de Habitaciones Zona Sur", x = "Número de Habitaciones", y = "Precio por metro cuadrado")
p42_plotly <- ggplotly(p42)
p42_plotly
Estime un modelo de regresión lineal múltiple con las variables del punto anterior:
\[ \text{precio} = f(\text{área construida}, \text{estrato}, \text{número de cuartos}, \text{número de parqueaderos}, \text{número de baños}) \]
e interprete los coeficientes si son estadísticamente significativos.
Las interpretaciones deben estar contextualizadas y se debe discutir si los resultados son lógicos.
Adicionalmente, interprete el coeficiente \(R^2\) y discuta el ajuste del modelo e implicaciones (qué podrían hacer para mejorarlo).
# Filtrar por Zona Norte y tipo Casa
vivienda_norte_casas <- vivienda_redistribuida %>%
filter(ZonaRed == "Zona Norte", tipo == "Casa")
# 1. Verificar valores NA en las variables de interés
colSums(is.na(vivienda_norte_casas[, c("preciom", "areaconst", "estrato", "habitaciones", "parqueaderos", "banios")]))
## preciom areaconst estrato habitaciones parqueaderos banios
## 0 0 0 0 0 0
#2.estimar modelo con las variables: área construida, estrato, número de parqueaderos, número de baños.
modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios,
data = vivienda_norte_casas)
summary(modelo1)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = vivienda_norte_casas)
##
## Residuals:
## Min 1Q Median 3Q Max
## -917.89 -73.86 -15.42 35.12 1129.07
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -170.32280 36.33205 -4.688 3.45e-06 ***
## areaconst 0.80380 0.04969 16.176 < 2e-16 ***
## estrato 72.46792 8.93096 8.114 3.00e-15 ***
## habitaciones -1.31170 5.16698 -0.254 0.79969
## parqueaderos 22.49742 4.86174 4.627 4.58e-06 ***
## banios 18.49152 6.80958 2.716 0.00682 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 161.1 on 572 degrees of freedom
## Multiple R-squared: 0.6563, Adjusted R-squared: 0.6533
## F-statistic: 218.5 on 5 and 572 DF, p-value: < 2.2e-16
MODELO 1
\[ \text{Precio} = -170.32 + 0.80 \times \text{areaconst} + 72.47 \times \text{estrato} + 22.49 \times \text{parqueaderos} + 18.49 \times \text{banios} + \varepsilon \]
Los coeficientes indican cómo cada variable influye en el precio de la vivienda. El intercepto no tiene sentido práctico, el área construida y el estrato tienen un impacto positivo y significativo en el precio, mientras que el número de habitaciones no parece relevante. Tener parqueaderos y baños adicionales sí aumenta el precio de manera significativa. El modelo explica el 65.63% de la variabilidad del precio (R²), lo cual es moderado, pero hay otros factores que podrían mejorar la predicción, como la ubicación y los materiales. Además, la variable habitaciones podría reconsiderarse.
Se plantea segundo modelo sin la variable habitaciones queda así: el precio se estima con un intercepto de -174.93 y aumenta con el área construida (0.800 por m²), el estrato (73.17 por nivel), los parqueaderos (22.44 por cada uno) y los baños (17.54 por cada uno). La eliminación de habitaciones no afectó el ajuste del modelo, ya que R², los coeficientes y el error estándar residual se mantuvieron casi iguales. Esto confirma que habitaciones no aportaba información útil.
modelo2 <- lm(preciom ~ areaconst + estrato + parqueaderos + banios,
data = vivienda_norte_casas)
summary(modelo2)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + parqueaderos + banios,
## data = vivienda_norte_casas)
##
## Residuals:
## Min 1Q Median 3Q Max
## -919.52 -73.87 -15.48 35.12 1126.34
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -174.92509 31.46001 -5.560 4.14e-08 ***
## areaconst 0.80024 0.04763 16.800 < 2e-16 ***
## estrato 73.17145 8.48317 8.625 < 2e-16 ***
## parqueaderos 22.43891 4.85231 4.624 4.65e-06 ***
## banios 17.53795 5.67523 3.090 0.0021 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 161 on 573 degrees of freedom
## Multiple R-squared: 0.6563, Adjusted R-squared: 0.6539
## F-statistic: 273.5 on 4 and 573 DF, p-value: < 2.2e-16
MODELO 2
\[ \text{Precio} = -174.93 + 0.80 \times \text{areaconst} + 73.17 \times \text{estrato} + 22.44 \times \text{parqueaderos} + 17.54 \times \text{banios} + \varepsilon \]
Se plantea un modelo 3 con transformación logaritmica, en este se usa log_preciom y log_areaconst
vivienda_modelo <- vivienda_norte_casas # Crear una copia
vivienda_modelo$log_preciom <- log(vivienda_modelo$preciom)
vivienda_modelo$log_areaconst <- log(vivienda_modelo$areaconst)
modelo3 <- lm(log_preciom ~ log_areaconst + estrato + parqueaderos + banios, data = vivienda_modelo)
summary(modelo3)
##
## Call:
## lm(formula = log_preciom ~ log_areaconst + estrato + parqueaderos +
## banios, data = vivienda_modelo)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.76903 -0.16864 -0.01433 0.13534 1.12494
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.275475 0.104766 21.720 < 2e-16 ***
## log_areaconst 0.508213 0.024472 20.767 < 2e-16 ***
## estrato 0.165433 0.014726 11.234 < 2e-16 ***
## parqueaderos 0.037913 0.008080 4.692 3.39e-06 ***
## banios 0.044230 0.009654 4.582 5.67e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2673 on 573 degrees of freedom
## Multiple R-squared: 0.7877, Adjusted R-squared: 0.7862
## F-statistic: 531.3 on 4 and 573 DF, p-value: < 2.2e-16
MODELO 3
\[ \log(\text{precio}) = 1.459 + 0.669 \times \log(\text{área construida}) + 0.179 \times \text{estrato} + 0.090 \times \text{parqueaderos} + 0.068 \times \text{baños} \]
Este modelo explica el 86.17% de la variabilidad en el logaritmo del precio, mejorando significativamente el ajuste anterior. Como usa logaritmos, los coeficientes indican cambios porcentuales: un 1% más de área construida sube el precio un 0.67%, cada nivel de estrato lo aumenta en 17.9%, un parqueadero adicional en 8.97% y un baño en 6.85%. Los residuos son menores, lo que sugiere que el modelo predice mejor los precios.
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).
Las pruebas de supuestos en modelos de regresión incluyen verificar la normalidad de los residuos (test de Shapiro-Wilk o gráfico Q-Q), homocedasticidad (prueba de Breusch-Pagan o gráfico de residuos), no colinealidad (VIF) y ausencia de autocorrelación (prueba de Durbin-Watson), a continuación realizaremos estas pruebas:
par(mfrow = c(2, 2)) # Dividir la pantalla en 4 gráficos
plot(modelo1) # Modelo lineal sin habitaciones
plot(modelo2) # Modelo lineal con menos variables
plot(modelo3) # Modelo log-log
#prueba de normalidad
shapiro.test(resid(modelo1)) # Para el modelo 1
##
## Shapiro-Wilk normality test
##
## data: resid(modelo1)
## W = 0.79872, p-value < 2.2e-16
shapiro.test(resid(modelo2)) # Para el modelo 2
##
## Shapiro-Wilk normality test
##
## data: resid(modelo2)
## W = 0.79873, p-value < 2.2e-16
shapiro.test(resid(modelo3)) # Para el modelo 3
##
## Shapiro-Wilk normality test
##
## data: resid(modelo3)
## W = 0.9746, p-value = 1.831e-08
#prueba homocedasticidad
bptest(modelo1) # Prueba de Breusch-Pagan para modelo 1
##
## studentized Breusch-Pagan test
##
## data: modelo1
## BP = 90.478, df = 5, p-value < 2.2e-16
bptest(modelo2) # Prueba de Breusch-Pagan para modelo 2
##
## studentized Breusch-Pagan test
##
## data: modelo2
## BP = 90.077, df = 4, p-value < 2.2e-16
bptest(modelo3) # Prueba de Breusch-Pagan para modelo 3
##
## studentized Breusch-Pagan test
##
## data: modelo3
## BP = 25.887, df = 4, p-value = 3.336e-05
# independencia de los residuos
dwtest(modelo1) # Prueba de Durbin-Watson para modelo 1
##
## Durbin-Watson test
##
## data: modelo1
## DW = 1.7275, p-value = 0.0004411
## alternative hypothesis: true autocorrelation is greater than 0
dwtest(modelo2) # Prueba de Durbin-Watson para modelo 2
##
## Durbin-Watson test
##
## data: modelo2
## DW = 1.725, p-value = 0.0003999
## alternative hypothesis: true autocorrelation is greater than 0
dwtest(modelo3) # Prueba de Durbin-Watson para modelo 3
##
## Durbin-Watson test
##
## data: modelo3
## DW = 1.725, p-value = 0.0003934
## alternative hypothesis: true autocorrelation is greater than 0
Los tres modelos presentan problemas con los supuestos. La prueba de Shapiro-Wilk indica que los residuos no siguen una distribución normal (p < 2.2e-16 en todos los casos), aunque el modelo 3 tiene un W más alto, lo que sugiere una mejor aproximación a la normalidad. La prueba de Breusch-Pagan muestra heterocedasticidad significativa en los tres modelos (p < 2.2e-16), lo que implica que la varianza de los residuos no es constante. La prueba de Durbin-Watson señala autocorrelación positiva en los tres modelos (p < 0.05), con el modelo 3 mostrando el mayor problema (DW = 1.5074). Esto indica que los residuos no son completamente independientes, lo que podría afectar la validez de las inferencias.
Para mejorar el ajuste, se recomienda transformar variables, se pueden aplicar transformaciones como logaritmos o Box-Cox para mejorar la normalidad de los residuos y estabilizar la varianza. Si hay heterocedasticidad, se pueden usar errores estándar robustos o regresión ponderada. Para la autocorrelación, se recomienda incluir términos autorregresivos, probar modelos ARIMA o aplicar estimadores como Prais-Winsten. Si hay multicolinealidad, calcular el VIF y eliminar variables redundantes o usar regresión ridge. También se puede mejorar la especificación del modelo incluyendo variables relevantes, términos polinómicos o interacciones. Finalmente, comparar modelos alternativos como regresión robusta o cuantílica puede ser útil si los problemas persisten.
Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.
# Crear data frame con valores a predecir
solicitud1 <- data.frame(
areaconst = 200,
parqueaderos = 1,
banios = 2,
habitaciones = 4,
estrato = c(4, 5) # Se hacen dos predicciones, una para cada estrato
)
# Predicción con el Modelo 1
pred_modelo1 <- predict(modelo1, newdata = solicitud1)
# Predicción con el Modelo 2
pred_modelo2 <- predict(modelo2, newdata = solicitud1)
# Mostrar resultados
data.frame(estrato = c(4,5), precio_modelo1 = pred_modelo1, precio_modelo2 = pred_modelo2)
## estrato precio_modelo1 precio_modelo2
## 1 4 334.5417 335.3229
## 2 5 407.0096 408.4943
# Agregar log_areaconst
solicitud1$log_areaconst <- log(solicitud1$areaconst)
# Predicción en escala logarítmica
log_pred_modelo3 <- predict(modelo3, newdata = solicitud1)
# Transformar de log(precio) a precio real
pred_modelo3 <- exp(log_pred_modelo3)
# Mostrar resultados
data.frame(estrato = c(4,5), precio_modelo3 = pred_modelo3)
## estrato precio_modelo3
## 1 4 316.1625
## 2 5 373.0415
Según los resultados obtenidos el cliente podría obtener las casas de estrato 4 para el modelo 1 y 2, en cambio para el modelo 3 no podría adquirir una casa con las características deseadas debido a que el menor valor corresponde a 383.4801 millones excediendo en más de 33 millones su presupuesto.
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.
MODELO 1
# Generar las predicciones para toda la base de apartamentos en la Zona Norte
vivienda_norte_casas_modelo1 <- vivienda_norte_casas %>%
mutate(precio_estimado_1 = predict(modelo1, newdata = vivienda_norte_casas))
# Filtrar apartamentos cuyo precio estimado está dentro del crédito aprobado
ofertas_potenciales1 <- vivienda_norte_casas_modelo1 %>%
filter(precio_estimado_1 <= 350) %>%
select(longitud, latitud, precio_estimado_1, areaconst, estrato, habitaciones, banios) %>%
arrange(desc(precio_estimado_1)) %>%
head(5) # Seleccionar las 5 mejores opciones
# Crear mapa con leaflet
leaflet(ofertas_potenciales1) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = 5,
color = "blue",
label = ~paste0("Precio: ", round(precio_estimado_1, 2), "M | Área: ", areaconst, "m² | Estrato: ", estrato, " | Hab: ", habitaciones, " | Baños: ", banios),
popup = ~paste0("Precio: ", round(precio_estimado_1, 2), "M <br> Área: ", areaconst, "m² <br> Estrato: ", estrato, " <br> Habitaciones: ", habitaciones, " <br> Baños: ", banios)
) %>%
addProviderTiles(providers$CartoDB.Positron)
ofertas_potenciales1
## longitud latitud precio_estimado_1 areaconst estrato habitaciones banios
## 1 -76.50235 3.47350 345.7651 240 3 7 5
## 2 -76.49500 3.46700 345.6295 99 5 3 3
## 3 -76.51661 3.48049 344.9659 290 3 7 4
## 4 -76.52616 3.46978 344.8257 98 5 3 3
## 5 -76.49920 3.49241 343.3625 265 3 7 5
MODELO 2
# Generar las predicciones para toda la base de apartamentos en la Zona Norte
vivienda_norte_casas_modelo2 <- vivienda_norte_casas %>%
mutate(precio_estimado_2 = predict(modelo2, newdata = vivienda_norte_casas))
# Filtrar apartamentos cuyo precio estimado está dentro del crédito aprobado
ofertas_potenciales2 <- vivienda_norte_casas_modelo2 %>%
filter(precio_estimado_2 <= 350) %>%
select(longitud, latitud, precio_estimado_2, areaconst, estrato, habitaciones, banios) %>%
arrange(desc(precio_estimado_2)) %>%
head(5) # Seleccionar las 5 mejores opciones
# Crear mapa con leaflet
leaflet(ofertas_potenciales2) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = 5,
color = "blue",
label = ~paste0("Precio: ", round(precio_estimado_2, 2), "M | Área: ", areaconst, "m² | Estrato: ", estrato, " | Hab: ", habitaciones, " | Baños: ", banios),
popup = ~paste0("Precio: ", round(precio_estimado_2, 2), "M <br> Área: ", areaconst, "m² <br> Estrato: ", estrato, " <br> Habitaciones: ", habitaciones, " <br> Baños: ", banios)
) %>%
addProviderTiles(providers$CartoDB.Positron)
ofertas_potenciales2
## longitud latitud precio_estimado_2 areaconst estrato habitaciones banios
## 1 -76.51661 3.48049 346.8097 290 3 7 4
## 2 -76.50235 3.47350 346.7748 240 3 7 5
## 3 -76.49500 3.46700 345.2084 99 5 3 3
## 4 -76.52616 3.46978 344.4081 98 5 3 3
## 5 -76.49920 3.49241 344.3418 265 3 7 5
MODELO 3
# Generar las predicciones para toda la base de apartamentos en la Zona Sur
vivienda_norte_casas_modelo1 <- vivienda_norte_casas %>%
mutate(precio_estimado_1 = predict(modelo1, newdata = vivienda_norte_casas))
# Filtrar apartamentos cuyo precio estimado está dentro del crédito aprobado
ofertas_potenciales1 <- vivienda_norte_casas_modelo1 %>%
filter(precio_estimado_1 <= 350) %>%
select(longitud, latitud, precio_estimado_1, areaconst, estrato, habitaciones, banios, parqueaderos) %>%
arrange(desc(precio_estimado_1)) %>%
head(5) # Seleccionar las 5 mejores opciones
# Crear mapa con leaflet
leaflet(ofertas_potenciales1) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = 5,
color = "blue",
label = ~paste0("Precio: ", round(precio_estimado_1, 2), "M | Área: ", areaconst, "m² | Estrato: ", estrato, " | Hab: ", habitaciones, " | Baños: ", banios," | Parqueaderos: ", parqueaderos),
popup = ~paste0("Precio: ", round(precio_estimado_1, 2), "M <br> Área: ", areaconst, "m² <br> Estrato: ", estrato, " <br> Habitaciones: ", habitaciones, " <br> Baños: ", banios)
) %>%
addProviderTiles(providers$CartoDB.Positron)
print(ofertas_potenciales1)
## longitud latitud precio_estimado_1 areaconst estrato habitaciones banios
## 1 -76.50235 3.47350 345.7651 240 3 7 5
## 2 -76.49500 3.46700 345.6295 99 5 3 3
## 3 -76.51661 3.48049 344.9659 290 3 7 4
## 4 -76.52616 3.46978 344.8257 98 5 3 3
## 5 -76.49920 3.49241 343.3625 265 3 7 5
## parqueaderos
## 1 1
## 2 1
## 3 0
## 4 1
## 5 0
# Generar las predicciones para toda la base de apartamentos en la Zona Sur
vivienda_norte_casas_modelo2 <- vivienda_norte_casas %>%
mutate(precio_estimado_2 = predict(modelo2, newdata = vivienda_norte_casas))
# Filtrar apartamentos cuyo precio estimado está dentro del crédito aprobado
ofertas_potenciales2 <- vivienda_norte_casas_modelo2 %>%
filter(precio_estimado_2 <= 350) %>%
select(longitud, latitud, precio_estimado_2, areaconst, estrato, habitaciones, banios, parqueaderos) %>%
arrange(desc(precio_estimado_2)) %>%
head(5) # Seleccionar las 5 mejores opciones
# Crear mapa con leaflet
leaflet(ofertas_potenciales2) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = 5,
color = "blue",
label = ~paste0("Precio: ", round(precio_estimado_2, 2), "M | Área: ", areaconst, "m² | Estrato: ", estrato, " | Hab: ", habitaciones, " | Baños: ", banios," | Parqueaderos: ", parqueaderos),
popup = ~paste0("Precio: ", round(precio_estimado_2, 2), "M <br> Área: ", areaconst, "m² <br> Estrato: ", estrato, " <br> Habitaciones: ", habitaciones, " <br> Baños: ", banios)
) %>%
addProviderTiles(providers$CartoDB.Positron)
print(ofertas_potenciales2)
## longitud latitud precio_estimado_2 areaconst estrato habitaciones banios
## 1 -76.51661 3.48049 346.8097 290 3 7 4
## 2 -76.50235 3.47350 346.7748 240 3 7 5
## 3 -76.49500 3.46700 345.2084 99 5 3 3
## 4 -76.52616 3.46978 344.4081 98 5 3 3
## 5 -76.49920 3.49241 344.3418 265 3 7 5
## parqueaderos
## 1 0
## 2 1
## 3 1
## 4 1
## 5 0
#Modelo 3
# Modelo 3
# Generar las predicciones para toda la base de viviendas en la Zona Norte
vivienda_norte_casas <- vivienda_norte_casas %>%
mutate(log_areaconst = log(areaconst))
# Aplicar el modelo 3 para estimar precios
vivienda_norte_casas_modelo3 <- vivienda_norte_casas %>%
mutate(precio_estimado_31 = predict(modelo3, newdata = vivienda_norte_casas))
# Transformar de nuevo los valores a su escala original
vivienda_norte_casas_modelo3 <- vivienda_norte_casas_modelo3 %>%
mutate(precio_estimado_31 = exp(precio_estimado_31),
areaconst = exp(log_areaconst))
# Filtrar casas que cumplan con las condiciones del crédito
ofertas_potenciales3 <- vivienda_norte_casas_modelo3 %>%
filter(precio_estimado_31 <= 350) %>%
select(longitud, latitud, precio_estimado_31, areaconst, estrato, habitaciones, banios, parqueaderos) %>%
arrange(desc(precio_estimado_31)) %>%
head(5) # Seleccionar las 5 mejores opciones
# Crear mapa con leaflet
leaflet(ofertas_potenciales3) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = 5,
color = "blue",
label = ~paste0("Precio: ", round(precio_estimado_31, 2), "M | Área: ", round(areaconst, 2), "m² | Estrato: ", estrato, " | Hab: ", habitaciones, " | Baños: ", banios, " | Parqueaderos: ", parqueaderos),
popup = ~paste0("Precio: ", round(precio_estimado_31, 2), "M <br> Área: ", round(areaconst, 2), "m² <br> Estrato: ", estrato, " <br> Habitaciones: ", habitaciones, " <br> Baños: ", banios, " <br> Parqueaderos: ", parqueaderos)
) %>%
addProviderTiles(providers$CartoDB.Positron)
ofertas_potenciales3
## longitud latitud precio_estimado_31 areaconst estrato habitaciones banios
## 1 -76.53504 3.48958 349.8938 150 5 4 3
## 2 -76.51568 3.48876 348.1091 160 5 4 3
## 3 -76.51273 3.48960 348.0828 158 5 3 4
## 4 -76.52720 3.48433 346.8576 240 4 3 2
## 5 -76.52400 3.48400 346.0965 145 5 4 4
## parqueaderos
## 1 2
## 2 1
## 3 0
## 4 1
## 5 1