Este informe tiene como objetivo apoyar a María, propietaria de la agencia inmobiliaria C&A (Casas y Apartamentos) en Cali, para dar respuesta a la solicitud de una compañía internacional que desea adquirir dos viviendas para ubicar a sus empleados en la ciudad.
Para ello se emplean técnicas de regresión lineal múltiple, que permiten estimar el precio de las viviendas a partir de características observables como el área construida, el estrato, el número de habitaciones, baños y parqueaderos.
Las dos solicitudes son:
| Característica | Vivienda 1 (Casa) | Vivienda 2 (Apartamento) |
|---|---|---|
| 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 |
# Instalación (solo la primera vez — comentar después de instalar)
# install.packages("devtools")
# devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
# install.packages(c("plotly", "leaflet", "dplyr", "ggplot2",
# "car", "lmtest", "nortest", "corrplot", # "kableExtra"))
library(paqueteMODELOS)
library(dplyr)
library(ggplot2)
library(plotly)
library(leaflet)
library(car)
library(lmtest)
library(nortest)
library(kableExtra)
library(corrplot)
data("vivienda")Se filtra la base de datos para conservar únicamente las casas ubicadas en la Zona Norte de Cali.
base1 <- vivienda %>%
filter(tipo == "Casa", zona == "Zona Norte")
# Dimensiones de la base filtrada
cat("Registros totales en la base filtrada:", nrow(base1), "\n")## Registros totales en la base filtrada: 722
## Variables disponibles: 13
base1 %>%
head(3) %>%
kable(caption = "Primeros 3 registros – Casas Zona Norte") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
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.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 |
# Distribución por tipo
table(base1$tipo) %>%
kable(col.names = c("Tipo", "Frecuencia"),
caption = "Distribución por tipo de vivienda") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)| Tipo | Frecuencia |
|---|---|
| Casa | 722 |
# Distribución por zona
table(base1$zona) %>%
kable(col.names = c("Zona", "Frecuencia"),
caption = "Distribución por zona") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)| Zona | Frecuencia |
|---|---|
| Zona Norte | 722 |
leaflet(base1) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 5,
color = "#2196F3",
fillOpacity = 0.7,
popup = ~paste0(
"<b>Barrio:</b> ", barrio, "<br>",
"<b>Estrato:</b> ", estrato, "<br>",
"<b>Precio:</b> $", preciom, " M<br>",
"<b>Área:</b> ", areaconst, " m²"
)
) %>%
addLegend("bottomright",
colors = "#2196F3",
labels = "Casas – Zona Norte",
title = "C&A Cali")Observación: Al revisar el mapa, puede notarse que algunos puntos se ubican ligeramente fuera del perímetro típicamente asociado a la Zona Norte de Cali. Esto puede deberse a inconsistencias en la clasificación de zonas dentro de la base de datos, a la presencia de barrios limítrofes que comparten características de más de una zona administrativa, o a errores en las coordenadas geográficas registradas. Se recomienda validar estos registros con la nomenclatura oficial del municipio antes de utilizarlos en la estimación.
base1 %>%
select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos) %>%
summary() %>%
kable(caption = "Estadísticas descriptivas – Variables numéricas") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| preciom | areaconst | estrato | banios | habitaciones | parqueaderos | |
|---|---|---|---|---|---|---|
| Min. : 89.0 | Min. : 30.0 | Min. :3.000 | Min. : 0.000 | Min. : 0.000 | Min. : 1.000 | |
| 1st Qu.: 261.2 | 1st Qu.: 140.0 | 1st Qu.:3.000 | 1st Qu.: 2.000 | 1st Qu.: 3.000 | 1st Qu.: 1.000 | |
| Median : 390.0 | Median : 240.0 | Median :4.000 | Median : 3.000 | Median : 4.000 | Median : 2.000 | |
| Mean : 445.9 | Mean : 264.9 | Mean :4.202 | Mean : 3.555 | Mean : 4.507 | Mean : 2.182 | |
| 3rd Qu.: 550.0 | 3rd Qu.: 336.8 | 3rd Qu.:5.000 | 3rd Qu.: 4.000 | 3rd Qu.: 5.000 | 3rd Qu.: 3.000 | |
| Max. :1940.0 | Max. :1440.0 | Max. :6.000 | Max. :10.000 | Max. :10.000 | Max. :10.000 | |
| NA | NA | NA | NA | NA | NA’s :287 |
p1 <- plot_ly(base1, x = ~preciom, type = "histogram",
marker = list(color = "#1976D2", line = list(color = "white", width = 0.5)),
nbinsx = 25) %>%
layout(title = "Distribución del Precio – Casas Zona Norte",
xaxis = list(title = "Precio (millones COP)"),
yaxis = list(title = "Frecuencia"))
p1La distribución del precio presenta una asimetría positiva, lo que indica la presencia de viviendas con precios muy elevados que sesgan la media hacia la derecha. La mayoría de las casas se concentra en rangos de precio más accesibles.
p2 <- plot_ly(base1, x = ~areaconst, y = ~preciom,
type = "scatter", mode = "markers",
color = ~factor(estrato),
marker = list(size = 8, opacity = 0.7),
text = ~paste("Barrio:", barrio, "<br>Precio: $", preciom, "M<br>Área:", areaconst, "m²")) %>%
layout(title = "Precio vs Área Construida (color = Estrato)",
xaxis = list(title = "Área Construida (m²)"),
yaxis = list(title = "Precio (millones COP)"),
legend = list(title = list(text = "Estrato")))
p2Se observa una relación positiva entre el área construida y el precio: a mayor área, mayor precio. Adicionalmente, el estrato actúa como un diferenciador importante, pues las viviendas de estratos más altos tienden a ubicarse en los segmentos de precio más elevado para una misma área.
p3 <- plot_ly(base1, x = ~factor(estrato), y = ~preciom,
type = "box",
color = ~factor(estrato)) %>%
layout(title = "Precio por Estrato – Casas Zona Norte",
xaxis = list(title = "Estrato"),
yaxis = list(title = "Precio (millones COP)"))
p3El precio promedio aumenta consistentemente con el estrato, lo cual es coherente con la realidad del mercado inmobiliario colombiano. Los estratos 5 y 6 presentan mayor dispersión, reflejando mayor heterogeneidad en las características de las viviendas más costosas.
p4 <- plot_ly(base1, x = ~banios, y = ~preciom,
type = "scatter", mode = "markers",
marker = list(color = "#43A047", size = 8, opacity = 0.6),
text = ~paste("Baños:", banios, "<br>Precio: $", preciom, "M")) %>%
layout(title = "Precio vs Número de Baños",
xaxis = list(title = "Número de Baños"),
yaxis = list(title = "Precio (millones COP)"))
p4p5 <- plot_ly(base1, x = ~habitaciones, y = ~preciom,
type = "scatter", mode = "markers",
marker = list(color = "#FB8C00", size = 8, opacity = 0.6),
text = ~paste("Habitaciones:", habitaciones, "<br>Precio: $", preciom, "M")) %>%
layout(title = "Precio vs Número de Habitaciones",
xaxis = list(title = "Número de Habitaciones"),
yaxis = list(title = "Precio (millones COP)"))
p5vars_cor <- base1 %>%
select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos) %>%
na.omit()
cor_matrix <- cor(vars_cor)
corrplot(cor_matrix,
method = "color",
type = "upper",
addCoef.col = "black",
tl.cex = 0.9,
number.cex = 0.8,
title = "Matriz de Correlación – Variables Numéricas",
mar = c(0, 0, 2, 0))La variable
areaconstpresenta la correlación más alta conpreciom, seguida deestrato. Las variablesbaniosyhabitacionestambién muestran correlaciones positivas moderadas. Se observa cierta correlación entre las variables explicativas (p. ej.,areaconstybanios), lo que podría sugerir problemas de multicolinealidad a considerar en el modelo.
modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios,
data = base1)
summary(modelo1)##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = base1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -784.29 -77.56 -16.03 47.67 978.61
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -238.17090 44.40551 -5.364 1.34e-07 ***
## areaconst 0.67673 0.05281 12.814 < 2e-16 ***
## estrato 80.63495 9.82632 8.206 2.70e-15 ***
## habitaciones 7.64511 5.65873 1.351 0.177
## parqueaderos 24.00598 5.86889 4.090 5.14e-05 ***
## banios 18.89938 7.48800 2.524 0.012 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 155.1 on 429 degrees of freedom
## (287 observations deleted due to missingness)
## Multiple R-squared: 0.6041, Adjusted R-squared: 0.5995
## F-statistic: 130.9 on 5 and 429 DF, p-value: < 2.2e-16
coef_df <- as.data.frame(summary(modelo1)$coefficients)
coef_df$Variable <- rownames(coef_df)
coef_df <- coef_df[, c("Variable", "Estimate", "Std. Error", "t value", "Pr(>|t|)")]
names(coef_df) <- c("Variable", "Estimado", "Error Estándar", "t", "p-valor")
coef_df %>%
kable(digits = 4, caption = "Coeficientes del Modelo de Regresión – Base 1") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(which(coef_df$`p-valor` < 0.05), background = "#E8F5E9")| Variable | Estimado | Error Estándar | t | p-valor | |
|---|---|---|---|---|---|
| (Intercept) | (Intercept) | -238.1709 | 44.4055 | -5.3635 | 0.0000 |
| areaconst | areaconst | 0.6767 | 0.0528 | 12.8140 | 0.0000 |
| estrato | estrato | 80.6349 | 9.8263 | 8.2060 | 0.0000 |
| habitaciones | habitaciones | 7.6451 | 5.6587 | 1.3510 | 0.1774 |
| parqueaderos | parqueaderos | 24.0060 | 5.8689 | 4.0904 | 0.0001 |
| banios | banios | 18.8994 | 7.4880 | 2.5240 | 0.0120 |
Interpretación de los coeficientes estadísticamente significativos (p < 0.05):
- Intercepto: Representa el precio base estimado cuando todas las variables son cero. Su interpretación directa no es relevante en el contexto del negocio.
areaconst: Por cada metro cuadrado adicional en el área construida, el precio de la casa aumenta en promedio X millones de pesos, manteniendo lo demás constante. Esto es coherente: casas más grandes tienen mayor valor comercial.estrato: El precio aumenta en promedio X millones por cada nivel adicional de estrato. Refleja el mayor valor de las zonas de estrato alto en el mercado inmobiliario de Cali.parqueaderos: Cada parqueadero adicional eleva el precio promedio de la vivienda. Tiene sentido dado que los parqueaderos representan un activo valorado en el mercado colombiano.- Variables no significativas: Aquellas con p-valor > 0.05 no muestran evidencia estadística suficiente de influir en el precio dentro de este subconjunto de datos. Se podría explorar eliminarlas o transformarlas.
Coeficiente R²: El modelo explica aproximadamente el 60.4% de la variabilidad en el precio de las casas de la Zona Norte. Este nivel de ajuste es aceptable para datos inmobiliarios reales, donde existen muchas variables cualitativas difíciles de capturar (estado de la construcción, acabados, vista, etc.). Para mejorar el ajuste se podría incluir variables adicionales como el barrio (como variable categórica), el piso, o transformaciones logarítmicas del precio y el área.
plot(fitted(modelo1), residuals(modelo1),
main = "Residuales vs Valores Ajustados",
xlab = "Valores ajustados", ylab = "Residuales",
pch = 20, col = "#1565C0")
abline(h = 0, col = "red", lwd = 2)Se inspecciona si los residuales se distribuyen aleatoriamente alrededor de cero. La presencia de patrones sistemáticos indicaría no linealidad en la relación.
# Test de Shapiro-Wilk
shapiro_test <- shapiro.test(residuals(modelo1))
cat("Test de Shapiro-Wilk:\n")## Test de Shapiro-Wilk:
## Estadístico W: 0.8525
## p-valor: 0
# Q-Q Plot interactivo
residuales <- residuals(modelo1)
qq_data <- qqnorm(residuales, plot.it = FALSE)
p_qq <- plot_ly() %>%
add_markers(x = qq_data$x, y = qq_data$y,
name = "Residuales",
marker = list(color = "#1976D2", size = 6)) %>%
add_lines(x = range(qq_data$x),
y = range(qq_data$x) * sd(residuales) + mean(residuales),
name = "Línea teórica",
line = list(color = "red")) %>%
layout(title = "Q-Q Plot – Normalidad de Residuales",
xaxis = list(title = "Cuantiles teóricos"),
yaxis = list(title = "Cuantiles de la muestra"))
p_qqEl test de Shapiro-Wilk rechaza la hipótesis de normalidad (p < 0.05). Esto puede deberse a la presencia de valores atípicos o a la distribución sesgada del precio. Una posible solución es aplicar una transformación logarítmica a la variable respuesta.
## Test de Breusch-Pagan:
## Estadístico: 80.2808
## p-valor: 0
Se rechaza el supuesto de homocedasticidad (p < 0.05), lo que indica varianza no constante en los errores (heterocedasticidad). Para corregirlo se podrían usar errores estándar robustos o transformar la variable respuesta.
## Test de Durbin-Watson:
## Estadístico DW: 1.7615
## p-valor: 0.0055
Se detecta autocorrelación en los residuales. Dado que los datos son de corte transversal (no de series de tiempo), este resultado podría deberse a agrupaciones espaciales en los datos. Se sugiere explorar modelos espaciales.
vif_vals <- vif(modelo1)
vif_df <- data.frame(Variable = names(vif_vals), VIF = round(vif_vals, 3))
vif_df %>%
kable(caption = "Factor de Inflación de Varianza (VIF)") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(which(vif_df$VIF > 5), background = "#FFEBEE")| Variable | VIF | |
|---|---|---|
| areaconst | areaconst | 1.461 |
| estrato | estrato | 1.308 |
| habitaciones | habitaciones | 1.721 |
| parqueaderos | parqueaderos | 1.226 |
| banios | banios | 1.967 |
Variables con VIF > 5 indicarían multicolinealidad moderada; VIF > 10 indicaría multicolinealidad severa. En este caso, todos los valores son menores a 5, por lo que no hay evidencia de multicolinealidad problemática.
Se predice el precio de una casa en la Zona Norte
con las siguientes características: - Área construida: 200 m²
- Parqueaderos: 1
- Baños: 2
- Habitaciones: 4
- Estrato: 4 (se evalúan estrato 4 y 5)
# Nueva observación - Estrato 4
nueva_casa_e4 <- data.frame(
areaconst = 200,
estrato = 4,
habitaciones = 4,
parqueaderos = 1,
banios = 2
)
# Nueva observación - Estrato 5
nueva_casa_e5 <- data.frame(
areaconst = 200,
estrato = 5,
habitaciones = 4,
parqueaderos = 1,
banios = 2
)
pred_e4 <- predict(modelo1, newdata = nueva_casa_e4, interval = "prediction", level = 0.95)
pred_e5 <- predict(modelo1, newdata = nueva_casa_e5, interval = "prediction", level = 0.95)
# Tabla resumen
pred_tabla <- data.frame(
Escenario = c("Estrato 4", "Estrato 5"),
`Precio estimado` = round(c(pred_e4[1], pred_e5[1]), 1),
`Límite inferior 95%` = round(c(pred_e4[2], pred_e5[2]), 1),
`Límite superior 95%` = round(c(pred_e4[3], pred_e5[3]), 1)
)
pred_tabla %>%
kable(caption = "Predicción del precio – Vivienda 1 (millones COP)") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Escenario | Precio.estimado | Límite.inferior.95. | Límite.superior.95. |
|---|---|---|---|
| Estrato 4 | 312.1 | 6.2 | 618.0 |
| Estrato 5 | 392.7 | 86.2 | 699.3 |
Interpretación: El modelo estima que una casa con las características solicitadas tendría un precio aproximado de 312.1 millones (estrato 4) o 392.7 millones (estrato 5). El crédito preaprobado de $350 millones resulta suficiente para el escenario de estrato 4.
Se filtran las casas de la Zona Norte con precio ≤ 350 millones que más se asemejan a la solicitud:
ofertas1 <- base1 %>%
filter(preciom <= 350,
estrato %in% c(4, 5),
habitaciones >= 3,
banios >= 2) %>%
arrange(abs(areaconst - 200)) %>%
head(10)
ofertas1 %>%
select(barrio, zona, estrato, preciom, areaconst, habitaciones, banios, parqueaderos) %>%
kable(caption = "Potenciales ofertas – Vivienda 1 (≤ $350 M, Zona Norte)") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| barrio | zona | estrato | preciom | areaconst | habitaciones | banios | parqueaderos |
|---|---|---|---|---|---|---|---|
| el bosque | Zona Norte | 5 | 350 | 200 | 4 | 3 | 3 |
| la flora | Zona Norte | 5 | 320 | 200 | 4 | 4 | 2 |
| la merced | Zona Norte | 4 | 320 | 200 | 4 | 4 | 2 |
| el bosque | Zona Norte | 5 | 335 | 202 | 5 | 4 | 1 |
| el bosque | Zona Norte | 5 | 350 | 203 | 5 | 2 | 2 |
| vipasa | Zona Norte | 5 | 340 | 203 | 4 | 3 | 2 |
| vipasa | Zona Norte | 5 | 300 | 205 | 6 | 5 | 2 |
| el bosque | Zona Norte | 4 | 340 | 207 | 4 | 4 | NA |
| el bosque | Zona Norte | 5 | 340 | 208 | 4 | 6 | NA |
| acopi | Zona Norte | 4 | 275 | 190 | 3 | 2 | NA |
top_ofertas1 <- ofertas1 %>% head(5)
leaflet(top_ofertas1) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 8,
color = "#E53935",
fillColor = "#EF9A9A",
fillOpacity = 0.8,
weight = 2,
popup = ~paste0(
"<b>Barrio:</b> ", barrio, "<br>",
"<b>Precio:</b> $", preciom, " M<br>",
"<b>Área:</b> ", areaconst, " m²<br>",
"<b>Estrato:</b> ", estrato, "<br>",
"<b>Habitaciones:</b> ", habitaciones, "<br>",
"<b>Baños:</b> ", banios
),
label = ~paste0("$", preciom, "M – ", barrio)
) %>%
addLegend("bottomright",
colors = "#E53935",
labels = "Ofertas potenciales ≤ $350M",
title = "Vivienda 1")Análisis de ofertas: Se presentan las 5 viviendas de la base de datos que mejor satisfacen las condiciones de la solicitud: casas en la Zona Norte con estrato 4 o 5, al menos 3 habitaciones, 2 baños y precio igual o inferior a $350 millones. Se recomienda a María visitar personalmente estas propiedades para verificar acabados y estado de conservación, factores que no están incluidos en el modelo pero tienen un impacto significativo en el valor comercial final.
base2 <- vivienda %>%
filter(tipo == "Apartamento", zona == "Zona Sur")
cat("Registros en base2 (Apartamentos – Zona Sur):", nrow(base2), "\n")## Registros en base2 (Apartamentos – Zona Sur): 2787
base2 %>%
head(3) %>%
kable(caption = "Primeros 3 registros – Apartamentos Zona Sur") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), 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.53464 | 3.44987 |
| 698 | Zona Sur | 02 | 3 | 78 | 40 | 1 | 1 | 2 | Apartamento | aguablanca | -76.50100 | 3.40000 |
| 8199 | Zona Sur | NA | 6 | 875 | 194 | 2 | 5 | 3 | Apartamento | aguacatal | -76.55700 | 3.45900 |
table(base2$tipo) %>%
kable(col.names = c("Tipo", "Frecuencia"),
caption = "Distribución por tipo") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)| Tipo | Frecuencia |
|---|---|
| Apartamento | 2787 |
table(base2$zona) %>%
kable(col.names = c("Zona", "Frecuencia"),
caption = "Distribución por zona") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)| Zona | Frecuencia |
|---|---|
| Zona Sur | 2787 |
leaflet(base2) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 5,
color = "#7B1FA2",
fillOpacity = 0.7,
popup = ~paste0(
"<b>Barrio:</b> ", barrio, "<br>",
"<b>Estrato:</b> ", estrato, "<br>",
"<b>Precio:</b> $", preciom, " M<br>",
"<b>Área:</b> ", areaconst, " m²"
)
) %>%
addLegend("bottomright",
colors = "#7B1FA2",
labels = "Apartamentos – Zona Sur",
title = "C&A Cali")Observación: Al igual que en la base 1, pueden presentarse puntos fuera del límite estricto de la Zona Sur, posiblemente por las mismas razones mencionadas anteriormente: barrios limítrofes, errores en coordenadas o clasificaciones ambiguas en la fuente de datos.
base2 %>%
select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos) %>%
summary() %>%
kable(caption = "Estadísticas descriptivas – Apartamentos Zona Sur") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| preciom | areaconst | estrato | banios | habitaciones | parqueaderos | |
|---|---|---|---|---|---|---|
| Min. : 75.0 | Min. : 40.00 | Min. :3.00 | Min. :0.000 | Min. :0.000 | Min. : 1.000 | |
| 1st Qu.: 175.0 | 1st Qu.: 65.00 | 1st Qu.:4.00 | 1st Qu.:2.000 | 1st Qu.:3.000 | 1st Qu.: 1.000 | |
| Median : 245.0 | Median : 85.00 | Median :5.00 | Median :2.000 | Median :3.000 | Median : 1.000 | |
| Mean : 297.3 | Mean : 97.47 | Mean :4.63 | Mean :2.488 | Mean :2.966 | Mean : 1.415 | |
| 3rd Qu.: 335.0 | 3rd Qu.:110.00 | 3rd Qu.:5.00 | 3rd Qu.:3.000 | 3rd Qu.:3.000 | 3rd Qu.: 2.000 | |
| Max. :1750.0 | Max. :932.00 | Max. :6.00 | Max. :8.000 | Max. :6.000 | Max. :10.000 | |
| NA | NA | NA | NA | NA | NA’s :406 |
p6 <- plot_ly(base2, x = ~areaconst, y = ~preciom,
type = "scatter", mode = "markers",
color = ~factor(estrato),
marker = list(size = 8, opacity = 0.7),
text = ~paste("Barrio:", barrio, "<br>Precio: $", preciom, "M<br>Área:", areaconst, "m²")) %>%
layout(title = "Precio vs Área Construida – Apartamentos Zona Sur",
xaxis = list(title = "Área Construida (m²)"),
yaxis = list(title = "Precio (millones COP)"),
legend = list(title = list(text = "Estrato")))
p6vars_cor2 <- base2 %>%
select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos) %>%
na.omit()
cor_matrix2 <- cor(vars_cor2)
corrplot(cor_matrix2,
method = "color",
type = "upper",
addCoef.col = "black",
tl.cex = 0.9,
number.cex = 0.8,
title = "Matriz de Correlación – Apartamentos Zona Sur",
mar = c(0, 0, 2, 0))modelo2 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios,
data = base2)
summary(modelo2)##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = base2)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1092.02 -42.28 -1.33 40.58 926.56
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -261.62501 15.63220 -16.736 < 2e-16 ***
## areaconst 1.28505 0.05403 23.785 < 2e-16 ***
## estrato 60.89709 3.08408 19.746 < 2e-16 ***
## habitaciones -24.83693 3.89229 -6.381 2.11e-10 ***
## parqueaderos 72.91468 3.95797 18.422 < 2e-16 ***
## banios 50.69675 3.39637 14.927 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 98.02 on 2375 degrees of freedom
## (406 observations deleted due to missingness)
## Multiple R-squared: 0.7485, Adjusted R-squared: 0.748
## F-statistic: 1414 on 5 and 2375 DF, p-value: < 2.2e-16
coef_df2 <- as.data.frame(summary(modelo2)$coefficients)
coef_df2$Variable <- rownames(coef_df2)
coef_df2 <- coef_df2[, c("Variable", "Estimate", "Std. Error", "t value", "Pr(>|t|)")]
names(coef_df2) <- c("Variable", "Estimado", "Error Estándar", "t", "p-valor")
coef_df2 %>%
kable(digits = 4, caption = "Coeficientes del Modelo – Apartamentos Zona Sur") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
row_spec(which(coef_df2$`p-valor` < 0.05), background = "#EDE7F6")| Variable | Estimado | Error Estándar | t | p-valor | |
|---|---|---|---|---|---|
| (Intercept) | (Intercept) | -261.6250 | 15.6322 | -16.7363 | 0 |
| areaconst | areaconst | 1.2850 | 0.0540 | 23.7853 | 0 |
| estrato | estrato | 60.8971 | 3.0841 | 19.7457 | 0 |
| habitaciones | habitaciones | -24.8369 | 3.8923 | -6.3811 | 0 |
| parqueaderos | parqueaderos | 72.9147 | 3.9580 | 18.4223 | 0 |
| banios | banios | 50.6967 | 3.3964 | 14.9267 | 0 |
Interpretación: Al igual que en el modelo de casas, el área construida y el estrato son los predictores con mayor peso en la determinación del precio de los apartamentos de la Zona Sur. El coeficiente de
areaconstindica que por cada metro cuadrado adicional, el precio del apartamento aumenta en promedio X millones. El coeficiente deestratocaptura el diferencial de precio entre segmentos socioeconómicos.El R² del modelo es 0.749, lo que significa que el modelo explica el 74.9% de la variación en el precio de los apartamentos. Para mejorar el ajuste se podría considerar incluir el piso como variable (en apartamentos, los pisos más altos suelen tener mayor valor) o el barrio como efecto fijo.
## Test de Shapiro-Wilk:
## Estadístico W: 0.7912
## p-valor: 0
## Test de Breusch-Pagan:
## Estadístico: 754.8051
## p-valor: 0
## Test de Durbin-Watson:
## Estadístico DW: 1.5333
## p-valor: 0
vif_vals2 <- vif(modelo2)
data.frame(Variable = names(vif_vals2), VIF = round(vif_vals2, 3)) %>%
kable(caption = "VIF – Modelo Apartamentos Zona Sur") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Variable | VIF | |
|---|---|---|
| areaconst | areaconst | 2.067 |
| estrato | estrato | 1.545 |
| habitaciones | habitaciones | 1.429 |
| parqueaderos | parqueaderos | 1.738 |
| banios | banios | 2.529 |
Resumen de supuestos – Modelo 2: Se siguen las mismas interpretaciones que en el modelo 1. Las desviaciones que se presenten deben considerarse como oportunidades de mejora del modelo y no necesariamente invalidan las predicciones cuando se usan con precaución.
Se predice el precio de un apartamento en la Zona
Sur con: - Área construida: 300 m²
- Parqueaderos: 3
- Baños: 3
- Habitaciones: 5
- Estrato: 5 y 6
nueva_apto_e5 <- data.frame(
areaconst = 300,
estrato = 5,
habitaciones = 5,
parqueaderos = 3,
banios = 3
)
nueva_apto_e6 <- data.frame(
areaconst = 300,
estrato = 6,
habitaciones = 5,
parqueaderos = 3,
banios = 3
)
pred2_e5 <- predict(modelo2, newdata = nueva_apto_e5, interval = "prediction", level = 0.95)
pred2_e6 <- predict(modelo2, newdata = nueva_apto_e6, interval = "prediction", level = 0.95)
pred_tabla2 <- data.frame(
Escenario = c("Estrato 5", "Estrato 6"),
`Precio estimado` = round(c(pred2_e5[1], pred2_e6[1]), 1),
`Límite inferior 95%` = round(c(pred2_e5[2], pred2_e6[2]), 1),
`Límite superior 95%` = round(c(pred2_e5[3], pred2_e6[3]), 1)
)
pred_tabla2 %>%
kable(caption = "Predicción del precio – Vivienda 2 (millones COP)") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| Escenario | Precio.estimado | Límite.inferior.95. | Límite.superior.95. |
|---|---|---|---|
| Estrato 5 | 675.0 | 481.5 | 868.6 |
| Estrato 6 | 735.9 | 542.3 | 929.5 |
Interpretación: El modelo estima que un apartamento con las características solicitadas en la Zona Sur tendría un precio de 675 millones (estrato 5) o 735.9 millones (estrato 6). El crédito preaprobado de $850 millones resulta suficiente para el escenario de estrato 5.
ofertas2 <- base2 %>%
filter(preciom <= 850,
estrato %in% c(5, 6),
habitaciones >= 4,
banios >= 3,
parqueaderos >= 2) %>%
arrange(abs(areaconst - 300)) %>%
head(10)
ofertas2 %>%
select(barrio, zona, estrato, preciom, areaconst, habitaciones, banios, parqueaderos) %>%
kable(caption = "Potenciales ofertas – Vivienda 2 (≤ $850 M, Zona Sur)") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| barrio | zona | estrato | preciom | areaconst | habitaciones | banios | parqueaderos |
|---|---|---|---|---|---|---|---|
| seminario | Zona Sur | 5 | 670 | 300.00 | 6 | 5 | 3 |
| cuarto de legua | Zona Sur | 5 | 410 | 295.55 | 4 | 4 | 2 |
| cuarto de legua | Zona Sur | 5 | 520 | 320.00 | 4 | 4 | 2 |
| ciudadela pasoancho | Zona Sur | 5 | 650 | 275.00 | 5 | 5 | 2 |
| capri | Zona Sur | 5 | 350 | 270.00 | 4 | 3 | 3 |
| san fernando | Zona Sur | 5 | 500 | 330.00 | 4 | 4 | 2 |
| san fernando viejo | Zona Sur | 5 | 485 | 259.00 | 4 | 4 | 2 |
| San Fernando | Zona Sur | 5 | 350 | 258.00 | 5 | 4 | 2 |
| seminario | Zona Sur | 5 | 530 | 256.00 | 5 | 5 | 3 |
| el ingenio | Zona Sur | 6 | 700 | 250.00 | 5 | 4 | 2 |
top_ofertas2 <- ofertas2 %>% head(5)
leaflet(top_ofertas2) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 8,
color = "#7B1FA2",
fillColor = "#CE93D8",
fillOpacity = 0.8,
weight = 2,
popup = ~paste0(
"<b>Barrio:</b> ", barrio, "<br>",
"<b>Precio:</b> $", preciom, " M<br>",
"<b>Área:</b> ", areaconst, " m²<br>",
"<b>Estrato:</b> ", estrato, "<br>",
"<b>Habitaciones:</b> ", habitaciones, "<br>",
"<b>Baños:</b> ", banios, "<br>",
"<b>Parqueaderos:</b> ", parqueaderos
),
label = ~paste0("$", preciom, "M – ", barrio)
) %>%
addLegend("bottomright",
colors = "#7B1FA2",
labels = "Ofertas potenciales ≤ $850M",
title = "Vivienda 2")Análisis de ofertas: Se presentan las 5 mejores opciones de apartamentos en la Zona Sur que cumplen con el presupuesto de $850 millones y los requerimientos mínimos de la solicitud. Se recomienda priorizar aquellas con área más cercana a los 300 m² y estrato 5 o 6, y realizar visitas in-situ para evaluar aspectos cualitativos como acabados, vistas, estado del edificio y amenidades del conjunto residencial.
En respuesta a la solicitud de la compañía internacional, la agencia C&A ha llevado a cabo un análisis estadístico riguroso basado en los datos de oferta inmobiliaria de los últimos tres meses en Cali. Los principales hallazgos son:
Vivienda 1 – Casa en Zona Norte: El modelo de regresión lineal múltiple estimó un precio de aproximadamente 312 millones (estrato 4) o 393 millones (estrato 5). Se identificaron al menos 5 propiedades en la base de datos que cumplen las condiciones solicitadas dentro del presupuesto de $350 millones.
Vivienda 2 – Apartamento en Zona Sur: El modelo estimó un precio de aproximadamente 675 millones (estrato 5) o 736 millones (estrato 6). Se identificaron opciones reales en la base de datos dentro del presupuesto de $850 millones.
Informe elaborado con R Markdown. Los datos provienen del paquete
paqueteMODELOS del repositorio centromagis.
Análisis realizado con fines académicos.