El presente anexo describe, de manera práctica y estructurada, la metodología utilizada para obtener la información necesaria y desarrollar el análisis solicitado en el caso de estudio sobre la adquisición de dos viviendas para una empresa internacional. Aquí se detallan los pasos aplicados para filtrar la base de datos, explorar las variables relevantes, construir el modelo de regresión lineal, validar sus supuestos y generar predicciones que permitan identificar las mejores opciones disponibles en el mercado inmobiliario según los requisitos de cada vivienda.
El objetivo de este plan es mostrar, de forma clara y ordenada, cómo se obtienen los datos y cómo se aplican las técnicas estadísticas para apoyar la toma de decisiones. Por ello, el anexo explica el proceso seguido desde la preparación de la información hasta la selección final de ofertas compatibles con el crédito preaprobado y las características solicitadas para cada vivienda.
La primera etapa del trabajo consiste en preparar la base de datos proporcionada, verificando la consistencia de las variables y filtrando únicamente aquellas viviendas que corresponden al tipo y zona solicitadas en cada caso. Para la Vivienda 1 se seleccionan las casas en la zona Norte, mientras que para la Vivienda 2 se filtran los apartamentos en la zona Sur. Este filtrado inicial permite centrar el análisis exclusivamente en los inmuebles relevantes, facilitando la exploración posterior y evitando ruido en los modelos. Adicionalmente, se verifica la ubicación geográfica mediante mapas para confirmar que los registros se encuentran dentro de las zonas esperadas.
Una vez aislados los conjuntos de viviendas pertinentes, se desarrolla un análisis exploratorio enfocado en comprender la relación entre el precio y las características físicas de las propiedades. Se evalúan variables como el área construida, el estrato, la cantidad de habitaciones, número de baños y parqueaderos. Se utilizan gráficos interactivos que permiten identificar tendencias, patrones y posibles valores atípicos. Este análisis es clave para determinar si existe una relación adecuada entre las características analizadas y el precio, y si es factible estimar un modelo de regresión con un nivel de confiabilidad suficiente.
Con base en las relaciones observadas en el análisis exploratorio, se construye un modelo de regresión lineal múltiple que estima el precio de las viviendas en función de las características más relevantes solicitadas en el enunciado. El modelo se ajusta utilizando los métodos estándar de mínimos cuadrados, y se analizan los coeficientes estimados para evaluar su significado estadístico y su coherencia con el mercado inmobiliario. Además, se revisa el valor del coeficiente de determinación (R²) para evaluar la capacidad explicativa del modelo y se discuten posibles mejoras como la inclusión de variables adicionales o transformaciones.
La siguiente etapa consiste en verificar el cumplimiento de los supuestos clásicos de la regresión lineal, tales como la normalidad de los residuos, la homocedasticidad, la ausencia de colinealidad fuerte y la independencia entre observaciones. Para ello, se revisan los gráficos de diagnóstico y se realizan pruebas complementarias como el test de Breusch-Pagan y el cálculo de los factores de inflación de varianza. En esta fase se identifican posibles problemas y se formulan recomendaciones sin necesidad de modificar el modelo, dado que el objetivo principal es la evaluación y discusión de su validez.
Después de validar la calidad del modelo, se procede a realizar predicciones para los dos casos planteados. Utilizando las características específicas de cada vivienda (tipo, área, parqueaderos, baños, habitaciones y estrato), el modelo genera una estimación del precio esperado junto con un intervalo de predicción. Este paso permite comparar los valores arrojados por el modelo con el crédito disponible para cada solicitud y determinar si resulta viable encontrar ofertas dentro del presupuesto establecido por la empresa.
Finalmente, se identifican las viviendas reales dentro de la base de datos que cumplen con las características solicitadas y cuyo precio se encuentra por debajo del límite de crédito aprobado para cada caso. Se aplica un criterio de similitud basado en las especificaciones del cliente para ordenar las opciones más convenientes. Posteriormente, se seleccionan alternativas para cada vivienda y se visualizan en un mapa geográfico que facilite el análisis comparativo y la toma de decisiones. Este conjunto de viviendas constituye la recomendación final sustentada por el análisis estadístico.
##### CARGUE DE LA INFORMACIÓN A TRABAJAR Y PAQUETES A UTILIZAR
# Instalación
# install.packages(c("tidyverse","janitor","plotly","broom","lmtest","car","leaflet","DT","GGally","sandwich"))
# install.packages("devtools")
#devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
library(broom)
library(paqueteMODELOS)
library(tidyverse)
library(janitor)
library(plotly)
library(lmtest)
library(car)
library(leaflet)
library(DT)
library(GGally)
library(sandwich)
library(htmltools)
# Carga de datos
data("vivienda")En este primer paso se realiza el filtrado inicial de la información con el fin de obtener únicamente las viviendas que son relevantes para el Caso 1. Dado que la solicitud específica corresponde a una casa ubicada en la zona Norte, se aplica un filtro sobre la base de datos original para conservar solo los registros cuyo tipo es Casa y cuya zona coincide con Zona Norte. Este proceso permite enfocar el análisis posterior únicamente en los inmuebles que cumplen con las condiciones establecidas por el cliente, evitando trabajar con datos irrelevantes o que pertenecen a otras zonas de la ciudad.
Una vez aplicado el filtro, se revisan los primeros tres registros obtenidos y se generan tablas de validación para verificar que la selección se realizó correctamente. El resultado muestra un total de 722 casas en la Zona Norte, lo cual garantiza una muestra lo suficientemente amplia para el análisis. Asimismo, la distribución por estrato revela que predominan los estratos 5 (271 registros), 3 (235), 4 (161) y 6 (55), lo que indica una mezcla socioeconómica típica de esta zona. En cuanto a los barrios, los más representativos son La Flora (99), Acopi (70), Villa del Prado (40) y El Bosque (37), entre otros.
Finalmente, se genera un mapa interactivo que permite visualizar la ubicación geográfica de todas las casas filtradas. La concentración de puntos se observa principalmente en el sector norte de la ciudad, lo que confirma que el filtro espacial funciona adecuadamente. Si bien aparecen algunos puntos ligeramente dispersos, estos se mantienen dentro del área general atribuida comercialmente a la “Zona Norte”, lo cual es coherente con la nomenclatura utilizada por el dataset. Con este paso se asegura que el análisis posterior se construya sobre un subconjunto de datos depurado y alineado con los requerimientos del caso.
# --- 1) Filtrar y crear objetos de control EN ESTE MISMO CHUNK ---
base1 <- vivienda %>%
filter(tipo == "Casa", str_detect(str_to_lower(zona), "norte")) %>%
mutate(across(c(zona, tipo), as.factor))
tab_zona <- base1 %>% count(zona, sort = TRUE)
tab_estr <- base1 %>% count(estrato, sort = TRUE)
tab_barrio <- base1 %>% count(barrio, sort = TRUE)
# --- 2) Tabla: primeros 3 registros (con título/caption) ---
DT::datatable(
base1 %>%
select(id, zona, piso, estrato, preciom, areaconst, parqueaderos, banios, habitaciones) %>%
head(3),
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Tabla 1. Primeros 3 registros – Casas en Zona Norte'
),
rownames = FALSE,
options = list(dom = 'tip', pageLength = 3)
)# --- 3) Tabla: conteo por zona ---
DT::datatable(
tab_zona %>% rename(`Zona` = zona, `N° de registros` = n),
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Tabla 2. Conteo por zona (esperado: Zona Norte)'
),
rownames = FALSE,
options = list(dom = 'tip', pageLength = 5)
)# --- 4) Tabla: conteo por estrato ---
DT::datatable(
tab_estr %>% rename(`Estrato` = estrato, `N° de registros` = n),
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Tabla 3. Conteo por estrato – Subconjunto Casas Zona Norte'
),
rownames = FALSE,
options = list(dom = 'tip', pageLength = 5)
)# --- 5) Tabla: top 10 barrios ---
DT::datatable(
tab_barrio %>%
rename(`Barrio` = barrio, `N° de registros` = n) %>%
head(10),
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Tabla 4. Top 10 barrios con mayor número de registros – Casas Zona Norte'
),
rownames = FALSE,
options = list(dom = 'tip', pageLength = 10)
)base1_map <- base1 %>% drop_na(longitud, latitud)
if (nrow(base1_map) > 0) {
leaflet(base1_map) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 6, color = "#1f77b4", fillOpacity = 0.85,
popup = ~paste0(
"<b>Casa – ", barrio, "</b><br>",
"Estrato: ", estrato, " | Zona: ", zona, "<br>",
"Área: ", areaconst, " m² | Hab.: ", habitaciones,
" | Baños: ", banios, " | Parq.: ", parqueaderos, "<br>",
"<b>Precio: </b>$", formatC(preciom, big.mark=".", format="d"), " millones"
)
)
}En este paso se exploran las relaciones entre el precio (millones de COP) y las variables consideradas como posibles determinantes del valor de los inmuebles: área construida, estrato, número de baños, número de habitaciones y zona. Para ello se construyeron gráficos interactivos que permiten identificar tendencias, niveles y posibles valores atípicos: (i) un diagrama de dispersión Precio vs. Área coloreado por estrato, (ii) un boxplot de precio por zona, y (iii) una matriz de pares con correlaciones entre las variables numéricas.
Los resultados muestran, primero, una relación positiva entre área construida y precio, con gradientes de color que evidencian que los inmuebles de estratos más altos tienden a ubicarse en los niveles superiores de precio. En la matriz de pares se observa una correlación moderada-alta entre precio y área (≈ 0.69), así como entre precio y baños (≈ 0.67) y entre precio y estrato (≈ 0.61). La relación entre precio y habitaciones es más débil (≈ 0.26), lo que sugiere que “habitaciones” aporta información, pero menor que la que proveen área, baños o estrato. Además, se aprecia colinealidad moderada entre algunas explicativas (p. ej., área–baños ≈ 0.65, área–habitaciones ≈ 0.52, baños–habitaciones ≈ 0.59), algo esperable porque mayor tamaño suele venir acompañado de más ambientes y sanitarios.
El boxplot por zona indica diferencias de nivel en los precios: hay zonas con medianas e intercuartiles sensiblemente superiores (p. ej., la distribución de Zona Oeste se ubica, en general, por encima de otras), mientras que Zona Sur presenta mayor dispersión y valores altos en cola. Este patrón respalda la conveniencia de controlar por zona (o barrio) en versiones alternativas del modelo, dado que la ubicación captura efectos de accesibilidad, oferta de servicios y segmentación del mercado.
En conjunto, el EDA confirma que existe estructura suficiente para estimar un modelo de regresión lineal con precio ~ área + estrato + baños + habitaciones + parqueaderos. Sin embargo, los gráficos sugieren dispersión creciente del precio a medida que aumenta el nivel (posible heterocedasticidad) y la presencia de outliers en áreas y precios altos; por ello, más adelante se verifican supuestos con pruebas formales y, de ser necesario, se recomendará usar errores estándar robustos o considerar una transformación logarítmica del precio como alternativa de mejora.
eda_df <- vivienda %>%
select(preciom, areaconst, estrato, banios, habitaciones, zona, tipo) %>%
drop_na()
# Dispersión interactiva: Precio vs Área (color por estrato)
g1 <- ggplot(eda_df, aes(areaconst, preciom, color = factor(estrato), text = paste("Zona:", zona))) +
geom_point(alpha = 0.7) +
scale_color_brewer(palette = "Set1", name = "Estrato") +
theme_minimal() +
labs(title = "Precio vs Área (color = estrato)", x = "Área construida (m²)", y = "Precio (millones COP)")
ggplotly(g1, tooltip = c("x","y","colour","text"))Se estimó un modelo de regresión lineal de mínimos cuadrados con la forma:
\[ \text{precio (millones COP)} \sim \text{área construida} + \text{estrato} + \text{habitaciones} + \text{parqueaderos} + \text{baños}. \]
El modelo logra un R² = 0.721 (R² ajustado = 0.720), lo que indica que explica aproximadamente el 72% de la variabilidad del precio observada en la base. El estadístico F = 3462 (p < 2.2e-16) confirma que, en conjunto, las variables incluidas tienen poder explicativo significativo. Magnitud y dirección de los efectos. Todos los predictores son significativos a niveles convencionales (p < 0.001), con los siguientes efectos marginales (ceteris paribus):
Área construida: coef. 0.851 ⇒ cada m² adicional se asocia, en promedio, con +0.851 millones COP en el precio, manteniendo constantes las demás variables. Este es el principal impulsor continuo del precio.
Estrato: coef. 97.91 ⇒ subir un nivel de estrato (p. ej., de 4 a 5) se asocia con +97.9 millones COP. Refleja la prima socioeconómica y de amenidades del entorno.
Parqueaderos: coef. 74.49 ⇒ cada parqueadero adicional se asocia con +74.5 millones COP, consistente con mayor comodidad y con inmuebles de mayor tamaño/segmento.
Baños: coef. 61.06 ⇒ cada baño adicional con +61.1 millones COP; suele capturar calidad y tamaño interno.
Habitaciones: coef. −31.27 ⇒ cada habitación adicional se asocia con −31.3 millones COP, manteniendo fija el área. Aunque contraintuitivo a primera vista, este signo es coherente cuando el área se mantiene constante: más habitaciones en la misma superficie implica dividir el espacio (ambientes más pequeños), lo que puede reducir el precio a igualdad de metros, estrato y baños. Otra posibilidad es colinealidad con área/baños: aunque no invalida el modelo, sugiere revisar VIF en el Paso 4 y, si fuese alto, considerar ajustes (p. ej., remover/combinar o centrar variables).
Intercepto. El intercepto (−380.76) carece de interpretación directa de mercado (precio cuando todas las explicativas son 0), pero es necesario para el ajuste del plano. Lectura global. Los signos y magnitudes son lógicos para el mercado inmobiliario: precio crece con tamaño (área), nivel socioeconómico (estrato) y amenidades (baños, parqueaderos). La señal negativa en habitaciones es consistente con el trade-off de distribución del espacio a área fija. En la siguiente sección (Paso 4) se verifican heterocedasticidad, colinealidad y normalidad de residuos; de detectarse heterocedasticidad, se recomienda reportar errores estándar robustos (HC3) y considerar una versión log-lineal como alternativa.
mod_df <- vivienda %>%
select(preciom, areaconst, estrato, habitaciones, parqueaderos, banios) %>%
drop_na()
m_base <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = mod_df)
coef_tab <- tidy(m_base, conf.int = TRUE) %>%
mutate(across(where(is.numeric), ~round(.x, 3))) %>%
rename(
Termino = term, Estimador = estimate, `EE (Std.)` = std.error,
`t` = statistic, `p-valor` = p.value, `IC95% Inf` = conf.low, `IC95% Sup` = conf.high
)
DT::datatable(
coef_tab,
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Coeficientes del modelo de regresión (estimador, EE, t, p e IC 95%)'
),
options = list(pageLength = 10, dom = 'tip'),
rownames = FALSE
)# Resumen del modelo para extraer F y g.l.
sum_lm <- summary(m_base)
fs <- sum_lm$fstatistic
numdf <- unname(fs["numdf"]) # gl1 (numerador)
dendf <- unname(fs["dendf"]) # gl2 (denominador)
fval <- unname(fs["value"]) # valor de F
# p-valor del F con gl correctos
pval_F <- stats::pf(fval, numdf, dendf, lower.tail = FALSE)
# Tabla de métricas con g.l. correctos
glance_tab <- glance(m_base) %>%
transmute(
`R²` = round(r.squared, 3),
`R² ajustado` = round(adj.r.squared, 3),
`Error estándar resid.` = round(sigma, 3),
`F-statistic` = round(fval, 1),
`g.l. (num y den)` = paste0(numdf, " y ", dendf),
`p-valor (modelo)` = format.pval(pval_F, digits = 3, eps = .001)
)
DT::datatable(
glance_tab,
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Métricas globales del modelo (R², R² ajustado, σ, F, g.l. y p-valor)'
),
options = list(dom = 't'),
rownames = FALSE
)Los gráficos de diagnóstico sugieren heterocedasticidad (patrón en abanico y pendiente en Scale-Location) y no normalidad de residuos en colas; esto se confirma con el test de Breusch–Pagan (BP = 1212.2; p < 0.001). La multicolinealidad no es problemática (VIF entre 1.55 y 2.81), por lo que los coeficientes son estables e interpretables. Se identifican algunas observaciones con mayor leverage, sin evidencia de dominancia severa. Recomendación: reportar la inferencia con errores estándar robustos (HC3) y considerar como mejora un modelo log-lineal de preciom y/o la incorporación de controles espaciales (zona/barrio). Estas acciones suelen reducir la heterocedasticidad y mejorar la capacidad explicativa en mercados inmobiliarios.
# Diagnóstico visual
op <- par(mfrow=c(2,2)); plot(m_base); par(op) # Residuos vs ajustados, QQ, etc.# Heterocedasticidad (Breusch–Pagan)
bp_test <- bptest(m_base)
bp_tab <- tidy(bp_test) |>
mutate(
statistic = round(statistic, 1),
p.value = format.pval(p.value, digits = 3, eps = .001),
parameter = as.integer(parameter)
) |>
dplyr::rename(
`Prueba` = method,
`Estadístico BP` = statistic,
`gl` = parameter,
`p-valor` = p.value
)
DT::datatable(
bp_tab[, c("Prueba","Estadístico BP","gl","p-valor")],
caption = tags$caption(style='caption-side: top; text-align:left; font-weight:bold;',
'Test de heterocedasticidad Breusch–Pagan'),
options = list(dom='t'),
rownames = FALSE
)# 4.3 VIF
library(car)
vif_tab <- tibble::tibble(
Variable = names(car::vif(m_base)),
VIF = as.numeric(car::vif(m_base))
) |>
dplyr::mutate(VIF = round(VIF, 3))
DT::datatable(
vif_tab,
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Factores de inflación de varianza (VIF)'
),
options = list(dom='t'),
rownames = FALSE
)Utilizando el modelo de regresión estimado, se realizó la predicción del precio esperado para una vivienda con las características solicitadas por el cliente (200 m², 1 parqueadero, 2 baños, 4 habitaciones) bajo dos posibles escenarios de estrato: 4 y 5.
Para estrato 4, el modelo estima un precio aproximado de 252.6 millones COP, con un intervalo de predicción del 95% entre –94.8 millones y 599.9 millones. El intervalo amplio refleja la alta variabilidad del precio en viviendas de este segmento, propia del mercado inmobiliario.
Para estrato 5, el precio estimado es de 350.5 millones COP, con un intervalo de predicción entre 3.1 millones y 697.9 millones. En este caso, el valor puntual se encuentra exactamente en el límite del crédito disponible (350 millones COP), lo que sugiere que las opciones en estrato 5 estarán más ajustadas al presupuesto del cliente.
# Datos nuevos para predicción
new_v1_e4 <- data.frame(areaconst=200, estrato=4, habitaciones=4, parqueaderos=1, banios=2)
new_v1_e5 <- data.frame(areaconst=200, estrato=5, habitaciones=4, parqueaderos=1, banios=2)
# Predicciones
pred_v1_e4 <- predict(m_base, newdata = new_v1_e4, interval = "prediction", level = 0.95)
pred_v1_e5 <- predict(m_base, newdata = new_v1_e5, interval = "prediction", level = 0.95)
# Crear tablas limpias
tab_pred1 <- data.frame(
Estrato = 4,
Estimado = round(pred_v1_e4[1, "fit"], 3),
Límite_inferior = round(pred_v1_e4[1, "lwr"], 3),
Límite_superior = round(pred_v1_e4[1, "upr"], 3)
)
tab_pred2 <- data.frame(
Estrato = 5,
Estimado = round(pred_v1_e5[1, "fit"], 3),
Límite_inferior = round(pred_v1_e5[1, "lwr"], 3),
Límite_superior = round(pred_v1_e5[1, "upr"], 3)
)
tabla_pred <- rbind(tab_pred1, tab_pred2)
DT::datatable(
tabla_pred,
caption = htmltools::tags$caption(
style="caption-side: top; text-align:left; font-weight:bold;",
"Predicción del precio para la Vivienda 1 (200 m², 1 parqueadero, 2 baños, 4 habitaciones)"
),
rownames = FALSE,
options = list(dom='t')
)Se filtraron las viviendas de tipo Casa ubicadas en Zona Norte que cumplen con los mínimos solicitados por el cliente (área ≈ 200 m², ≥1 parqueadero, ≥2 baños, ≥4 habitaciones, estrato 4–5) y con precio ≤ 350 millones. A partir de ese subconjunto se construyó un índice de similitud (score) que prioriza: cercanía al área objetivo, cumplimiento de amenidades mínimas y precio competitivo dentro del presupuesto. Con este criterio se ordenaron las opciones y se seleccionaron las Top 5 ofertas, presentadas en la Tabla 12 y en el Mapa 2.
En los resultados observados, destacan inmuebles en barrios como el bosque, la flora y la merced, con áreas cercanas a 200 m² y precios entre 320 y 350 millones, lo que los ubica dentro o muy cerca del límite de crédito. Estas alternativas cumplen las condiciones del caso y representan buenas candidatas para visita técnica y negociación, especialmente aquellas con mayor número de baños o más parqueaderos al mismo precio (mejor relación valor/amenidades). Si se requiere ampliar el abanico de opciones, se sugiere aplicar una tolerancia de ±10–15% al área objetivo manteniendo el mismo tope de precio, lo cual incrementa la disponibilidad sin sacrificar los criterios principales del cliente.
# 6.1 Definir criterios del caso 1
target_v1 <- list(
tipo = "Casa",
zona_pat = "norte",
credito = 350,
area = 200,
estr = c(4, 5),
p = 1, # parqueaderos mínimos
b = 2, # baños mínimos
h = 4 # habitaciones mínimas
)
# 6.2 Candidatas que cumplen criterios y presupuesto
cand_v1 <- vivienda %>%
filter(tipo == target_v1$tipo,
str_detect(str_to_lower(zona), target_v1$zona_pat),
preciom <= target_v1$credito,
estrato %in% target_v1$estr,
parqueaderos >= target_v1$p,
banios >= target_v1$b,
habitaciones >= target_v1$h) %>%
mutate(
# Score: proximidad al área objetivo y penalizaciones suaves
score = abs(areaconst - target_v1$area) * 0.5 +
pmax(0, target_v1$p - parqueaderos) * 10 +
pmax(0, target_v1$b - banios) * 8 +
pmax(0, target_v1$h - habitaciones) * 6 +
(max(preciom, na.rm = TRUE) - preciom) * 0.02
) %>%
arrange(score)
# 6.3 Tomar Top 5 (o menos si no hay suficientes)
top5_v1 <- cand_v1 %>% slice_head(n = 5)
# 6.4 Tabla formateada con título
DT::datatable(
top5_v1 %>%
select(barrio, zona, estrato, areaconst, habitaciones, banios, parqueaderos, preciom),
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Top 5 ofertas – Vivienda 1 (≤ 350M)'
),
rownames = FALSE,
options = list(dom = 'tip', pageLength = 5)
)top5_v1_map <- top5_v1 %>% drop_na(longitud, latitud)
if (nrow(top5_v1_map) > 0) {
leaflet(top5_v1_map) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 8, color = "#2ca02c", fillOpacity = 0.9,
popup = ~paste0(
"<b>Casa – ", barrio, "</b><br>",
"Estrato: ", estrato, " | Zona: ", zona, "<br>",
"Área: ", areaconst, " m² | Hab.: ", habitaciones,
" | Baños: ", banios, " | Parq.: ", parqueaderos, "<br>",
"<b>Precio: </b>$", formatC(preciom, big.mark = ".", format = "d"), " millones"
)
)
} else {
cat("> Nota: Las ofertas Top 5 no cuentan con coordenadas completas para mapearse.\n")
}En este primer paso se filtraron las viviendas correspondientes a Apartamentos ubicados en la Zona Sur, tal como exige el caso 2. El subconjunto resultante contiene 2787 registros, lo cual constituye una base suficientemente amplia para realizar análisis y recomendaciones confiables.
Los primeros registros muestran apartamentos con características diversas en área construida (entre 40 m² y 194 m²), estratos entre 3 y 6 y precios desde 78 millones hasta 875 millones de pesos, lo que confirma la heterogeneidad del mercado del sur de la ciudad.
La tabla de conteo por zona confirma que todos los registros pertenecen efectivamente a Zona Sur. En cuanto al estrato, la mayoría de los apartamentos están ubicados en los estratos 4 (1091 registros) y 5 (1033 registros), seguidos por estrato 6 (462) y 3 (201). Este comportamiento es coherente con la composición socioeconómica de los principales sectores residenciales del sur.
Respecto a los barrios, los de mayor frecuencia son Valle del Lili (837 registros), Ciudad Jardín (218), Pance (205), El Ingenio (128) y El Caney (124). Estas zonas concentran una alta oferta de vivienda vertical orientada a segmentos medios y altos.
Finalmente, el mapa confirma que las viviendas filtradas se distribuyen en el corredor sur de la ciudad, incluyendo sectores consolidados y en expansión. La distribución espacial es coherente con el filtro aplicado, sin evidencias de registros ubicados fuera del área esperada.
# 1) Filtrar Apartamentos en Zona Sur
base2 <- vivienda %>%
filter(tipo == "Apartamento",
str_detect(str_to_lower(zona), "sur")) %>%
mutate(across(c(zona, tipo), as.factor))
# ================================
# TABLAS CON TÍTULO USANDO DT
# ================================
# Primeros 3 registros
DT::datatable(
base2 %>%
select(id, zona, piso, estrato, preciom, areaconst, parqueaderos, banios, habitaciones) %>%
head(3),
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Primeros 3 registros — Apartamentos Zona Sur'
),
rownames = FALSE,
options = list(dom='tip', pageLength=3)
)# Tablas de control
tab2_zona <- base2 %>% count(zona, sort = TRUE)
tab2_estr <- base2 %>% count(estrato, sort = TRUE)
tab2_barrio <- base2 %>% count(barrio, sort = TRUE)
# Conteo por zona
DT::datatable(
tab2_zona %>% rename(Zona = zona, `N° de registros` = n),
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Conteo por zona — Apartamentos Zona Sur'
),
rownames = FALSE,
options = list(dom='t')
)# Conteo por estrato
DT::datatable(
tab2_estr %>% rename(Estrato = estrato, `N° de registros` = n),
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Conteo por estrato — Apartamentos Zona Sur'
),
rownames = FALSE,
options = list(dom='t')
)# Top 10 barrios
DT::datatable(
tab2_barrio %>% rename(Barrio = barrio, `N° de registros` = n) %>% head(10),
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Top 10 barrios — Apartamentos Zona Sur'
),
rownames = FALSE,
options = list(dom='tip', pageLength=10)
)base2_map <- base2 %>% drop_na(longitud, latitud)
if (nrow(base2_map) > 0) {
leaflet(base2_map) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 6, color = "#d62728", fillOpacity = 0.85,
popup = ~paste0(
"<b>Apartamento – ", barrio, "</b><br>",
"Estrato: ", estrato, " | Zona: ", zona, "<br>",
"Área: ", areaconst, " m² | Hab.: ", habitaciones,
" | Baños: ", banios, " | Parq.: ", parqueaderos, "<br>",
"<b>Precio: </b>$",
formatC(preciom, big.mark=".", format="d"), " millones"
)
)
} else {
cat("> Nota: las unidades filtradas no cuentan con coordenadas para el mapa.")
}En este paso se exploran las relaciones entre el precio (millones de COP) y las variables que, por teoría de mercado, influyen en su formación: área construida, estrato, número de baños, número de habitaciones y zona. Para ello se construyeron tres vistas: (i) un diagrama de dispersión de Precio vs. Área coloreado por estrato (interactivo), (ii) un boxplot del precio por zona, y (iii) una matriz de pares con dispersogramas, densidades y correlaciones entre las variables numéricas.
Los resultados indican una relación positiva clara entre área construida y precio; a medida que aumenta el metraje, el valor tiende a subir. El color por estrato muestra una estratificación de niveles: los puntos de estratos más altos se concentran en precios superiores para áreas comparables, lo que refleja primas de localización, amenidades y segmentación del mercado en el sur de la ciudad. El boxplot por zona evidencia diferencias de nivel en el precio entre zonas (medianas e intercuartiles distintos), con colas superiores que confirman la presencia de inmuebles de alto valor en algunos sectores.
La matriz de pares muestra correlaciones que respaldan la especificación del modelo lineal: precio–área (~0.69), precio–baños (~0.67) y precio–estrato (~0.61) son asociaciones moderadas a altas y positivas; precio–habitaciones es más débil (~0.26), lo cual sugiere que “habitaciones” aporta información pero menos que área, baños o estrato. Entre explicativas, se aprecia colinealidad moderada (p. ej., área–baños ~0.65; área–habitaciones ~0.52; baños–habitaciones ~0.59), razonable porque inmuebles más grandes suelen tener más ambientes y sanitarios. Estas relaciones justifican el uso de un modelo de regresión lineal múltiple con las variables del enunciado y anticipan una posible heterocedasticidad (dispersión creciente del precio en niveles altos), que será verificada en el Paso 4.
eda2_df <- vivienda %>%
select(preciom, areaconst, estrato, banios, habitaciones, zona, tipo) %>%
drop_na()
# Dispersión interactiva: Precio vs Área (color por estrato)
g1_2 <- ggplot(eda2_df, aes(areaconst, preciom, color = factor(estrato), text = paste("Zona:", zona))) +
geom_point(alpha = 0.7) +
scale_color_brewer(palette = "Set1", name = "Estrato") +
theme_minimal() +
labs(title = "Precio vs Área (color = estrato)", x = "Área construida (m²)", y = "Precio (millones COP)")
ggplotly(g1_2, tooltip = c("x","y","colour","text"))Para el Caso 2 se estimó un modelo de regresión lineal múltiple con el fin de explicar el precio de los apartamentos de la ciudad a partir de variables físicas (área, habitaciones, baños, parqueaderos) y socioeconómicas (estrato). El modelo presenta un R² = 0.7206 (ajustado = 0.7204), lo que indica que aproximadamente el 72% de la variabilidad del precio se explica por las variables consideradas. Este nivel de ajuste es adecuado para datos inmobiliarios, donde la heterogeneidad de mercado suele introducir variabilidad adicional no observable.
Todos los coeficientes son estadísticamente significativos (p < 0.001):
Área construida (coef = 0.851): por cada metro cuadrado adicional, el precio aumenta en 0.851 millones de pesos, manteniendo constantes las demás variables.
Estrato (coef = 97.91): subir un nivel de estrato aumenta el precio en 97.9 millones, lo cual refleja una prima por ubicación, seguridad, infraestructura y servicios del sector.
Parqueaderos (coef = 74.49): cada parqueadero adicional incrementa el valor en 74.5 millones, lo que indica que este atributo es altamente valorado en apartamentos del sur.
Baños (coef = 61.06): cada baño adicional añade en promedio 61.1 millones al valor de la vivienda.
Habitaciones (coef = –31.27): el coeficiente negativo indica que, manteniendo fija el área, un mayor número de habitaciones implica dividir el espacio, reduciendo el tamaño de cada ambiente; esto se traduce en una penalización en precio. Esta interpretación es coherente y no producto de colinealidad, ya que los VIF del Paso 4 son bajos.
El intercepto (–380.76) no tiene interpretación económica directa, pero es necesario para la estimación del modelo.
En síntesis, el modelo confirma que área, estrato, parqueaderos y baños son los principales impulsores del precio de apartamentos en la ciudad, mientras que habitaciones actúa como un factor de distribución interna del espacio. Este modelo será usado en el Paso 5 para predecir el precio de la vivienda solicitada por el cliente (300 m², 3 parqueaderos, 3 baños, 5 habitaciones, estrato 5–6).
# Dataset para el modelo
mod_df2 <- vivienda %>%
select(preciom, areaconst, estrato, habitaciones, parqueaderos, banios) %>%
drop_na()
# Modelo base
m_base2 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios,
data = mod_df2)
# Tabla de coeficientes
coef_tab2 <- tidy(m_base2, conf.int = TRUE) %>%
mutate(across(where(is.numeric), ~ round(.x, 3))) %>%
rename(
Término = term,
Estimador = estimate,
`EE (Std.)` = std.error,
`t` = statistic,
`p-valor` = p.value,
`IC 95% inf` = conf.low,
`IC 95% sup` = conf.high
)
DT::datatable(
coef_tab2,
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Coeficientes del modelo de regresión – Caso 2'
),
rownames = FALSE,
options = list(dom='tip', pageLength=10)
)glance_tab2 <- glance(m_base2) %>%
transmute(
`R²` = round(r.squared, 3),
`R² ajustado` = round(adj.r.squared, 3),
`Error estándar resid.` = round(sigma, 3),
`F-statistic` = round(statistic, 1),
`p-valor (modelo)` = format.pval(p.value, digits = 3)
)
DT::datatable(
glance_tab2,
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Métricas globales del modelo – Caso 2'
),
rownames = FALSE,
options = list(dom='t')
)Validación de supuestos (Caso 2). Los gráficos de diagnóstico muestran heterocedasticidad (abanico en Residuals vs Fitted y pendiente en Scale‑Location) y desvíos en colas en el QQ‑plot. El test de Breusch–Pagan confirma el hallazgo (BP = 1212.2; p < 0.001). Los VIF se sitúan entre 1.55 y 2.81, lo que descarta colinealidad preocupante. En consecuencia, la inferencia se reporta con errores estándar robustos (HC3) y se recomienda, como mejora del modelo, considerar una especificación log‑lineal del precio y/o incluir controles por ubicación (zona/barrio) para capturar mejor la variabilidad espacial del mercado en la Zona Sur.
par(op)
# Breusch–Pagan con título
bp2 <- bptest(m_base2)
bp2_tab <- tidy(bp2) |>
mutate(
statistic = round(statistic, 1),
p.value = format.pval(p.value, digits = 3, eps = .001),
parameter = as.integer(parameter)
) |>
rename(`Prueba` = method, `Estadístico BP` = statistic, `gl` = parameter, `p-valor` = p.value)
DT::datatable(
bp2_tab[, c("Prueba","Estadístico BP","gl","p-valor")],
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Test de heterocedasticidad Breusch–Pagan — Caso 2'
),
options = list(dom='t'),
rownames = FALSE
)# VIF con título
vifs2_vals <- car::vif(m_base2)
vifs2_tab <- tibble::tibble(Variable = names(vifs2_vals), VIF = as.numeric(vifs2_vals)) |>
mutate(VIF = round(VIF, 3))
DT::datatable(
vifs2_tab,
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Factores de inflación de varianza (VIF) — Caso 2'
),
options = list(dom='t'),
rownames = FALSE
)# Coeficientes con errores estándar robustos (HC3)
robust2 <- lmtest::coeftest(m_base2, vcov = sandwich::vcovHC(m_base2, type = "HC3"))
robust2_tab <- broom::tidy(robust2) |>
rename(
Término = term, Estimador = estimate, `EE robusto (HC3)` = std.error,
`t` = statistic, `p-valor` = p.value
) |>
mutate(across(where(is.numeric), ~ round(.x, 3)))
DT::datatable(
robust2_tab,
caption = htmltools::tags$caption(
style='caption-side: top; text-align:left; font-weight:bold;',
'Coeficientes con errores estándar robustos (HC3) — Caso 2'
),
options = list(dom='tip', pageLength = 10),
rownames = FALSE
)Predicción del precio — Vivienda 2. Se estimó el precio esperado para un apartamento con 300 m², 3 parqueaderos, 3 baños y 5 habitaciones en dos escenarios de estrato (5 y 6).
Para estrato 5, el valor puntual estimado es de 614.36 millones de COP, con un intervalo de predicción (95%) entre 266.94 y 961.79 millones.
Para estrato 6, el valor puntual estimado asciende a 712.27 millones de COP, con IC95% entre 364.76 y 1059.79 millones.
Comparación con el crédito (≤ 850M): ambos escenarios presentan valores puntuales por debajo del límite de 850M, por lo que la compra es viable según el modelo. No obstante, los límites superiores del intervalo (especialmente en estrato 6) superan el tope de crédito, lo que sugiere que, en el mercado real, podrían encontrarse propiedades similares con precios por encima del presupuesto.
# Datos nuevos para la predicción
new_v2_e5 <- data.frame(areaconst = 300, estrato = 5, habitaciones = 5, parqueaderos = 3, banios = 3)
new_v2_e6 <- data.frame(areaconst = 300, estrato = 6, habitaciones = 5, parqueaderos = 3, banios = 3)
# Predicciones con intervalo de predicción 95%
pred_v2_e5 <- predict(m_base2, newdata = new_v2_e5, interval = "prediction", level = 0.95)
pred_v2_e6 <- predict(m_base2, newdata = new_v2_e6, interval = "prediction", level = 0.95)
# Construir tabla consolidada
tabla_pred_v2 <- rbind(
data.frame(Estrato = 5,
Estimado_M = round(pred_v2_e5[,"fit"], 3),
LI_95_M = round(pred_v2_e5[,"lwr"], 3),
LS_95_M = round(pred_v2_e5[,"upr"], 3)),
data.frame(Estrato = 6,
Estimado_M = round(pred_v2_e6[,"fit"], 3),
LI_95_M = round(pred_v2_e6[,"lwr"], 3),
LS_95_M = round(pred_v2_e6[,"upr"], 3))
)
DT::datatable(
tabla_pred_v2,
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Predicción del precio — Vivienda 2 (300 m², 3 parq., 3 baños, 5 hab.)'
),
rownames = FALSE,
options = list(dom = 't')
)Se filtraron apartamentos en Zona Sur que cumplen con las condiciones mínimas del cliente (≈ 300 m², ≥ 3 parqueaderos, ≥ 3 baños, ≥ 5 habitaciones, estrato 5–6) y cuyo precio es ≤ 850 millones. Sobre el subconjunto resultante se construyó un índice de similitud que prioriza: (i) cercanía al área objetivo, (ii) cumplimiento de amenidades mínimas y (iii) mejor relación precio dentro del presupuesto. Con este criterio se ordenaron las opciones y se seleccionaron las mejores ofertas.
En los resultados observados, destacan alternativas en Seminario y Guadalupe, con precios entre 530 y 730 millones y atributos superiores al mínimo (hasta 5 baños y 8 baños en el caso de la unidad de mayor metraje), lo que las ubica holgadamente dentro del crédito ≤ 850M. Estas propiedades son candidatas sólidas para visita técnica y negociación, priorizando aquellas con mejor equilibrio entre metraje, parqueaderos y número de baños al mismo nivel de precio. Si se requiriese ampliar el abanico (pocas coincidencias exactas con 300 m²), es razonable considerar una tolerancia de ±10–15% en área manteniendo el tope de precio.
# 6.1 Criterios del Caso 2
target_v2 <- list(
tipo = "Apartamento",
zona_pat = "sur",
credito = 850,
area = 300,
estr = c(5, 6),
p = 3, # parqueaderos mínimos
b = 3, # baños mínimos
h = 5 # habitaciones mínimas
)
# 6.2 Candidatas que cumplen criterios y presupuesto
cand_v2 <- vivienda %>%
filter(tipo == target_v2$tipo,
str_detect(str_to_lower(zona), target_v2$zona_pat),
preciom <= target_v2$credito,
estrato %in% target_v2$estr,
parqueaderos >= target_v2$p,
banios >= target_v2$b,
habitaciones >= target_v2$h) %>%
mutate(
score = abs(areaconst - target_v2$area) * 0.5 +
pmax(0, target_v2$p - parqueaderos) * 10 +
pmax(0, target_v2$b - banios) * 8 +
pmax(0, target_v2$h - habitaciones) * 6 +
(max(preciom, na.rm = TRUE) - preciom) * 0.02
) %>%
arrange(score)
# 6.3 Top 5 (o menos si el filtro devuelve <5)
top5_v2 <- cand_v2 %>% slice_head(n = 5)
# 6.4 Tabla con título
DT::datatable(
top5_v2 %>%
select(barrio, zona, estrato, areaconst, habitaciones, banios, parqueaderos, preciom),
caption = htmltools::tags$caption(
style = 'caption-side: top; text-align: left; font-weight: bold;',
'Top ofertas — Vivienda 2 (≤ 850M, ordenadas por “score” de similitud)'
),
rownames = FALSE,
options = list(dom = 'tip', pageLength = 5)
)top5_v2_map <- top5_v2 %>% drop_na(longitud, latitud)
if (nrow(top5_v2_map) > 0) {
leaflet(top5_v2_map) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 8, color = "#d62728", fillOpacity = 0.9,
popup = ~paste0(
"<b>Apartamento – ", barrio, "</b><br>",
"Estrato: ", estrato, " | Zona: ", zona, "<br>",
"Área: ", areaconst, " m² | Hab.: ", habitaciones,
" | Baños: ", banios, " | Parq.: ", parqueaderos, "<br>",
"<b>Precio: </b>$", formatC(preciom, big.mark=".", format="d"), " millones"
)
)
} else {
cat("> Nota: las ofertas seleccionadas no cuentan con latitud/longitud completas para visualizar el mapa.\n")
}El presente informe ejecutivo resume los hallazgos más relevantes del análisis realizado para apoyar a la empresa C&A (Casas y Apartamentos) en la selección de dos inmuebles solicitados por una compañía internacional que trasladará a dos de sus funcionarios a la ciudad. El objetivo del estudio fue identificar alternativas de vivienda que cumplieran con criterios específicos de área construida, estrato socioeconómico, número de habitaciones, baños, parqueaderos y ubicación geográfica, considerando además el límite de crédito preaprobado para cada caso.
Para garantizar una recomendación sustentada en evidencia, se empleó un proceso analítico estructurado que incluyó:
Filtrado y preparación de los datos.
Análisis exploratorio de variables relevantes.
Estimación de un modelo de regresión lineal múltiple para explicar el precio de las viviendas.
Validación de supuestos estadísticos.
Predicción del precio de los inmuebles solicitados.
Selección final de ofertas reales del mercado que se ajustan a las necesidades de cada caso.
Todo el análisis se fundamentó en la base de datos de vivienda suministrada, correspondiente a las ofertas publicadas en los últimos meses, lo que permite una lectura actualizada del comportamiento del mercado inmobiliario en las zonas Norte y Sur de la ciudad. A partir de los resultados del modelo y de la exploración de la información geográfica y descriptiva, se identificaron opciones concretas que representan oportunidades reales y viables para la empresa.
El análisis realizado para el Caso 1 permitió identificar viviendas en la Zona Norte que cumplen con los criterios solicitados por la empresa: casa de aproximadamente 200 m², 1 parqueadero, 2 baños, 4 habitaciones, estrato 4 o 5, y con un límite de crédito de 350 millones de pesos.
A partir del modelo de regresión lineal, se estimó el precio esperado de una vivienda con las características solicitadas bajo dos escenarios de estrato:
Estrato 4:
Precio estimado: ≈ 252.6 millones COP Intervalo de predicción 95%: –94.8 a 599.9 millones COP
Estrato 5:
Precio estimado: ≈ 350.5 millones COP Intervalo de predicción 95%: 3.1 a 697.9 millones COP
El valor estimado para estrato 5 cae exactamente en el límite del crédito disponible, lo cual indica que el presupuesto asignado es suficiente, aunque con poco margen para cubrir variaciones del mercado. Estrato 4 ofrece mayor holgura presupuestal, pero es menos consistente con el perfil socioeconómico predominante en la zona.
Luego del filtrado de las viviendas en la Zona Norte y la aplicación del índice de similitud basado en área, estrato y amenidades mínimas, se identificaron cinco viviendas que cumplen con las condiciones del cliente y cuyo precio se ubica dentro del rango permitido (≤ 350M). Las ofertas se concentran en los barrios El Bosque, La Flora y La Merced, zonas tradicionalmente residenciales con buena accesibilidad y oferta de servicios.
Características destacadas de las mejores opciones identificadas:
Áreas entre 200 y 203 m², alineadas con el objetivo solicitado.
Estratos 4 y 5, cumpliendo adecuadamente el perfil deseado.
Valores entre 320 y 350 millones, dentro del crédito preaprobado.
Variaciones positivas en amenidades:
Conclusión clave:
El mercado de la Zona Norte ofrece opciones coherentes con el presupuesto del cliente. Las alternativas identificadas proporcionan un equilibrio adecuado entre área, localización y amenidades, por lo que se recomienda avanzar con visitas técnicas para validar condiciones físicas, estado de mantenimiento, entorno y posibilidad de negociación del precio.
A partir de la predicción del modelo y del análisis de oferta disponible, se concluye que:
La compra de una casa en la Zona Norte con las especificaciones solicitadas es viable dentro del presupuesto.
Las ofertas identificadas en los barrios El Bosque, La Flora y La Merced cumplen con todas las condiciones del cliente.
Se recomienda priorizar las viviendas con más parqueaderos y mayor número de baños, ya que presentan una mejor relación valor–amenidades y mayor potencial de valorización.
top5_v1_map <- top5_v1 %>% drop_na(longitud, latitud)
if (nrow(top5_v1_map) > 0) {
leaflet(top5_v1_map) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 8, color = "#2ca02c", fillOpacity = 0.9,
popup = ~paste0(
"<b>Casa – ", barrio, "</b><br>",
"Estrato: ", estrato, " | Zona: ", zona, "<br>",
"Área: ", areaconst, " m² | Hab.: ", habitaciones,
" | Baños: ", banios, " | Parq.: ", parqueaderos, "<br>",
"<b>Precio: </b>$", formatC(preciom, big.mark = ".", format = "d"), " millones"
)
)
} else {
cat("> Nota: Las ofertas Top 5 no cuentan con coordenadas completas para mapearse.\n")
}El análisis del Caso 2 tuvo como objetivo identificar apartamentos ubicados en la Zona Sur que cumplieran con los criterios solicitados: aproximadamente 300 m², 3 parqueaderos, 3 baños, 5 habitaciones, estrato 5 o 6, y con un límite de crédito de 850 millones de pesos. La Zona Sur es reconocida por su alta oferta de vivienda vertical en estratos medio–alto y alto, lo que la convierte en un sector competitivo y heterogéneo en precios.
El modelo de regresión permitió estimar el valor esperado del apartamento solicitado bajo dos escenarios:
Estrato 5:
Precio estimado: 614.36 millones COP Intervalo de predicción 95%: 266.94 a 961.79 millones COP
Estrato 6:
Precio estimado: 712.27 millones COP Intervalo de predicción 95%: 364.76 a 1059.79 millones COP
Conclusiones de predicción
Ambos precios estimados están por debajo del crédito disponible (850M), lo que indica que el presupuesto es adecuado para este tipo de inmueble.
Sin embargo, los límites superiores de ambos intervalos sobrepasan el tope de crédito, lo cual es consistente con la fuerte dispersión del mercado del sur, donde existen unidades premium de metraje similar con valores superiores al presupuesto.
Entre los dos escenarios, estrato 5 ofrece mayor margen frente al crédito, pero estrato 6 se ajusta mejor al perfil de los barrios más exclusivos de la zona.
Al aplicar los criterios mínimos solicitados y realizar el cálculo del índice de similitud, el análisis identificó tres ofertas viables dentro del presupuesto:
Barrios donde se concentran las mejores opciones
Estas zonas son reconocidas por su cercanía a corredores viales, instituciones educativas, zonas comerciales y amplia oferta de servicios, lo que aporta valor a la decisión de compra.
Características destacadas de las ofertas identificadas
Precios entre 530M y 730M, muy por debajo del crédito disponible.
Áreas que oscilan entre 256 y 573 m², lo cual supera o se acerca adecuadamente al objetivo de 300 m².
Amenidades superiores al mínimo solicitado:
Aunque se encontraron únicamente tres unidades que cumplen todos los criterios estrictos (metraje alto + muchos baños + muchos parqueaderos + estrato alto), todas están dentro del crédito aprobado y se ubican en barrios de alta demanda y buena valorización.
Si la empresa desea aumentar la variedad de opciones, bastaría con relajar ligeramente el criterio de área (±10–15%), manteniendo el resto de características, para obtener un conjunto más amplio de alternativas dentro del presupuesto.
La compra de un apartamento en la Zona Sur con las especificaciones solicitadas es completamente viable dentro del crédito aprobado. Las viviendas identificadas en Seminario y Guadalupe son altamente recomendables por su equilibrio entre metraje, amenidades y precio. Se recomienda avanzar con visita técnica y revisión documental (administración, antigüedad, estado del edificio, zonas comunes). Si la empresa desea ampliar el abanico de alternativas, puede flexibilizar el criterio de área a un rango 270–330 m², lo cual aumentaría la oferta sin comprometer la calidad.
top5_v2_map <- top5_v2 %>% drop_na(longitud, latitud)
if (nrow(top5_v2_map) > 0) {
leaflet(top5_v2_map) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 8, color = "#d62728", fillOpacity = 0.9,
popup = ~paste0(
"<b>Apartamento – ", barrio, "</b><br>",
"Estrato: ", estrato, " | Zona: ", zona, "<br>",
"Área: ", areaconst, " m² | Hab.: ", habitaciones,
" | Baños: ", banios, " | Parq.: ", parqueaderos, "<br>",
"<b>Precio: </b>$", formatC(preciom, big.mark=".", format="d"), " millones"
)
)
} else {
cat("> Nota: las ofertas seleccionadas no cuentan con latitud/longitud completas para visualizar el mapa.\n")
}