El presente informe tiene como objetivo modelar el precio de la vivienda en el barrio Valle del Lili en la ciudad de Cali. Se analizan modelos de regresión lineal simple y múltiple, evaluando sus supuestos econométricos, la pertinencia de transformaciones logarítmicas, selección de variables mediante Stepwise y métricas de error predictivo (MAE).
# Carga de librerías requeridas
library(readxl)
library(dplyr)
library(ggplot2)
library(lmtest) # Breusch-Pagan, Durbin-Watson
library(car) # VIF (Multicolinealidad)
library(broom)
# Lectura de la base de datos (reconociendo celdas vacías y texto "NA")
datos <- read_excel("Datos_Vivienda.xlsx", na = c("", "NA"))
# Filtrado por barrio, conversión numérica de parqueaderos y limpieza
datos_lili <- datos %>%
filter(tolower(trimws(Barrio)) == "valle del lili") %>%
mutate(parqueaderos = as.numeric(parqueaderos)) %>%
select(precio_millon, Area_contruida, Banos, Habitaciones, parqueaderos, Tipo) %>%
na.omit()
# Convertir Tipo en factor (Apartamento será la categoría base)
datos_lili$Tipo <- as.factor(datos_lili$Tipo)
summary(datos_lili)
## precio_millon Area_contruida Banos Habitaciones
## Min. :120.0 Min. : 45.00 Min. :1.000 Min. :2.000
## 1st Qu.:210.0 1st Qu.: 70.00 1st Qu.:2.000 1st Qu.:3.000
## Median :245.0 Median : 80.00 Median :2.000 Median :3.000
## Mean :256.3 Mean : 94.48 Mean :2.432 Mean :2.974
## 3rd Qu.:295.0 3rd Qu.: 94.75 3rd Qu.:3.000 3rd Qu.:3.000
## Max. :800.0 Max. :932.00 Max. :6.000 Max. :8.000
## parqueaderos Tipo
## Min. : 1.000 Apartamento:679
## 1st Qu.: 1.000 Casa :159
## Median : 1.000
## Mean : 1.198
## 3rd Qu.: 1.000
## Max. :10.000
Se formulan tres modelos de regresión lineal simple tomando el precio
del inmueble (precio_millon) como variable respuesta frente
a: 1. Área construida (Area_contruida) 2. Número de baños
(Banos) 3. Número de habitaciones
(Habitaciones)
# Modelo 1: Precio vs Área construida
mod_s1 <- lm(precio_millon ~ Area_contruida, data = datos_lili)
# Modelo 2: Precio vs Baños
mod_s2 <- lm(precio_millon ~ Banos, data = datos_lili)
# Modelo 3: Precio vs Habitaciones
mod_s3 <- lm(precio_millon ~ Habitaciones, data = datos_lili)
summary(mod_s1)
##
## Call:
## lm(formula = precio_millon ~ Area_contruida, data = datos_lili)
##
## Residuals:
## Min 1Q Median 3Q Max
## -656.42 -33.37 -1.72 32.43 339.01
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 177.43412 3.66440 48.42 <2e-16 ***
## Area_contruida 0.83475 0.03211 25.99 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 59.48 on 836 degrees of freedom
## Multiple R-squared: 0.447, Adjusted R-squared: 0.4463
## F-statistic: 675.7 on 1 and 836 DF, p-value: < 2.2e-16
summary(mod_s2)
##
## Call:
## lm(formula = precio_millon ~ Banos, data = datos_lili)
##
## Residuals:
## Min 1Q Median 3Q Max
## -174.57 -37.36 -0.45 27.05 345.43
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 68.540 6.709 10.22 <2e-16 ***
## Banos 77.206 2.641 29.24 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 56.24 on 836 degrees of freedom
## Multiple R-squared: 0.5056, Adjusted R-squared: 0.505
## F-statistic: 854.8 on 1 and 836 DF, p-value: < 2.2e-16
summary(mod_s3)
##
## Call:
## lm(formula = precio_millon ~ Habitaciones, data = datos_lili)
##
## Residuals:
## Min 1Q Median 3Q Max
## -178.03 -43.13 -8.14 39.86 361.84
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 48.21 11.89 4.054 5.51e-05 ***
## Habitaciones 69.98 3.92 17.851 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 68.06 on 836 degrees of freedom
## Multiple R-squared: 0.276, Adjusted R-squared: 0.2751
## F-statistic: 318.7 on 1 and 836 DF, p-value: < 2.2e-16
Interpretación de coeficientes: * Modelo 1 (Área): Por cada metro cuadrado adicional construido, el precio de la vivienda se incrementa en promedio en 0.835 millones de pesos. El área explica aproximadamente el 44.7% de la variabilidad del precio (\(R^2\)). * Modelo 2 (Baños): Cada baño adicional incrementa el precio esperado en 77.21 millones de pesos (\(R^2 \approx 50.6\%\)). * Modelo 3 (Habitaciones): Cada habitación adicional aporta en promedio 69.98 millones de pesos (\(R^2 \approx 27.6\%\)).
Se evalúa la normalidad de los residuos (Shapiro-Wilk) y la homocedasticidad (Breusch-Pagan).
par(mfrow = c(1, 3))
qqnorm(residuals(mod_s1), main = "Q-Q Residuos M1 (Área)")
qqline(residuals(mod_s1), col = "red")
qqnorm(residuals(mod_s2), main = "Q-Q Residuos M2 (Baños)")
qqline(residuals(mod_s2), col = "red")
qqnorm(residuals(mod_s3), main = "Q-Q Residuos M3 (Habitaciones)")
qqline(residuals(mod_s3), col = "red")
par(mfrow = c(1, 1))
# Pruebas estadísticas para el Modelo 1
shapiro.test(residuals(mod_s1)[1:500]) # Shapiro admite hasta 5000 obs; se toma muestra
##
## Shapiro-Wilk normality test
##
## data: residuals(mod_s1)[1:500]
## W = 0.95027, p-value = 6.344e-12
bptest(mod_s1)
##
## studentized Breusch-Pagan test
##
## data: mod_s1
## BP = 244.04, df = 1, p-value < 2.2e-16
Debido al sesgo positivo del precio y del área construida, se prueba una transformación logarítmica (modelo Log-Log: \(\ln(\text{precio}) \sim \ln(\text{área})\)).
mod_s1_log <- lm(log(precio_millon) ~ log(Area_contruida), data = datos_lili)
summary(mod_s1_log)
##
## Call:
## lm(formula = log(precio_millon) ~ log(Area_contruida), data = datos_lili)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.36095 -0.11304 0.02687 0.11882 0.59647
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.81105 0.07483 37.57 <2e-16 ***
## log(Area_contruida) 0.60480 0.01675 36.11 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1813 on 836 degrees of freedom
## Multiple R-squared: 0.6093, Adjusted R-squared: 0.6088
## F-statistic: 1304 on 1 and 836 DF, p-value: < 2.2e-16
# Comparación gráfica de residuos
par(mfrow = c(1, 2))
plot(fitted(mod_s1), residuals(mod_s1), main = "Residuos Modelo Lineal", xlab = "Ajustados", ylab = "Residuos")
abline(h = 0, col = "red")
plot(fitted(mod_s1_log), residuals(mod_s1_log), main = "Residuos Modelo Log-Log", xlab = "Ajustados", ylab = "Residuos")
abline(h = 0, col = "blue")
par(mfrow = c(1, 1))
bptest(mod_s1_log)
##
## studentized Breusch-Pagan test
##
## data: mod_s1_log
## BP = 64.195, df = 1, p-value = 1.127e-15
Diagnóstico: La transformación logarítmica incrementa sustancialmente el ajuste explicativo (el \(R^2\) pasa de 0.447 a 0.609). Además, estabiliza la dispersión de los residuos a lo largo de los valores ajustados, mostrando mayor simetría, lo que valida su pertinencia teórica y empírica. En este modelo Log-Log, el coeficiente 0.605 representa una elasticidad: por cada 1% de aumento en el área, el precio sube aproximadamente 0.6%.
Se formulan dos modelos con múltiples predictores, incluyendo la
variable cualitativa Tipo como variable
DUMMY (Referencia: Apartamento; Valor 1:
Casa).
Modelo Múltiple 1 (Lineal): \[\text{precio\_millon} = \beta_0 + \beta_1 \text{Area} + \beta_2 \text{Banos} + \beta_3 \text{Habitaciones} + \beta_4 \text{parqueaderos} + \beta_5 \text{TipoCasa} + \epsilon\]
Modelo Múltiple 2 (Transformación Logarítmica - Semilog/Log-Log): \[\ln(\text{precio\_millon}) = \beta_0 + \beta_1 \ln(\text{Area}) + \beta_2 \text{Banos} + \beta_3 \text{Habitaciones} + \beta_4 \text{parqueaderos} + \beta_5 \text{TipoCasa} + \epsilon\]
# Modelo Múltiple 1: En escala natural
mod_m1 <- lm(precio_millon ~ Area_contruida + Banos + Habitaciones + parqueaderos + Tipo, data = datos_lili)
# Modelo Múltiple 2: En escala logarítmica
mod_m2 <- lm(log(precio_millon) ~ log(Area_contruida) + Banos + Habitaciones + parqueaderos + Tipo, data = datos_lili)
summary(mod_m1)
##
## Call:
## lm(formula = precio_millon ~ Area_contruida + Banos + Habitaciones +
## parqueaderos + Tipo, data = datos_lili)
##
## Residuals:
## Min 1Q Median 3Q Max
## -331.82 -30.28 3.27 24.95 294.80
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 36.34558 10.78018 3.372 0.000782 ***
## Area_contruida 0.41320 0.03773 10.950 < 2e-16 ***
## Banos 49.58940 3.77490 13.137 < 2e-16 ***
## Habitaciones 13.71318 3.69326 3.713 0.000218 ***
## parqueaderos 19.46425 3.67390 5.298 1.5e-07 ***
## TipoCasa -19.93544 6.06726 -3.286 0.001060 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 50.49 on 832 degrees of freedom
## Multiple R-squared: 0.6035, Adjusted R-squared: 0.6011
## F-statistic: 253.3 on 5 and 832 DF, p-value: < 2.2e-16
summary(mod_m2)
##
## Call:
## lm(formula = log(precio_millon) ~ log(Area_contruida) + Banos +
## Habitaciones + parqueaderos + Tipo, data = datos_lili)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.22081 -0.10512 0.03088 0.10911 0.63511
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.77647 0.10078 27.551 < 2e-16 ***
## log(Area_contruida) 0.56751 0.02803 20.245 < 2e-16 ***
## Banos 0.08324 0.01378 6.040 2.33e-09 ***
## Habitaciones -0.01388 0.01278 -1.086 0.278
## parqueaderos 0.05643 0.01259 4.484 8.37e-06 ***
## TipoCasa -0.14870 0.02144 -6.935 8.18e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1724 on 832 degrees of freedom
## Multiple R-squared: 0.6482, Adjusted R-squared: 0.6461
## F-statistic: 306.6 on 5 and 832 DF, p-value: < 2.2e-16
Interpretación de coeficientes: * Variable
Dummy TipoCasa en Modelo 1: A igualdad de área,
baños, habitaciones y parqueaderos, una casa cuesta en promedio 19.94
millones menos en comparación con un apartamento en este sector, lo que
refleja diferencias en costos de administración, amenidades de conjuntos
cerrados y densidad del suelo. * Variable Dummy
TipoCasa en Modelo 2: Tras aplicar el logaritmo,
el efecto porcentual aproximado se obtiene como \((\exp(\beta) - 1) \times 100\), indicando
una diferencia porcentual controlando por las demás covariables.
# 1. Multicolinealidad (VIF)
vif(mod_m1)
## Area_contruida Banos Habitaciones parqueaderos Tipo
## 1.916435 2.536031 1.613036 1.170912 1.860616
vif(mod_m2)
## log(Area_contruida) Banos Habitaciones parqueaderos
## 3.095729 2.897428 1.654309 1.177853
## Tipo
## 1.992013
# 2. Homocedasticidad (Breusch-Pagan)
bptest(mod_m1)
##
## studentized Breusch-Pagan test
##
## data: mod_m1
## BP = 240.06, df = 5, p-value < 2.2e-16
bptest(mod_m2)
##
## studentized Breusch-Pagan test
##
## data: mod_m2
## BP = 110.73, df = 5, p-value < 2.2e-16
# 3. Autocorrelación de residuos (Durbin-Watson)
dwtest(mod_m1)
##
## Durbin-Watson test
##
## data: mod_m1
## DW = 1.9225, p-value = 0.1259
## alternative hypothesis: true autocorrelation is greater than 0
Utilizamos el algoritmo step() en ambas direcciones
(both) basado en el Criterio de Información de Akaike (AIC).
# Selección paso a paso sobre el Modelo 2 (Logarítmico)
mod_step <- step(mod_m2, direction = "both", trace = TRUE)
## Start: AIC=-2939.87
## log(precio_millon) ~ log(Area_contruida) + Banos + Habitaciones +
## parqueaderos + Tipo
##
## Df Sum of Sq RSS AIC
## - Habitaciones 1 0.0351 24.777 -2940.7
## <none> 24.742 -2939.9
## - parqueaderos 1 0.5978 25.340 -2921.9
## - Banos 1 1.0847 25.827 -2905.9
## - Tipo 1 1.4301 26.172 -2894.8
## - log(Area_contruida) 1 12.1878 36.930 -2606.2
##
## Step: AIC=-2940.68
## log(precio_millon) ~ log(Area_contruida) + Banos + parqueaderos +
## Tipo
##
## Df Sum of Sq RSS AIC
## <none> 24.777 -2940.7
## + Habitaciones 1 0.0351 24.742 -2939.9
## - parqueaderos 1 0.5750 25.352 -2923.5
## - Banos 1 1.0530 25.830 -2907.8
## - Tipo 1 1.4686 26.246 -2894.4
## - log(Area_contruida) 1 12.9055 37.682 -2591.3
summary(mod_step)
##
## Call:
## lm(formula = log(precio_millon) ~ log(Area_contruida) + Banos +
## parqueaderos + Tipo, data = datos_lili)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.19952 -0.10459 0.03255 0.10827 0.63038
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.78119 0.10069 27.620 < 2e-16 ***
## log(Area_contruida) 0.55864 0.02682 20.830 < 2e-16 ***
## Banos 0.08137 0.01368 5.950 3.95e-09 ***
## parqueaderos 0.05506 0.01252 4.397 1.24e-05 ***
## TipoCasa -0.15033 0.02139 -7.027 4.40e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1725 on 833 degrees of freedom
## Multiple R-squared: 0.6477, Adjusted R-squared: 0.646
## F-statistic: 382.9 on 4 and 833 DF, p-value: < 2.2e-16
El procedimiento evalúa la eliminación secuencial de variables para
minimizar el AIC. Si una variable (como Habitaciones) no
aporta significancia adicional una vez controlado el área y los baños,
el modelo óptimo la excluye o retiene según el menor AIC obtenido.
Se predice el valor comercial estimado para un apartamento hipotético con las siguientes características: * Área construida: 85 m² * Baños: 2 * Habitaciones: 3 * Parqueaderos: 1 * Tipo: Apartamento
# Definición de la vivienda hipotética
nueva_vivienda <- data.frame(
Area_contruida = 85,
Banos = 2,
Habitaciones = 3,
parqueaderos = 1,
Tipo = factor("Apartamento", levels = levels(datos_lili$Tipo))
)
# Predicción con Modelo 1 (Lineal)
pred_m1 <- predict(mod_m1, newdata = nueva_vivienda, interval = "confidence")
# Predicción con Modelo 2 / Stepwise (Logarítmico) -> Requiere función exponencial inversa
pred_log <- predict(mod_step, newdata = nueva_vivienda, interval = "confidence")
pred_m2_final <- exp(pred_log)
predicciones <- data.frame(
Modelo = c("Lineal (M1)", "Logarítmico Óptimo (M2)"),
Precio_Estimado_Millones = c(pred_m1[1], pred_m2_final[1]),
IC_Inferior_95 = c(pred_m1[2], pred_m2_final[2]),
IC_Superior_95 = c(pred_m1[3], pred_m2_final[3])
)
knitr::kable(predicciones, digits = 2, caption = "Predicción de precio para vivienda hipotética (85 m², 2 baños, 1 parqueadero)")
| Modelo | Precio_Estimado_Millones | IC_Inferior_95 | IC_Superior_95 |
|---|---|---|---|
| Lineal (M1) | 231.25 | 226.79 | 235.71 |
| Logarítmico Óptimo (M2) | 240.05 | 236.09 | 244.07 |
El Error Absoluto Medio (MAE) mide la magnitud media de los errores de predicción en las mismas unidades de la variable original (millones de pesos colombianos):
\[\text{MAE} = \frac{1}{n} \sum_{i=1}^n |y_i - \hat{y}_i|\]
# Valores observados reales
y_real <- datos_lili$precio_millon
# Predicciones en escala de millones
y_pred_m1 <- predict(mod_m1, newdata = datos_lili)
y_pred_m2 <- exp(predict(mod_step, newdata = datos_lili)) # Exponencial para volver a millones
# Cálculo de MAE
mae_m1 <- mean(abs(y_real - y_pred_m1))
mae_m2 <- mean(abs(y_real - y_pred_m2))
metricas <- data.frame(
Modelo = c("Modelo 1: Múltiple Lineal", "Modelo 2: Múltiple Logarítmico (Stepwise)"),
MAE_Millones = c(mae_m1, mae_m2)
)
knitr::kable(metricas, digits = 2, caption = "Comparación de Desempeño predictivo (MAE en Millones de COP)")
| Modelo | MAE_Millones |
|---|---|
| Modelo 1: Múltiple Lineal | 36.48 |
| Modelo 2: Múltiple Logarítmico (Stepwise) | 34.46 |
El modelo con especificación logarítmica reduce el error absoluto medio, lo que confirma que las transformaciones no lineales capturan de forma más precisa la dinámica del mercado inmobiliario.