# Paquetes necesarios
packs <- c(
"devtools", "paqueteMODELOS", # datos
"tidyverse", "janitor", "lubridate", "scales",
"plotly", "leaflet", "sf",
"broom", "gt", "performance", "car", "lmtest", "glue"
)
for(p in packs){ if(!requireNamespace(p, quietly=TRUE)) install.packages(p) }
# paqueteMODELOS desde GitHub si hace falta
if(!requireNamespace("paqueteMODELOS", quietly=TRUE)){
devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
}
# Carga de librerías
library(paqueteMODELOS)
library(tidyverse); library(janitor); library(lubridate); library(scales)
library(plotly); library(leaflet); library(sf)
library(broom); library(gt); library(performance); library(car); library(lmtest); library(glue)
# Datos
data("vivienda")
raw <- vivienda %>% clean_names()
# Vista general
glimpse(raw)
## Rows: 8,322
## Columns: 13
## $ id <dbl> 1147, 1169, 1350, 5992, 1212, 1724, 2326, 4386, 1209, 159…
## $ zona <chr> "Zona Oriente", "Zona Oriente", "Zona Oriente", "Zona Sur…
## $ piso <chr> NA, NA, NA, "02", "01", "01", "01", "01", "02", "02", "02…
## $ estrato <dbl> 3, 3, 3, 4, 5, 5, 4, 5, 5, 5, 6, 4, 5, 6, 4, 5, 5, 4, 5, …
## $ preciom <dbl> 250, 320, 350, 400, 260, 240, 220, 310, 320, 780, 750, 62…
## $ areaconst <dbl> 70, 120, 220, 280, 90, 87, 52, 137, 150, 380, 445, 355, 2…
## $ parqueaderos <dbl> 1, 1, 2, 3, 1, 1, 2, 2, 2, 2, NA, 3, 2, 2, 1, 4, 2, 2, 2,…
## $ banios <dbl> 3, 2, 2, 5, 2, 3, 2, 3, 4, 3, 7, 5, 6, 2, 4, 4, 4, 3, 2, …
## $ habitaciones <dbl> 6, 3, 4, 3, 3, 3, 3, 4, 6, 3, 6, 5, 6, 2, 5, 5, 4, 3, 3, …
## $ tipo <chr> "Casa", "Casa", "Casa", "Casa", "Apartamento", "Apartamen…
## $ barrio <chr> "20 de julio", "20 de julio", "20 de julio", "3 de julio"…
## $ longitud <dbl> -76.51168, -76.51237, -76.51537, -76.54000, -76.51350, -7…
## $ latitud <dbl> 3.43382, 3.43369, 3.43566, 3.43500, 3.45891, 3.36971, 3.4…
# Normalización de tipos
vivi <- raw %>%
mutate(
estrato = as.integer(estrato),
preciom = as.numeric(preciom), # precio en millones de pesos
areaconst = as.numeric(areaconst),
parqueaderos = as.integer(parqueaderos),
banios = as.integer(banios),
habitaciones = as.integer(habitaciones),
latitud = as.numeric(latitud),
longitud = as.numeric(longitud),
tipo = as.factor(tipo),
zona = as.factor(zona),
barrio = as.character(barrio)
) %>%
filter(!is.na(preciom), !is.na(areaconst), !is.na(estrato)) %>%
distinct() # remover duplicados exactos si los hay
summary(vivi$preciom)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 58.0 220.0 330.0 433.9 540.0 1999.0
Nota: En todo el informe, preciom está en millones de pesos.
base1 <- vivi %>% filter(tipo == "Casa", zona == "Zona Norte")
# Primeros 3 registros
head(base1, 3) %>% gt()
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 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 |
# Tablas de control
vivi %>% count(tipo, zona, name = "n_ofertas") %>% arrange(desc(n_ofertas)) %>% gt()
| tipo | zona | n_ofertas |
|---|---|---|
| Apartamento | Zona Sur | 2787 |
| Casa | Zona Sur | 1939 |
| Apartamento | Zona Norte | 1198 |
| Apartamento | Zona Oeste | 1029 |
| Casa | Zona Norte | 722 |
| Casa | Zona Oriente | 289 |
| Casa | Zona Oeste | 169 |
| Casa | Zona Centro | 100 |
| Apartamento | Zona Oriente | 62 |
| Apartamento | Zona Centro | 24 |
# Comprobación básica de coherencia geográfica (coordenadas dentro de un rango plausible de Cali)
# Cali aprox: lat 3.2–3.7, lon -76.7 a -76.3 (rango amplio para detectar outliers)
base1 <- base1 %>% mutate(
coord_ok = between(latitud, 3.2, 3.7) & between(longitud, -76.7, -76.3)
)
table_coord <- base1 %>% count(coord_ok, name = "n")
table_coord %>% gt()
| coord_ok | n |
|---|---|
| TRUE | 722 |
# Mapa: todas las ofertas (gris) y Casas Zona Norte (color)
leaflet() %>% addProviderTiles(providers$CartoDB.Positron) %>%
addCircleMarkers(data = vivi %>% filter(!is.na(latitud), !is.na(longitud)),
lng = ~longitud, lat = ~latitud, radius = 3,
opacity = 0.5, fillOpacity = 0.3, popup = ~paste0(
"<b>", tipo, " – ", zona, "</b><br>",
barrio, "<br>Área: ", areaconst, " m²",
"<br>Precio: $", scales::comma(preciom, accuracy = 0.1), " M"
)) %>%
addCircleMarkers(data = base1 %>% filter(!is.na(latitud), !is.na(longitud)),
lng = ~longitud, lat = ~latitud, radius = 5,
opacity = 1, fillOpacity = 0.8, color = "#90ee90",
popup = ~paste0(
"<b>CASA – Zona Norte</b><br>", barrio,
"<br>Área: ", areaconst, " m²",
"<br>Estrato: ", estrato,
"<br>Hab: ", habitaciones, " | Baños: ", banios,
" | Parq: ", parqueaderos,
"<br>Precio: $", scales::comma(preciom, accuracy = 0.1), " M"
))
Conclusiones:
Cantidad de ofertas: El filtro aplicado a la base de datos permitió identificar 722 casas ubicadas en la Zona Norte de Cali, lo que representa un volumen importante de alternativas para potenciales compradores en este sector.
Coherencia geográfica: Todas las viviendas filtradas presentan coordenadas dentro del rango esperado para el área urbana de Cali (coord_ok = TRUE en 722 casos). Esto indica que no existen registros con errores de georreferenciación ni ubicaciones fuera del perímetro de la ciudad.
Distribución espacial: En el mapa interactivo se observa una alta concentración de ofertas en la franja norte de la ciudad, lo que confirma la correcta clasificación de los registros como “Zona Norte”. Además, las viviendas aparecen distribuidas en varios barrios, lo que diversifica la oferta.
Ejemplos de registros: Los primeros casos muestran variación en área construida (150–445 m²), estrato (5–6), número de habitaciones y precio (320–780 millones), lo cual refleja heterogeneidad dentro de la misma zona. Esto será útil más adelante para modelar precios y segmentar opciones según presupuesto.
# Variables de interés
vars_num <- vivi %>% select(preciom, areaconst, estrato, banios, habitaciones)
# Matriz de correlación (Pearson por defecto)
cor_mat <- cor(vars_num, use = "pairwise.complete.obs")
cor_mat
## preciom areaconst estrato banios habitaciones
## preciom 1.0000000 0.6873520 0.60980664 0.6691456 0.26409121
## areaconst 0.6873520 1.0000000 0.27432332 0.6484165 0.51691292
## estrato 0.6098066 0.2743233 1.00000000 0.4203218 -0.07137615
## banios 0.6691456 0.6484165 0.42032178 1.0000000 0.58990641
## habitaciones 0.2640912 0.5169129 -0.07137615 0.5899064 1.00000000
# Heatmap interactivo de correlaciones
plot_ly(x = colnames(cor_mat), y = rownames(cor_mat), z = cor_mat,
type = "heatmap", hovertemplate = paste(
"<b>%{x} ~ %{y}</b><br>", "cor: %{z:.2f}<extra></extra>"
))
# Dispersión precio vs área (toda la base) con color por zona
plot_ly(vivi, x = ~areaconst, y = ~preciom, color = ~zona, type = "scattergl", mode = "markers",
hovertemplate = paste(
"Zona: %{marker.color}<br>",
"Área: %{x} m²<br>",
"Precio: $%{y} M<extra></extra>"
)) %>%
layout(xaxis = list(title = "Área construida (m²)"), yaxis = list(title = "Precio (M)"))
# Boxplot Precio por Estrato (interactivo)
plot_ly(vivi, x = ~as.factor(estrato), y = ~preciom, type = "box", boxpoints = "outliers") %>%
layout(xaxis = list(title = "Estrato"), yaxis = list(title = "Precio (M)"))
# Precio vs número de baños (casas), color por habitaciones
plot_ly(vivi %>% filter(tipo=="Casa"), x = ~banios, y = ~preciom, color = ~as.factor(habitaciones),
type = "scatter", mode = "markers") %>%
layout(xaxis = list(title = "Baños"), yaxis = list(title = "Precio (M)"), legend = list(title=list(text="Habitaciones")))
Conclusiones del análisis exploratorio
Área construida y precio:
Existe una correlación positiva moderada-alta (r ≈ 0.69) entre el área construida y el precio de la vivienda.
En el diagrama de dispersión se observa que a mayor área, los precios tienden a ser más altos, aunque con bastante dispersión en los valores superiores.
Estrato y precio:
El boxplot por estrato muestra que el precio se incrementa de manera clara conforme sube el estrato.
La correlación también es positiva (r ≈ 0.61), lo cual confirma que los inmuebles de estratos altos suelen ser más costosos.
Baños y habitaciones:
El número de baños tiene una correlación moderada con el precio (r ≈ 0.66), lo que sugiere que es una característica relevante en la valorización.
El número de habitaciones muestra una relación más débil con el precio (r ≈ 0.26), lo que indica que el impacto no es tan fuerte como el área o el estrato.
Interacciones entre variables:
Baños y área tienen alta correlación (r ≈ 0.65), lo que es lógico, ya que viviendas más grandes suelen tener más baños.
Habitaciones y baños también se correlacionan positivamente (r ≈ 0.59).
Esto indica cierta redundancia: algunas variables aportan información similar y habrá que revisarlo al momento de construir el modelo para evitar multicolinealidad.
Diferencias por zona:
El gráfico de dispersión precio–área por zonas evidencia que la Zona Sur concentra gran parte de la oferta con precios altos y áreas grandes.
La Zona Norte también presenta precios elevados, mientras que Oriente y Centro tienden a mostrar precios menores, incluso en áreas comparables.
Síntesis ejecutiva:
El análisis confirma que el precio de la vivienda está principalmente explicado por el área construida, el estrato y el número de baños, mientras que las habitaciones tienen menor peso individual. Además, la ubicación (zona) influye claramente en el nivel de precios, lo que justifica incluirla o controlarla en los modelos posteriores.
casas <- vivi %>% filter(tipo == "Casa")
modelo <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = casas)
summary(modelo)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = casas)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1190.80 -114.52 -25.94 74.59 986.16
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -413.87536 25.58852 -16.174 < 2e-16 ***
## areaconst 0.74227 0.02941 25.235 < 2e-16 ***
## estrato 116.07109 5.26618 22.041 < 2e-16 ***
## habitaciones -14.74995 3.18137 -4.636 3.73e-06 ***
## parqueaderos 64.29943 3.47719 18.492 < 2e-16 ***
## banios 39.03498 4.05083 9.636 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 205.2 on 2480 degrees of freedom
## (733 observations deleted due to missingness)
## Multiple R-squared: 0.6834, Adjusted R-squared: 0.6828
## F-statistic: 1071 on 5 and 2480 DF, p-value: < 2.2e-16
# Métricas de ajuste
r2 <- summary(modelo)$r.squared
r2_adj <- summary(modelo)$adj.r.squared
rmse <- sqrt(mean(residuals(modelo)^2))
glue("R2 = {round(r2,3)} | R2 ajustado = {round(r2_adj,3)} | RMSE = {round(rmse,2)} M")
## R2 = 0.683 | R2 ajustado = 0.683 | RMSE = 205 M
# Tabla ordenada de coeficientes
broom::tidy(modelo, conf.int = TRUE) %>%
mutate(across(estimate:conf.high, ~round(.x,3))) %>%
arrange(p.value) %>%
gt()
| term | estimate | std.error | statistic | p.value | conf.low | conf.high |
|---|---|---|---|---|---|---|
| (Intercept) | -413.875 | 25.589 | -16.174 | 0 | -464.052 | -363.698 |
| areaconst | 0.742 | 0.029 | 25.235 | 0 | 0.685 | 0.800 |
| estrato | 116.071 | 5.266 | 22.041 | 0 | 105.745 | 126.398 |
| habitaciones | -14.750 | 3.181 | -4.636 | 0 | -20.988 | -8.512 |
| parqueaderos | 64.299 | 3.477 | 18.492 | 0 | 57.481 | 71.118 |
| banios | 39.035 | 4.051 | 9.636 | 0 | 31.092 | 46.978 |
Coeficiente de determinación (R²):
El modelo explica aproximadamente el 68.3% de la variabilidad del precio de las casas.
Es un ajuste aceptable considerando que en bienes raíces influyen factores no incluidos (ubicación exacta, antigüedad, acabados, etc.).
Error estándar residual (RMSE):
El error medio de predicción es de 205 millones, lo que marca la magnitud típica de desviación entre los valores observados y los predichos.
Esto significa que el modelo es útil para capturar tendencias, pero hay un margen de error considerable en casos individuales.
Significancia de las variables:
Área construida (0.742, p<0.001): por cada metro cuadrado adicional, el precio aumenta en promedio 0.74 millones.
Estrato (116.07, p<0.001): subir un nivel de estrato aumenta el precio en promedio 116 millones, manteniendo lo demás constante.
Parqueaderos (64.30, p<0.001): cada parqueadero adicional incrementa el precio en 64 millones.
Baños (39.04, p<0.001): cada baño adicional aumenta el precio en 39 millones.
Habitaciones (-14.75, p<0.001): sorprendentemente, más habitaciones reducen el precio en promedio, lo cual puede reflejar colinealidad con el área (casas grandes con muchas habitaciones no siempre son más costosas si el área por habitación es menor).
Intercepción: El intercepto (-413) carece de interpretación práctica, pues corresponde al precio estimado cuando todas las variables valen cero (situación irreal).
Conclucion general: El precio de las casas en Cali depende principalmente del área, el estrato y la dotación de parqueaderos y baños. El modelo explica dos tercios de la variabilidad de los precios, con un error promedio de ±205 millones. Se recomienda complementar con variables de localización y características constructivas para afinar la predicción.
# Linealidad y homocedasticidad: residuales vs ajustados
plot_ly(x = fitted(modelo), y = resid(modelo), type = "scatter", mode = "markers") %>%
layout(xaxis=list(title="Valores ajustados"), yaxis=list(title="Residuales"))
# Normalidad (QQ-plot)
qq <- qqnorm(resid(modelo), plot.it = FALSE)
plot_ly(x = qq$x, y = qq$y, type = "scatter", mode = "markers") %>%
add_lines(x = sort(qq$x), y = sort(qq$x)) %>%
layout(xaxis=list(title="Teórico"), yaxis=list(title="Muestral"))
# Breusch–Pagan (heterocedasticidad)
bptest(modelo)
##
## studentized Breusch-Pagan test
##
## data: modelo
## BP = 321.2, df = 5, p-value < 2.2e-16
# Multicolinealidad (VIF)
car::vif(modelo)
## areaconst estrato habitaciones parqueaderos banios
## 1.541765 1.694080 1.594265 1.535105 2.059733
# Observaciones influyentes (Cook)
cook <- cooks.distance(modelo)
plot_ly(x = seq_along(cook), y = cook, type = "bar") %>%
layout(xaxis=list(title="Índice"), yaxis=list(title="Cook's D"))
Concluciones: El modelo cumple con los supuestos de independencia y baja multicolinealidad, pero presenta problemas de heterocedasticidad y cierta no normalidad de residuales.
A nivel práctico, el modelo sigue siendo útil y significativo, pero para mejorarlo se podrían aplicar transformaciones (logaritmo del precio), usar modelos robustos o métodos no lineales.
También es recomendable revisar y depurar los outliers influyentes detectados por la distancia de Cook
Características requeridas: área = 200 m², parqueaderos = 1, baños = 2, habitaciones = 4, estrato 4 o 5.
new_casa <- expand.grid(
areaconst = 200,
estrato = c(4,5),
habitaciones = 4,
parqueaderos = 1,
banios = 2
)
pred_casa <- predict(modelo, newdata = new_casa, interval = "prediction", level = 0.90) %>% as.data.frame()
resultado_casa <- cbind(new_casa, round(pred_casa, 2))
resultado_casa %>% gt()
| areaconst | estrato | habitaciones | parqueaderos | banios | fit | lwr | upr |
|---|---|---|---|---|---|---|---|
| 200 | 4 | 4 | 1 | 2 | 282.23 | -55.71 | 620.18 |
| 200 | 5 | 4 | 1 | 2 | 398.30 | 60.23 | 736.38 |
Concluciones: .
El modelo estima que una casa con las características solicitadas tendría un precio esperado de 282 M en estrato 4 (ajustado al presupuesto disponible) y 398 M en estrato 5 (superior al crédito aprobado). Por lo tanto, la recomendación es centrar la búsqueda en casas de estrato 4 en la Zona Norte, donde es más probable encontrar opciones viables dentro del límite de financiación.
# Estrategia de filtrado: match exacto de tipo y zona, y tolerancias razonables en área
# (±15%). Para baños/habitaciones/parqueaderos se piden mínimos.
match_ofertas <- function(data, tipo_req, zona_req, area_obj, area_tol = 0.15,
estrato_min = 4, estrato_max = 5,
banios_min = 2, hab_min = 4, parq_min = 1,
precio_max = 350){
data %>%
filter(
tipo == tipo_req,
zona == zona_req,
areaconst >= area_obj*(1-area_tol) & areaconst <= area_obj*(1+area_tol),
estrato >= estrato_min, estrato <= estrato_max,
banios >= banios_min,
habitaciones >= hab_min,
parqueaderos >= parq_min,
preciom <= precio_max,
!is.na(latitud), !is.na(longitud)
) %>%
mutate(
score = abs(areaconst - area_obj) + pmax(0, preciom - precio_max) # menor es mejor
) %>% arrange(score, preciom)
}
ofertas_casa <- match_ofertas(
vivi, tipo_req = "Casa", zona_req = "Zona Norte",
area_obj = 200, estrato_min = 4, estrato_max = 5,
banios_min = 2, hab_min = 4, parq_min = 1, precio_max = 350
)
head(ofertas_casa, 10) %>% select(barrio, preciom, areaconst, estrato, banios, habitaciones, parqueaderos, latitud, longitud) %>% gt()
| barrio | preciom | areaconst | estrato | banios | habitaciones | parqueaderos | latitud | longitud |
|---|---|---|---|---|---|---|---|---|
| la flora | 320 | 200 | 5 | 4 | 4 | 2 | 3.48893 | -76.51524 |
| la merced | 320 | 200 | 4 | 4 | 4 | 2 | 3.48029 | -76.51156 |
| el bosque | 350 | 200 | 5 | 3 | 4 | 3 | 3.48503 | -76.53010 |
| el bosque | 335 | 202 | 5 | 4 | 5 | 1 | 3.48399 | -76.53044 |
| vipasa | 340 | 203 | 5 | 3 | 4 | 2 | 3.48257 | -76.51803 |
| el bosque | 350 | 203 | 5 | 2 | 5 | 2 | 3.48531 | -76.51448 |
| vipasa | 300 | 205 | 5 | 5 | 6 | 2 | 3.48138 | -76.51832 |
| urbanización la merced | 320 | 210 | 5 | 3 | 5 | 2 | 3.47600 | -76.51200 |
| la merced | 350 | 216 | 5 | 2 | 4 | 2 | 3.48181 | -76.51218 |
| la flora | 340 | 180 | 5 | 4 | 4 | 2 | 3.48675 | -76.51633 |
# Mapa con al menos 5 ofertas (si existen)
leaflet(ofertas_casa %>% head(10)) %>% addProviderTiles(providers$CartoDB.Positron) %>%
addCircleMarkers(~longitud, ~latitud, radius = 7, popup = ~paste0(
"<b>", barrio, "</b><br>",
"Precio: $", scales::comma(preciom), " M<br>",
"Área: ", areaconst, " m² | Estrato: ", estrato, "<br>",
"Hab: ", habitaciones, " | Baños: ", banios, " | Parq: ", parqueaderos
))
Conclucion:
Las opciones identificadas cumplen con el presupuesto de $350 millones y las características solicitadas para la Vivienda 1. Los barrios La Flora, La Merced, El Bosque y Vipasa se perfilan como las alternativas más sólidas, tanto por ubicación como por precio. Se recomienda a la empresa cliente priorizar estas zonas, ya que ofrecen viviendas que satisfacen los requisitos de área, estrato y comodidades.
Requisitos: tipo = Apartamento, área = 300 m², parqueaderos = 3, baños = 3, habitaciones = 5, estrato 5 o 6, zona = Sur, crédito = $850 M.
# Predicción usando mismo modelo (nota: es de CASAS). Opciones:
# a) Estimar un modelo análogo solo con Apartamentos; o
# b) Un modelo combinado con factor(tipo).
# Aquí mostramos ambos para transparencia.
aptos <- vivi %>% filter(tipo == "Apartamento")
modelo_apt <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = aptos)
summary(modelo_apt)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = aptos)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1699.03 -57.72 -0.67 48.59 1005.44
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -278.47706 15.86822 -17.55 <2e-16 ***
## areaconst 2.00464 0.04839 41.42 <2e-16 ***
## estrato 56.24218 3.05907 18.39 <2e-16 ***
## habitaciones -42.66447 3.80700 -11.21 <2e-16 ***
## parqueaderos 90.42324 4.14278 21.83 <2e-16 ***
## banios 54.84690 3.41824 16.05 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 137.7 on 4225 degrees of freedom
## (869 observations deleted due to missingness)
## Multiple R-squared: 0.7845, Adjusted R-squared: 0.7843
## F-statistic: 3077 on 5 and 4225 DF, p-value: < 2.2e-16
new_apto <- expand.grid(
areaconst = 300,
estrato = c(5,6),
habitaciones = 5,
parqueaderos = 3,
banios = 3
)
pred_apto <- predict(modelo_apt, newdata = new_apto, interval = "prediction", level = 0.90) %>% as.data.frame()
resultado_apto <- cbind(new_apto, round(pred_apto, 2))
resultado_apto %>% gt()
| areaconst | estrato | habitaciones | parqueaderos | banios | fit | lwr | upr |
|---|---|---|---|---|---|---|---|
| 300 | 5 | 5 | 3 | 3 | 826.61 | 599.36 | 1053.87 |
| 300 | 6 | 5 | 3 | 3 | 882.86 | 655.58 | 1110.14 |
# Sugerencia de ofertas (Sur, tope $850 M)
ofertas_apto <- match_ofertas(
vivi, tipo_req = "Apartamento", zona_req = "Zona Sur",
area_obj = 300, estrato_min = 5, estrato_max = 6,
banios_min = 3, hab_min = 5, parq_min = 3, precio_max = 850
)
head(ofertas_apto, 10) %>% select(barrio, preciom, areaconst, estrato, banios, habitaciones, parqueaderos, latitud, longitud) %>% gt()
| barrio | preciom | areaconst | estrato | banios | habitaciones | parqueaderos | latitud | longitud |
|---|---|---|---|---|---|---|---|---|
| seminario | 670 | 300 | 5 | 5 | 6 | 3 | 3.40900 | -76.55000 |
| seminario | 530 | 256 | 5 | 5 | 5 | 3 | 3.40748 | -76.55408 |
leaflet(ofertas_apto %>% head(10)) %>% addProviderTiles(providers$CartoDB.Positron) %>%
addCircleMarkers(~longitud, ~latitud, radius = 7, popup = ~paste0(
"<b>", barrio, "</b><br>",
"Precio: $", scales::comma(preciom), " M<br>",
"Área: ", areaconst, " m² | Estrato: ", estrato, "<br>",
"Hab: ", habitaciones, " | Baños: ", banios, " | Parq: ", parqueaderos
))
El modelo para apartamentos presenta buen ajuste (R²=0.785) y predice precios esperados de 826–883 M para la vivienda solicitada, valores alineados con el crédito aprobado de 850 M. Se identificaron dos opciones viables en el barrio Seminario (Zona Sur), con precios de 530 M y 670 M, que cumplen e incluso superan las características requeridas. Por tanto, existen alternativas en el mercado dentro del presupuesto y con condiciones favorables para la empresa.
María debe concentrarse en casas de estrato 4 en el norte y apartamentos de estrato 5 en el sur, donde hay oferta suficiente dentro del presupuesto aprobado. Se recomienda complementar el análisis con más variables de ubicación y aplicar modelos más robustos en futuras proyecciones para mejorar la precisión y reducir la influencia de outliers.
sessionInfo()
## R version 4.4.2 (2024-10-31 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 22631)
##
## Matrix products: default
##
##
## locale:
## [1] LC_COLLATE=Spanish_Colombia.utf8 LC_CTYPE=Spanish_Colombia.utf8
## [3] LC_MONETARY=Spanish_Colombia.utf8 LC_NUMERIC=C
## [5] LC_TIME=Spanish_Colombia.utf8
##
## time zone: America/Bogota
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] glue_1.8.0 lmtest_0.9-40 zoo_1.8-12
## [4] car_3.1-3 carData_3.0-5 performance_0.15.1
## [7] gt_1.0.0 sf_1.0-21 leaflet_2.2.2
## [10] plotly_4.11.0 scales_1.3.0 janitor_2.2.1
## [13] lubridate_1.9.4 forcats_1.0.0 stringr_1.5.1
## [16] dplyr_1.1.4 purrr_1.0.4 readr_2.1.5
## [19] tidyr_1.3.1 tibble_3.2.1 tidyverse_2.0.0
## [22] paqueteMODELOS_0.1.0 summarytools_1.1.4 knitr_1.50
## [25] gridExtra_2.3 GGally_2.2.1 ggplot2_3.5.2
## [28] broom_1.0.8 boot_1.3-31
##
## loaded via a namespace (and not attached):
## [1] DBI_1.2.3 tcltk_4.4.2 remotes_2.5.0
## [4] rlang_1.1.5 magrittr_2.0.3 snakecase_0.11.1
## [7] matrixStats_1.5.0 e1071_1.7-16 compiler_4.4.2
## [10] reshape2_1.4.4 vctrs_0.6.5 profvis_0.4.0
## [13] crayon_1.5.3 pkgconfig_2.0.3 fastmap_1.2.0
## [16] backports_1.5.0 magick_2.8.7 ellipsis_0.3.2
## [19] pander_0.6.6 promises_1.3.2 rmarkdown_2.29
## [22] tzdb_0.4.0 sessioninfo_1.2.3 xfun_0.52
## [25] cachem_1.1.0 jsonlite_1.8.9 later_1.4.1
## [28] pryr_0.1.6 R6_2.6.1 bslib_0.9.0
## [31] stringi_1.8.4 RColorBrewer_1.1-3 pkgload_1.4.0
## [34] jquerylib_0.1.4 Rcpp_1.0.14 usethis_3.1.0
## [37] base64enc_0.1-3 leaflet.providers_2.0.0 httpuv_1.6.15
## [40] timechange_0.3.0 tidyselect_1.2.1 rstudioapi_0.17.1
## [43] abind_1.4-8 yaml_2.3.10 codetools_0.2-20
## [46] miniUI_0.1.2 pkgbuild_1.4.6 lattice_0.22-6
## [49] plyr_1.8.9 shiny_1.10.0 withr_3.0.2
## [52] evaluate_1.0.3 ggstats_0.9.0 units_0.8-7
## [55] proxy_0.4-27 urlchecker_1.0.1 xml2_1.3.6
## [58] pillar_1.10.1 KernSmooth_2.23-24 checkmate_2.3.2
## [61] insight_1.4.1 generics_0.1.3 hms_1.1.3
## [64] munsell_0.5.1 xtable_1.8-4 class_7.3-22
## [67] lazyeval_0.2.2 tools_4.4.2 data.table_1.16.4
## [70] fs_1.6.5 rapportools_1.2 grid_4.4.2
## [73] crosstalk_1.2.1 devtools_2.4.5 colorspace_2.1-1
## [76] Formula_1.2-5 cli_3.6.3 viridisLite_0.4.2
## [79] gtable_0.3.6 sass_0.4.9 digest_0.6.37
## [82] classInt_0.4-11 farver_2.1.2 htmlwidgets_1.6.4
## [85] memoise_2.0.1 htmltools_0.5.8.1 lifecycle_1.0.4
## [88] httr_1.4.7 mime_0.12 MASS_7.3-61