María, gerente de C&A (Casas y Apartamentos), recibió una solicitud de una compañía internacional que busca ubicar a dos familias de empleados en Cali. Cada familia tiene requisitos de vivienda y un crédito hipotecario preaprobado distintos:
| Característica | Vivienda 1 | Vivienda 2 |
|---|---|---|
| Tipo | Casa | Apartamento |
| Área construida | 200 m² | 300 m² |
| Parqueaderos | 1 | 3 |
| Baños | 2 | 3 |
| Habitaciones | 4 | 5 |
| Estrato | 4 o 5 | 5 o 6 |
| Zona | Norte | Sur |
| Crédito preaprobado | $350 millones | $850 millones |
Este informe usa un modelo estadístico de precios (regresión lineal múltiple), estimado de forma independiente para cada segmento de mercado relevante (casas en zona norte; apartamentos en zona sur) con datos de oferta inmobiliaria de los últimos tres meses, para responder dos preguntas concretas por cada familia: ¿cuánto vale en el mercado una vivienda con esas características? y ¿qué inmuebles reales disponibles hoy se ajustan a esas características y al presupuesto aprobado?
Con base en 435 ofertas de casas en zona norte de los últimos tres meses, el modelo estima que una casa con las características solicitadas (200 m², 4 habitaciones, 2 baños, 1 parqueadero) tiene un valor de mercado de referencia de aproximadamente 393 millones de pesos (estrato 5; ver Anexo 2, sección “Vivienda 1 — Paso 5”, para el detalle por estrato e intervalos de predicción).
Esto está por encima del crédito preaprobado de $350 millones en aproximadamente 43 millones, lo que sugiere que una vivienda exactamente con esas características puede no ser alcanzable con el presupuesto actual. Con el modelo se identificaron 5 ofertas concretas, disponibles hoy y dentro del presupuesto, que más se aproximan a lo solicitado (ver mapa y tabla en el Anexo 2, sección Vivienda 1, Paso 6). Recomendamos a María presentar estas alternativas a la familia, manteniendo el estrato solicitado, ya que hay suficientes opciones dentro de presupuesto.
Con base en 2381 ofertas de apartamentos en zona sur de los últimos tres meses, el modelo estima que un apartamento con las características solicitadas (300 m², 5 habitaciones, 3 baños, 3 parqueaderos) tiene un valor de mercado de referencia de aproximadamente 736 millones de pesos (estrato 6; ver Anexo 2, sección “Vivienda 2 — Paso 5”).
Esto está dentro del crédito preaprobado de $850 millones, por lo que una vivienda con esas características es alcanzable. Se identificaron 5 ofertas concretas dentro de presupuesto que se aproximan a lo solicitado (Anexo 2, sección Vivienda 2, Paso 6).
Se detectaron 499 registros cuya ubicación geográfica está más cerca del centroide de otra zona que de la propia (ver Anexo 2, sección “Paso 1” de cada vivienda), lo que sugiere posibles errores de etiquetado de zona en la base de datos. Esto no invalida las conclusiones, pero es un punto a corregir en la calidad de los datos de origen.
Los modelos se basan en precios de oferta (anuncios), no en precios de cierre de negociación, por lo que los valores reales de venta podrían ser distintos (típicamente algo menores, tras negociación). El tamaño de muestra de cada segmento (435 casas en zona norte, 2381 apartamentos en zona sur) acota la precisión de las estimaciones; el Anexo 2 detalla, para cada segmento, el ajuste del modelo (Paso 3) y las pruebas de validación de supuestos (Paso 4).
Para responder la solicitud de las dos familias se sigue un plan de trabajo de seis pasos, aplicado de forma independiente a cada segmento de mercado relevante (casas en zona norte para la Vivienda 1; apartamentos en zona sur para la Vivienda 2, como réplica del mismo procedimiento):
base1: casas de
zona norte; base2: apartamentos de zona sur), y se verifica
con tablas de frecuencia y una muestra de registros que el filtro se
aplicó correctamente. Se añade un chequeo geográfico (distancia de cada
inmueble al centroide de su zona vs. al de las demás) para detectar
posibles inconsistencias de etiquetado en la variable
zona.plotly), la relación entre el precio
y sus determinantes (área construida, estrato, baños, habitaciones,
zona) en el mercado general, para justificar la selección de variables
del modelo y anticipar el signo esperado de sus coeficientes.Este plan se aplica primero a la Vivienda 1 (Casa, zona norte) y luego se replica de forma idéntica para la Vivienda 2 (Apartamento, zona sur), como pide el enunciado.
Esta sección documenta, para cada solicitud, la ejecución completa del plan de trabajo del Anexo 1: filtrado y chequeo de la base de datos, análisis exploratorio, especificación y validación del modelo de regresión, predicción y búsqueda de ofertas.
## Observaciones totales (con variables completas): 6717
## Zonas disponibles: Zona Centro, Zona Norte, Zona Oeste, Zona Oriente, Zona Sur
## Tipos de vivienda disponibles: Apartamento, Casa
Antes de filtrar por segmento, se explora la relación entre el precio y sus principales determinantes en toda la base (todas las zonas y tipos), para tener contexto de mercado. Los gráficos son interactivos (pase el cursor sobre los puntos para ver el detalle de cada inmueble).
vars_num <- c("preciom", "areaconst", "estrato", "banios", "habitaciones")
mat_cor <- cor(vivienda[, vars_num], use = "pairwise.complete.obs")
plot_ly(
x = colnames(mat_cor), y = rownames(mat_cor), z = mat_cor,
type = "heatmap", colors = colorRamp(c("#2166ac", "#f7f7f7", "#b2182b")),
zmin = -1, zmax = 1
) %>%
layout(title = "Correlación entre precio y sus determinantes")cor_precio_area <- mat_cor["preciom", "areaconst"]
cor_precio_estrato <- mat_cor["preciom", "estrato"]
cor_precio_banios <- mat_cor["preciom", "banios"]
cor_precio_hab <- mat_cor["preciom", "habitaciones"]El precio muestra una correlación de 0.68 con el área construida, 0.59 con el estrato, 0.67 con el número de baños y 0.27 con el número de habitaciones. Todas son positivas, en línea con lo esperado: inmuebles más grandes, de estratos más altos y con más baños/habitaciones tienden a costar más.
g1 <- ggplot(vivienda, aes(x = areaconst, y = preciom, color = zona,
text = paste0("Barrio: ", barrio, "<br>Tipo: ", tipo))) +
geom_point(alpha = 0.5, size = 1.5) +
labs(x = "Área construida (m²)", y = "Precio (millones COP)",
title = "Precio vs. área construida, por zona", color = "Zona") +
theme_minimal()
ggplotly(g1, tooltip = c("x", "y", "text", "colour"))g3 <- ggplot(vivienda, aes(x = factor(banios), y = preciom, fill = factor(banios))) +
geom_boxplot(show.legend = FALSE) +
labs(x = "N° de baños", y = "Precio (millones COP)", title = "Precio por número de baños") +
theme_minimal()
g4 <- ggplot(vivienda, aes(x = factor(habitaciones), y = preciom, fill = factor(habitaciones))) +
geom_boxplot(show.legend = FALSE) +
labs(x = "N° de habitaciones", y = "Precio (millones COP)", title = "Precio por número de habitaciones") +
theme_minimal()
ggplotly(g3)g5 <- ggplot(vivienda, aes(x = fct_reorder(zona, preciom, median), y = preciom, fill = zona)) +
geom_boxplot(show.legend = FALSE) +
coord_flip() +
labs(x = NULL, y = "Precio (millones COP)", title = "Precio por zona (ordenado por mediana)") +
theme_minimal()
ggplotly(g5)Interpretación general: el precio se asocia de forma
clara y positiva con el área construida (la relación más fuerte), con el
estrato socioeconómico y, en menor medida, con el número de baños y
habitaciones (que están a su vez correlacionados entre sí y con el área,
ya que inmuebles más grandes suelen tener más espacios). La variable
zona marca diferencias claras de nivel de precios entre
sectores de la ciudad, lo que justifica analizar cada zona por
separado en el modelo predictivo, en lugar de mezclar zonas con
niveles de precio estructuralmente distintos.
Las siguientes dos secciones (una por solicitud) siguen exactamente los pasos 1 a 6 del enunciado, ya filtrados al segmento tipo+zona relevante para cada familia.
base1)head(res_v1$base, 3) %>%
kableExtra::kbl(caption = "Primeros 3 registros de base1 (Casas, Zona Norte)") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| 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.51 | 3.480 |
| 1592 | Zona Norte | 02 | 5 | 780 | 380 | 2 | 3 | 3 | Casa | acopi | -76.52 | 3.487 |
| 4460 | Zona Norte | 02 | 4 | 625 | 355 | 3 | 5 | 5 | Casa | acopi | -76.53 | 3.406 |
cat("Verificación del filtro -- valores únicos de tipo:", paste(names(res_v1$chequeo_tipo), collapse=", "), "\n")## Verificación del filtro -- valores únicos de tipo: Casa
cat("Verificación del filtro -- valores únicos de zona:", paste(names(res_v1$chequeo_zona), collapse=", "), "\n")## Verificación del filtro -- valores únicos de zona: Zona Norte
## Tamaño de la base filtrada (base1): 435 registros
El chequeo geográfico (distancia de cada punto al centroide de su propia zona vs. al centroide más cercano de otra zona) identificó 94 de 435 inmuebles (en rojo en el mapa) cuya ubicación está objetivamente más cerca de otra zona que de zona norte – probablemente errores de captura en la etiqueta de zona, o inmuebles ubicados en el límite administrativo entre zonas.
res_v1$modelo_tidy %>%
kableExtra::kbl(digits = 3, caption = "Coeficientes del modelo -- Vivienda 1 (Casas, Zona Norte)") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| term | estimate | std.error | statistic | p.value |
|---|---|---|---|---|
| (Intercept) | -238.171 | 44.406 | -5.364 | 0.000 |
| areaconst | 0.677 | 0.053 | 12.814 | 0.000 |
| estrato | 80.635 | 9.826 | 8.206 | 0.000 |
| habitaciones | 7.645 | 5.659 | 1.351 | 0.177 |
| parqueaderos | 24.006 | 5.869 | 4.090 | 0.000 |
| banios | 18.899 | 7.488 | 2.524 | 0.012 |
res_v1$modelo_glance %>% select(r.squared, adj.r.squared, sigma, statistic, p.value, df, nobs) %>%
kableExtra::kbl(digits = 3, caption = "Bondad de ajuste -- Vivienda 1") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| r.squared | adj.r.squared | sigma | statistic | p.value | df | nobs |
|---|---|---|---|---|---|---|
| 0.604 | 0.599 | 155.1 | 130.9 | 0 | 5 | 435 |
Interpretación de los coeficientes. Para cada variable con un p-valor inferior a 0.05, el coeficiente indica el cambio esperado en el precio (en millones de pesos) ante un aumento de una unidad en esa variable, manteniendo las demás constantes. Se espera, y sería lo lógico económicamente, que los coeficientes de área construida, estrato, baños, habitaciones y parqueaderos sean todos positivos (más espacio, mejor estrato o más comodidades deberían encarecer el inmueble); un coeficiente negativo y significativo en alguna de estas variables sería contraintuitivo y ameritaría revisión de los datos (posible multicolinealidad, o que esa variable esté capturando un efecto de otra correlacionada con ella).
Interpretación de R². El modelo explica
60.4% de la variabilidad del precio de las casas en
zona norte. Este es un ajuste moderado: el modelo captura una parte
importante de la variación de precios, pero queda una porción relevante
sin explicar, probablemente asociada a atributos no observados
(acabados, antigüedad, vista, estado de conservación, cercanía a vías o
equipamientos). Para mejorar el ajuste se podría: (i) incorporar
variables adicionales no disponibles en esta base (antigüedad, acabados,
cercanía a vías principales o centros comerciales); (ii) usar variables
de barrio como efecto fijo, dado que dentro de una misma zona el barrio
puede aportar información de precio adicional; (iii) probar
transformaciones (p. ej. log(preciom)) si la relación no es
perfectamente lineal; o (iv) usar modelos no lineales (árboles, bosques
aleatorios) si la relación entre las variables y el precio no es
aditiva.
if (!is.null(res_v1$shapiro)) cat("Shapiro-Wilk (normalidad de residuos): W =", round(res_v1$shapiro$statistic,3),
", p-valor =", signif(res_v1$shapiro$p.value,3), "\n")## Shapiro-Wilk (normalidad de residuos): W = 0.852 , p-valor = 0.0000000000000000000877
if (!is.null(res_v1$bp)) cat("Breusch-Pagan (homocedasticidad): BP =", round(res_v1$bp$statistic,3),
", p-valor =", signif(res_v1$bp$p.value,3), "\n")## Breusch-Pagan (homocedasticidad): BP = 80.28 , p-valor = 0.000000000000000733
if (!is.null(res_v1$dw)) cat("Durbin-Watson (independencia): DW =", round(res_v1$dw$statistic,3),
", p-valor =", signif(res_v1$dw$p.value,3), "\n")## Durbin-Watson (independencia): DW = 1.762 , p-valor = 0.00547
if (!is.null(res_v1$vif)) { cat("Factores de inflación de varianza (VIF):\n"); print(round(res_v1$vif,2)) }## Factores de inflación de varianza (VIF):
## areaconst estrato habitaciones parqueaderos banios
## 1.46 1.31 1.72 1.23 1.97
Interpretación. El gráfico de residuos vs. valores
ajustados permite evaluar linealidad y homocedasticidad (un patrón
embudo indicaría varianza no constante); el gráfico Q-Q compara los
residuos contra una distribución normal (desviaciones fuertes en las
colas indican no normalidad). El test de Shapiro-Wilk formaliza la
evaluación de normalidad (aquí se rechaza la normalidad de los residuos
(p < 0.05), lo que sugiere que los intervalos de predicción deben
interpretarse con cautela), el de Breusch-Pagan la homocedasticidad
(aquí se rechaza la homocedasticidad (p < 0.05): la varianza del
error no es constante, probablemente crece con el precio/tamaño del
inmueble), y el VIF la multicolinealidad entre predictores (valores por
encima de 5-10 señalan colinealidad problemática). El test de
Durbin-Watson se reporta por completitud, pero su supuesto de
independencia asume un orden natural de las observaciones (p. ej.
temporal), que no aplica de forma directa a datos de corte transversal
como estos; para datos inmobiliarios georreferenciados, un diagnóstico
más pertinente sería la autocorrelación espacial de los
residuos (p. ej. el índice de Moran), ya que inmuebles cercanos entre sí
suelen compartir factores de valorización no observados (cercanía a
vías, parques, seguridad del sector). No se realizan
correcciones, tal como pide el enunciado; de presentarse
violaciones, se sugeriría: para heterocedasticidad, usar errores
estándar robustos (sandwich/lmtest) o
transformar la variable respuesta (log(preciom)); para no
normalidad, la misma transformación logarítmica suele ayudar; para
multicolinealidad, retirar o combinar variables redundantes (p. ej.
habitaciones y baños suelen estar correlacionadas entre sí).
res_v1$pred_tabla %>%
kableExtra::kbl(digits = 1, col.names = c("Estrato", "Precio estimado (M COP)", "Límite inferior (95%)", "Límite superior (95%)"),
caption = "Predicción de precio -- Casa de 200 m², 4 hab., 2 baños, 1 parqueadero") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Estrato | Precio estimado (M COP) | Límite inferior (95%) | Límite superior (95%) |
|---|---|---|---|
| 4 | 312.1 | 6.2 | 618.0 |
| 5 | 392.7 | 86.2 | 699.3 |
if (res_v1$n_candidatas == 0) {
cat("No se encontró ninguna casa en zona norte, de ningún estrato, con precio listado <= $350M en los últimos tres meses.")
} else if (res_v1$estrato_relajado) {
cat("Nota: al filtrar por estrato 4-5 y presupuesto <= $350M había menos de 5 opciones, por lo que se amplió la búsqueda a todos los estratos disponibles en casas de zona norte dentro de presupuesto.")
} else {
cat("Búsqueda restringida a estrato 4-5 y presupuesto <= $350M.")
}## Búsqueda restringida a estrato 4-5 y presupuesto <= $350M.
if (nrow(res_v1$ofertas) > 0) {
res_v1$ofertas %>%
select(barrio, estrato, preciom, areaconst, habitaciones, banios, parqueaderos, precio_predicho, valor) %>%
kableExtra::kbl(digits = 1,
col.names = c("Barrio", "Estrato", "Precio (M)", "Área (m²)", "Hab.", "Baños",
"Parq.", "Precio predicho (M)", "Valor (predicho - listado)"),
caption = "Ofertas recomendadas para la Vivienda 1") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
} else {
cat("(No hay ofertas que mostrar dentro de este presupuesto.)")
}| Barrio | Estrato | Precio (M) | Área (m²) | Hab. | Baños | Parq. | Precio predicho (M) | Valor (predicho - listado) |
|---|---|---|---|---|---|---|---|---|
| alamos | 4 | 275 | 120 | 4 | 2 | 1 | 258.0 | -17.0 |
| vipasa | 5 | 350 | 346 | 4 | 2 | 1 | 491.5 | 141.5 |
| la merced | 5 | 350 | 216 | 4 | 2 | 2 | 427.6 | 77.6 |
| zona norte | 4 | 265 | 162 | 4 | 3 | 1 | 305.3 | 40.3 |
| la flora | 5 | 320 | 160 | 4 | 3 | 1 | 384.6 | 64.6 |
Discusión. Estas ofertas se seleccionaron dentro del presupuesto de $350 millones, priorizando primero la cercanía a las características solicitadas (área, habitaciones, baños, parqueaderos) y, en caso de empate, el mejor “valor” (precio predicho por el modelo por encima del precio realmente listado, es decir, inmuebles que el modelo considera baratos relativo a sus atributos). Recomendamos a María visitar en persona las opciones con mayor “valor” positivo, ya que son las que el modelo señala como potencialmente subvaloradas frente al mercado.
base2)head(res_v2$base, 3) %>%
kableExtra::kbl(caption = "Primeros 3 registros de base2 (Apartamentos, Zona Sur)") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 5098 | Zona Sur | 05 | 4 | 290 | 96 | 1 | 2 | 3 | Apartamento | acopi | -76.53 | 3.450 |
| 698 | Zona Sur | 02 | 3 | 78 | 40 | 1 | 1 | 2 | Apartamento | aguablanca | -76.50 | 3.400 |
| 8199 | Zona Sur | NA | 6 | 875 | 194 | 2 | 5 | 3 | Apartamento | aguacatal | -76.56 | 3.459 |
cat("Verificación del filtro -- valores únicos de tipo:", paste(names(res_v2$chequeo_tipo), collapse=", "), "\n")## Verificación del filtro -- valores únicos de tipo: Apartamento
cat("Verificación del filtro -- valores únicos de zona:", paste(names(res_v2$chequeo_zona), collapse=", "), "\n")## Verificación del filtro -- valores únicos de zona: Zona Sur
## Tamaño de la base filtrada (base2): 2381 registros
El chequeo geográfico identificó 405 de 2381 inmuebles (en rojo en el mapa) cuya ubicación está más cerca de otra zona que de zona sur.
res_v2$modelo_tidy %>%
kableExtra::kbl(digits = 3, caption = "Coeficientes del modelo -- Vivienda 2 (Apartamentos, Zona Sur)") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| term | estimate | std.error | statistic | p.value |
|---|---|---|---|---|
| (Intercept) | -261.625 | 15.632 | -16.736 | 0 |
| areaconst | 1.285 | 0.054 | 23.785 | 0 |
| estrato | 60.897 | 3.084 | 19.746 | 0 |
| habitaciones | -24.837 | 3.892 | -6.381 | 0 |
| parqueaderos | 72.915 | 3.958 | 18.422 | 0 |
| banios | 50.697 | 3.396 | 14.927 | 0 |
res_v2$modelo_glance %>% select(r.squared, adj.r.squared, sigma, statistic, p.value, df, nobs) %>%
kableExtra::kbl(digits = 3, caption = "Bondad de ajuste -- Vivienda 2") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| r.squared | adj.r.squared | sigma | statistic | p.value | df | nobs |
|---|---|---|---|---|---|---|
| 0.749 | 0.748 | 98.02 | 1414 | 0 | 5 | 2381 |
Interpretación de R². El modelo explica 74.9% de la variabilidad del precio de los apartamentos en zona sur. Ajuste alto para este tipo de datos. Las mismas estrategias de mejora sugeridas para la Vivienda 1 aplican aquí (variables adicionales, efecto fijo de barrio o de piso, transformación logarítmica, o modelos no lineales).
if (!is.null(res_v2$shapiro)) cat("Shapiro-Wilk (normalidad de residuos): W =", round(res_v2$shapiro$statistic,3),
", p-valor =", signif(res_v2$shapiro$p.value,3), "\n")## Shapiro-Wilk (normalidad de residuos): W = 0.791 , p-valor = 0.00000000000000000000000000000000000000000000000484
if (!is.null(res_v2$bp)) cat("Breusch-Pagan (homocedasticidad): BP =", round(res_v2$bp$statistic,3),
", p-valor =", signif(res_v2$bp$p.value,3), "\n")## Breusch-Pagan (homocedasticidad): BP = 754.8 , p-valor = 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000691
if (!is.null(res_v2$dw)) cat("Durbin-Watson (independencia): DW =", round(res_v2$dw$statistic,3),
", p-valor =", signif(res_v2$dw$p.value,3), "\n")## Durbin-Watson (independencia): DW = 1.533 , p-valor = 0.00000000000000000000000000000173
if (!is.null(res_v2$vif)) { cat("Factores de inflación de varianza (VIF):\n"); print(round(res_v2$vif,2)) }## Factores de inflación de varianza (VIF):
## areaconst estrato habitaciones parqueaderos banios
## 2.07 1.55 1.43 1.74 2.53
Igual que en la Vivienda 1, no se corrigen los posibles problemas detectados (por instrucción del enunciado), pero las mismas alternativas de remedio (errores robustos, transformación logarítmica, revisión de variables redundantes) aplican aquí.
res_v2$pred_tabla %>%
kableExtra::kbl(digits = 1, col.names = c("Estrato", "Precio estimado (M COP)", "Límite inferior (95%)", "Límite superior (95%)"),
caption = "Predicción de precio -- Apartamento de 300 m², 5 hab., 3 baños, 3 parqueaderos") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Estrato | Precio estimado (M COP) | Límite inferior (95%) | Límite superior (95%) |
|---|---|---|---|
| 5 | 675.0 | 481.5 | 868.6 |
| 6 | 735.9 | 542.3 | 929.5 |
if (res_v2$n_candidatas == 0) {
cat("No se encontró ningún apartamento en zona sur, de ningún estrato, con precio listado <= $850M en los últimos tres meses.")
} else if (res_v2$estrato_relajado) {
cat("Nota: al filtrar por estrato 5-6 y presupuesto <= $850M había menos de 5 opciones, por lo que se amplió la búsqueda a todos los estratos disponibles en apartamentos de zona sur dentro de presupuesto.")
} else {
cat("Búsqueda restringida a estrato 5-6 y presupuesto <= $850M.")
}## Búsqueda restringida a estrato 5-6 y presupuesto <= $850M.
if (nrow(res_v2$ofertas) > 0) {
res_v2$ofertas %>%
select(barrio, estrato, preciom, areaconst, habitaciones, banios, parqueaderos, precio_predicho, valor) %>%
kableExtra::kbl(digits = 1,
col.names = c("Barrio", "Estrato", "Precio (M)", "Área (m²)", "Hab.", "Baños",
"Parq.", "Precio predicho (M)", "Valor (predicho - listado)"),
caption = "Ofertas recomendadas para la Vivienda 2") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
} else {
cat("(No hay ofertas que mostrar dentro de este presupuesto.)")
}| Barrio | Estrato | Precio (M) | Área (m²) | Hab. | Baños | Parq. | Precio predicho (M) | Valor (predicho - listado) |
|---|---|---|---|---|---|---|---|---|
| capri | 5 | 350 | 270 | 4 | 3 | 3 | 661.3 | 311.3 |
| ciudad jardín | 6 | 550 | 130 | 4 | 3 | 3 | 542.3 | -7.7 |
| pampa linda | 5 | 450 | 267 | 3 | 3 | 3 | 682.3 | 232.3 |
| capri | 5 | 350 | 260 | 3 | 3 | 3 | 673.3 | 323.3 |
| San Fernando | 5 | 350 | 258 | 5 | 4 | 2 | 598.8 | 248.8 |
Discusión. Estas ofertas se seleccionaron dentro del presupuesto de $850 millones, priorizando la cercanía a las características solicitadas y, en caso de empate, el mejor “valor” frente al precio predicho por el modelo.
comparacion <- tibble(
Segmento = c(res_v1$etiqueta, res_v2$etiqueta),
`N observaciones` = c(res_v1$n_base, res_v2$n_base),
`R2` = c(res_v1$modelo_glance$r.squared, res_v2$modelo_glance$r.squared),
`R2 ajustado` = c(res_v1$modelo_glance$adj.r.squared, res_v2$modelo_glance$adj.r.squared),
`Error estándar residual` = c(res_v1$modelo_glance$sigma, res_v2$modelo_glance$sigma),
`Normalidad residuos (p Shapiro)` = c(
if (!is.null(res_v1$shapiro)) signif(res_v1$shapiro$p.value, 3) else NA,
if (!is.null(res_v2$shapiro)) signif(res_v2$shapiro$p.value, 3) else NA
),
`Homocedasticidad (p Breusch-Pagan)` = c(
if (!is.null(res_v1$bp)) signif(res_v1$bp$p.value, 3) else NA,
if (!is.null(res_v2$bp)) signif(res_v2$bp$p.value, 3) else NA
)
)
comparacion %>%
kableExtra::kbl(digits = 3, caption = "Comparación de los modelos de los dos segmentos") %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Segmento | N observaciones | R2 | R2 ajustado | Error estándar residual | Normalidad residuos (p Shapiro) | Homocedasticidad (p Breusch-Pagan) |
|---|---|---|---|---|---|---|
| Vivienda 1 (Casa, Zona Norte) | 435 | 0.604 | 0.599 | 155.12 | 0 | 0 |
| Vivienda 2 (Apartamento, Zona Sur) | 2381 | 0.749 | 0.748 | 98.02 | 0 | 0 |
Los dos modelos se estiman de forma independiente porque corresponden a segmentos de mercado distintos (tipo de vivienda y zona), cada uno con su propia dinámica de precios; no son directamente “el mismo modelo aplicado dos veces” sino dos ajustes específicos a su segmento, lo cual es preferible a forzar un único modelo global cuando, como se vio en el análisis exploratorio, el precio varía sustancialmente entre zonas y tipos de vivienda.
Kutner, M. H., Nachtsheim, C. J., Neter, J., & Li, W. (2005). Applied Linear Statistical Models (5th ed.). McGraw-Hill/Irwin.
Wooldridge, J. M. (2019). Introductory Econometrics: A Modern Approach (7th ed.). Cengage Learning.
Fox, J., & Weisberg, S. (2019). An R Companion to Applied
Regression (3rd ed.). Sage Publications. (Paquete
car.)
## R version 4.5.1 (2025-06-13)
## Platform: aarch64-apple-darwin20
## Running under: macOS Tahoe 26.5.2
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## time zone: America/Bogota
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] remotes_2.5.0 RColorBrewer_1.1-3 scales_1.4.0 kableExtra_1.4.0
## [5] lmtest_0.9-40 zoo_1.8-15 car_3.1-5 carData_3.0-6
## [9] broom_1.0.13 leaflet_2.2.3 plotly_4.12.1 lubridate_1.9.5
## [13] forcats_1.0.1 stringr_1.6.0 dplyr_1.2.1 purrr_1.2.2
## [17] readr_2.2.0 tidyr_1.3.2 tibble_3.3.1 ggplot2_4.0.3
## [21] tidyverse_2.0.0
##
## loaded via a namespace (and not attached):
## [1] gtable_0.3.6 xfun_0.60 bslib_0.9.0
## [4] htmlwidgets_1.6.4 lattice_0.22-7 tzdb_0.5.0
## [7] leaflet.providers_3.0.0 vctrs_0.7.3 tools_4.5.1
## [10] crosstalk_1.2.2 generics_0.1.4 pkgconfig_2.0.3
## [13] data.table_1.18.2.1 S7_0.2.2 lifecycle_1.0.5
## [16] compiler_4.5.1 farver_2.1.2 textshaping_1.0.4
## [19] htmltools_0.5.9 sass_0.4.10 yaml_2.3.12
## [22] Formula_1.2-5 pillar_1.11.1 jquerylib_0.1.4
## [25] cachem_1.1.0 abind_1.4-8 tidyselect_1.2.1
## [28] digest_0.6.39 stringi_1.8.9 labeling_0.4.3
## [31] fastmap_1.2.0 grid_4.5.1 cli_3.6.6
## [34] magrittr_2.0.5 withr_3.0.3 backports_1.5.1
## [37] timechange_0.4.0 rmarkdown_2.30 httr_1.4.8
## [40] otel_0.2.0 hms_1.1.4 evaluate_1.0.5
## [43] knitr_1.51 viridisLite_0.4.3 rlang_1.3.0
## [46] glue_1.8.1 xml2_1.5.1 svglite_2.2.2
## [49] rstudioapi_0.19.0 jsonlite_2.0.0 R6_2.6.1
## [52] systemfonts_1.3.1