Introducción y Carga de Datos

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

1. Modelación Simple

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)

Planteamiento e Interpretación de los 3 Modelos

# 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\%\)).

Validación de Supuestos (Modelos Simples)

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
  • Resultado: La prueba de Breusch-Pagan arroja un \(p\)-valor inferior a 0.05, lo que evidencia heterocedasticidad. Además, el gráfico Q-Q presenta colas pesadas, indicando no normalidad de los errores.

Pertinencia de la Transformación Logarítmica

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%.


2. Modelación Múltiple

Planteamiento de Modelos Múltiples

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.

Validación de Supuestos y Multicolinealidad

# 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
  • Multicolinealidad: Todos los valores de VIF son inferiores a 5 (la mayoría cercanos a 1-2), lo que indica que no existe multicolinealidad severa entre las variables predictoras.
  • Independencia: El estadístico de Durbin-Watson es cercano a 2 (1.92), indicando ausencia de autocorrelación en los residuos.

Selección de Variables Paso a Paso (Step by Step)

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.

Predicción Hipotética

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)")
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

Métricas de Evaluación: Cálculo del MAE

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)")
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.