1. Introducción

Este informe analiza los precios de oferta de vivienda del barrio Bochalema, en Cali, a partir de la base de datos Datos_Vivienda.xlsx. El propósito es estudiar la relación entre el precio de los apartamentos y algunas de sus características físicas, mediante modelos de regresión lineal simple y múltiple.

El análisis se limita al barrio Bochalema. En la base original el barrio aparece registrado como bochalema y ciudad bochalema; se consideran ambas denominaciones para no excluir observaciones del mismo sector. La variable respuesta es precio_millon, expresada en millones de pesos. Las variables explicativas incluyen área construida, habitaciones, baños y estrato.

2. Preparación y filtrado de la información

2.1. Carga de librerías y base de datos

library(readxl)
library(dplyr)
library(ggplot2)
library(knitr)
library(lmtest)
library(MASS)

datos <- read_excel("C:/Users/almar/Downloads/Datos_Vivienda (1).xlsx", 
    col_types = c("text", "numeric", "numeric", 
        "numeric", "numeric", "text", "numeric", 
        "numeric", "text", "text", "numeric", 
        "numeric"))

# Se agrega un identificador para reconocer cada registro.
datos <- datos %>% mutate(id = row_number())

# Se normaliza el texto y se conservan únicamente los registros
# cuyo nombre de barrio contiene "bochalema".
datos_sub <- datos %>%
  filter(grepl("bochalema", Barrio, ignore.case = TRUE)) %>%
  mutate(
    estrato_5 = ifelse(Estrato == 5, 1, 0),
    estrato_5 = factor(estrato_5, levels = c(0, 1),
                       labels = c("Estrato 4", "Estrato 5"))
  )

cat("Número de registros del barrio Bochalema:", nrow(datos_sub))
## Número de registros del barrio Bochalema: 81
table(datos_sub$Barrio)
## 
##        bochalema ciudad bochalema 
##               33               48
table(datos_sub$Estrato)
## 
##  4  5 
## 62 19

Se identifican 81 registros correspondientes a apartamentos de Bochalema, incluyendo las dos formas de escritura encontradas en la columna Barrio. La base filtrada se utiliza en todos los análisis que siguen.

2.2. Estructura y resumen de variables

names(datos_sub)
##  [1] "Zona"               "piso"               "Estrato"           
##  [4] "precio_millon"      "Area_contruida"     "parqueaderos"      
##  [7] "Banos"              "Habitaciones"       "Tipo"              
## [10] "Barrio"             "cordenada_longitud" "Cordenada_latitud" 
## [13] "id"                 "estrato_5"
str(datos_sub)
## tibble [81 × 14] (S3: tbl_df/tbl/data.frame)
##  $ Zona              : chr [1:81] "Zona Sur" "Zona Sur" "Zona Sur" "Zona Sur" ...
##  $ piso              : num [1:81] 8 10 3 2 1 1 9 7 4 NA ...
##  $ Estrato           : num [1:81] 5 4 4 5 4 4 4 4 4 4 ...
##  $ precio_millon     : num [1:81] 300 195 175 180 275 290 192 210 185 230 ...
##  $ Area_contruida    : num [1:81] 90 60 59 63 99 98 63 80 63 69 ...
##  $ parqueaderos      : chr [1:81] "2" "NA" "1" "1" ...
##  $ Banos             : num [1:81] 2 2 2 2 2 3 2 2 2 3 ...
##  $ Habitaciones      : num [1:81] 3 2 2 3 3 3 2 3 2 3 ...
##  $ Tipo              : chr [1:81] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
##  $ Barrio            : chr [1:81] "ciudad bochalema" "ciudad bochalema" "bochalema" "ciudad bochalema" ...
##  $ cordenada_longitud: num [1:81] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ Cordenada_latitud : num [1:81] 3.43 3.42 3.43 3.42 3.42 ...
##  $ id                : int [1:81] 20 40 43 48 49 50 51 52 63 643 ...
##  $ estrato_5         : Factor w/ 2 levels "Estrato 4","Estrato 5": 2 1 1 2 1 1 1 1 1 1 ...
summary(datos_sub[, c("precio_millon", "Area_contruida",
                      "Habitaciones", "Banos", "Estrato")])
##  precio_millon   Area_contruida  Habitaciones       Banos          Estrato     
##  Min.   :118.0   Min.   :47     Min.   :2.000   Min.   :1.000   Min.   :4.000  
##  1st Qu.:165.0   1st Qu.:60     1st Qu.:2.000   1st Qu.:2.000   1st Qu.:4.000  
##  Median :200.0   Median :66     Median :3.000   Median :2.000   Median :4.000  
##  Mean   :200.7   Mean   :69     Mean   :2.716   Mean   :2.025   Mean   :4.235  
##  3rd Qu.:230.0   3rd Qu.:73     3rd Qu.:3.000   3rd Qu.:2.000   3rd Qu.:4.000  
##  Max.   :300.0   Max.   :99     Max.   :3.000   Max.   :3.000   Max.   :5.000
resumen <- datos_sub %>%
  summarise(
    ofertas = n(),
    precio_promedio = mean(precio_millon, na.rm = TRUE),
    precio_mediano = median(precio_millon, na.rm = TRUE),
    precio_minimo = min(precio_millon, na.rm = TRUE),
    precio_maximo = max(precio_millon, na.rm = TRUE),
    area_promedio = mean(Area_contruida, na.rm = TRUE),
    habitaciones_promedio = mean(Habitaciones, na.rm = TRUE),
    banos_promedio = mean(Banos, na.rm = TRUE)
  )
kable(resumen, digits = 2,
      caption = "Resumen descriptivo de las ofertas de Bochalema")
Resumen descriptivo de las ofertas de Bochalema
ofertas precio_promedio precio_mediano precio_minimo precio_maximo area_promedio habitaciones_promedio banos_promedio
81 200.69 200 118 300 69 2.72 2.02

2.3. Exploración gráfica

ggplot(datos_sub, aes(x = precio_millon)) +
  geom_histogram(fill = "steelblue", color = "white", bins = 12) +
  labs(title = "Distribución del precio de los apartamentos en Bochalema",
       x = "Precio (millones de pesos)", y = "Frecuencia") +
  theme_minimal()

El histograma permite observar la concentración y dispersión de los precios. La forma de la distribución ayuda a identificar posibles asimetrías y valores extremos, aspectos que se revisan posteriormente en los diagnósticos de los modelos.

ggplot(datos_sub, aes(x = Area_contruida, y = precio_millon)) +
  geom_point(alpha = 0.75, color = "steelblue") +
  geom_smooth(method = "lm", se = TRUE, color = "darkred") +
  labs(title = "Precio y área construida en Bochalema",
       x = "Área construida (m²)", y = "Precio (millones de pesos)") +
  theme_minimal()

3. Modelación de regresión lineal simple

Se plantean tres modelos simples. En cada uno se utiliza una sola variable explicativa para estudiar su relación individual con el precio de oferta.

3.1. Modelo simple 1: precio y área construida

La hipótesis es que los apartamentos con mayor área construida tienden a presentar precios de oferta más altos.

mod_simple1 <- lm(precio_millon ~ Area_contruida, data = datos_sub)
summary(mod_simple1)
## 
## Call:
## lm(formula = precio_millon ~ Area_contruida, data = datos_sub)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -68.244 -21.605  -2.341  15.117  66.839 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    -10.4478    19.3339   -0.54     0.59    
## Area_contruida   3.0601     0.2767   11.06   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 27.45 on 79 degrees of freedom
## Multiple R-squared:  0.6076, Adjusted R-squared:  0.6026 
## F-statistic: 122.3 on 1 and 79 DF,  p-value: < 2.2e-16

Interpretación. El intercepto representa el precio estimado cuando el área construida es cero; aunque es necesario para definir la recta, no tiene una interpretación práctica dentro del rango observado. El coeficiente estimado del área es 3.06 millones de pesos por m². Por tanto, en esta muestra, un metro cuadrado adicional se asocia con un cambio promedio estimado de esa magnitud en el precio. El valor p de la pendiente es 1.02^{-17}, por lo que se evalúa su significancia estadística con el umbral usual de 0,05.

ggplot(datos_sub, aes(Area_contruida, precio_millon)) +
  geom_point() +
  geom_smooth(method = "lm", se = TRUE, color = "red") +
  labs(title = "Modelo simple 1: precio según área construida",
       x = "Área construida (m²)", y = "Precio (millones)") +
  theme_minimal()

3.2. Modelo simple 2: precio y número de habitaciones

mod_simple2 <- lm(precio_millon ~ Habitaciones, data = datos_sub)
summary(mod_simple2)
## 
## Call:
## lm(formula = precio_millon ~ Habitaciones, data = datos_sub)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -89.793 -35.783   2.207  27.207  92.207 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    132.76      28.70   4.625 1.44e-05 ***
## Habitaciones    25.01      10.43   2.399   0.0188 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 42.31 on 79 degrees of freedom
## Multiple R-squared:  0.0679, Adjusted R-squared:  0.0561 
## F-statistic: 5.755 on 1 and 79 DF,  p-value: 0.0188

Interpretación. El coeficiente estimado de habitaciones es 25.01 millones de pesos. En el modelo simple, una habitación adicional se asocia con ese cambio promedio estimado en el precio. El valor p de la pendiente es 0.0188. Esta relación no controla por diferencias de área, estrato u otras características y no debe interpretarse como causal.

ggplot(datos_sub, aes(Habitaciones, precio_millon)) +
  geom_jitter(width = 0.08, height = 0, alpha = 0.65) +
  geom_smooth(method = "lm", se = TRUE, color = "red") +
  labs(title = "Modelo simple 2: precio según habitaciones",
       x = "Número de habitaciones", y = "Precio (millones)") +
  theme_minimal()

3.3. Modelo simple 3: precio y número de baños

mod_simple3 <- lm(precio_millon ~ Banos, data = datos_sub)
summary(mod_simple3)
## 
## Call:
## lm(formula = precio_millon ~ Banos, data = datos_sub)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -81.394 -34.394   0.606  26.606 100.606 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)  
## (Intercept)    94.29      43.26   2.179   0.0323 *
## Banos          52.55      21.24   2.474   0.0155 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 42.22 on 79 degrees of freedom
## Multiple R-squared:  0.07191,    Adjusted R-squared:  0.06017 
## F-statistic: 6.121 on 1 and 79 DF,  p-value: 0.0155

Interpretación. El coeficiente estimado de baños es 52.55 millones de pesos. En este modelo simple, un baño adicional se asocia con ese cambio promedio estimado en el precio. El valor p de la pendiente es 0.0155. El modelo no incorpora las demás características del inmueble.

ggplot(datos_sub, aes(Banos, precio_millon)) +
  geom_jitter(width = 0.08, height = 0, alpha = 0.65) +
  geom_smooth(method = "lm", se = TRUE, color = "red") +
  labs(title = "Modelo simple 3: precio según baños",
       x = "Número de baños", y = "Precio (millones)") +
  theme_minimal()

3.4. Validación de supuestos de los modelos simples

La revisión de los supuestos se realiza mediante cuatro gráficos de diagnóstico, la prueba de normalidad de Shapiro-Wilk y la prueba de Breusch-Pagan para heterocedasticidad. La independencia de los errores también depende del diseño y la forma de recolección de los datos; no puede garantizarse únicamente con los gráficos.

diagnostico <- function(modelo, nombre) {
  cat("\\n\\n###", nombre, "\\n")
  par(mfrow = c(2, 2))
  plot(modelo)
  par(mfrow = c(1, 1))
  cat("\\nPrueba Shapiro-Wilk (normalidad):\\n")
  print(shapiro.test(residuals(modelo)))
  cat("\\nPrueba Breusch-Pagan (homocedasticidad):\\n")
  print(lmtest::bptest(modelo))
}

diagnostico(mod_simple1, "Diagnóstico del modelo simple 1")
## \n\n### Diagnóstico del modelo simple 1 \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.98256, p-value = 0.3386
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 1.0852, df = 1, p-value = 0.2975
diagnostico(mod_simple2, "Diagnóstico del modelo simple 2")
## \n\n### Diagnóstico del modelo simple 2 \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.97692, p-value = 0.1513
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 2.8297, df = 1, p-value = 0.09253
diagnostico(mod_simple3, "Diagnóstico del modelo simple 3")
## \n\n### Diagnóstico del modelo simple 3 \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.96217, p-value = 0.01724
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 0.012361, df = 1, p-value = 0.9115

Criterios de interpretación.

  • Linealidad: en residuos frente a ajustados se espera una nube sin patrón curvo.
  • Normalidad: en el gráfico Q-Q los puntos deberían aproximarse a la línea. En Shapiro-Wilk, un valor p superior a 0,05 significa que no se rechaza la hipótesis de normalidad.
  • Homocedasticidad: se espera una dispersión aproximadamente constante. En Breusch-Pagan, un valor p superior a 0,05 significa que no se rechaza la hipótesis de varianza constante.
  • Observaciones influyentes: se revisan los residuos estudentizados, el leverage y la distancia de Cook.

Estos criterios no convierten las pruebas en una aprobación automática: también se deben observar los gráficos y considerar el tamaño de la muestra.

3.5. Evaluación de transformaciones logarítmicas

Se comparan tres especificaciones para la relación entre precio y área:

  1. Precio en escala original y logaritmo del área.
  2. Logaritmo del precio y área en escala original.
  3. Logaritmo del precio y logaritmo del área.
mod_log1 <- lm(precio_millon ~ log(Area_contruida), data = datos_sub)
mod_log2 <- lm(log(precio_millon) ~ Area_contruida, data = datos_sub)
mod_log3 <- lm(log(precio_millon) ~ log(Area_contruida), data = datos_sub)

comparacion_log <- data.frame(
  Modelo = c("Precio ~ Área", "Precio ~ log(Área)",
             "log(Precio) ~ Área", "log(Precio) ~ log(Área)"),
  R2 = c(summary(mod_simple1)$r.squared,
         summary(mod_log1)$r.squared,
         summary(mod_log2)$r.squared,
         summary(mod_log3)$r.squared),
  R2_ajustado = c(summary(mod_simple1)$adj.r.squared,
                  summary(mod_log1)$adj.r.squared,
                  summary(mod_log2)$adj.r.squared,
                  summary(mod_log3)$adj.r.squared),
  AIC = c(AIC(mod_simple1), AIC(mod_log1), AIC(mod_log2), AIC(mod_log3))
)
kable(comparacion_log, digits = 4,
      caption = "Comparación de especificaciones lineales y logarítmicas")
Comparación de especificaciones lineales y logarítmicas
Modelo R2 R2_ajustado AIC
Precio ~ Área 0.6076 0.6026 770.4669
Precio ~ log(Área) 0.6045 0.5995 771.0882
log(Precio) ~ Área 0.5685 0.5630 -79.9524
log(Precio) ~ log(Área) 0.5774 0.5721 -81.6505
diagnostico(mod_log1, "Modelo precio frente a logaritmo del área")
## \n\n### Modelo precio frente a logaritmo del área \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.98679, p-value = 0.5765
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 0.58273, df = 1, p-value = 0.4452
diagnostico(mod_log2, "Modelo logaritmo del precio frente al área")
## \n\n### Modelo logaritmo del precio frente al área \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.98968, p-value = 0.7686
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 4.521, df = 1, p-value = 0.03348
diagnostico(mod_log3, "Modelo logaritmo del precio frente a logaritmo del área")
## \n\n### Modelo logaritmo del precio frente a logaritmo del área \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.99158, p-value = 0.8811
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 3.5333, df = 1, p-value = 0.06015

Interpretación de las transformaciones. En el modelo precio_millon ~ log(Area_contruida), el coeficiente aproxima el cambio en millones de pesos asociado con un aumento porcentual del área: un incremento del 1% se asocia aproximadamente con el coeficiente dividido por 100. En el modelo log-log, la pendiente se interpreta como una elasticidad: un aumento del 1% en el área se asocia aproximadamente con un cambio porcentual igual a la pendiente en el precio.

La decisión de transformar no se toma únicamente por el R². Se consideran conjuntamente los gráficos de residuos, normalidad, homocedasticidad, AIC y la facilidad de interpretación. Los modelos con respuesta logarítmica deben interpretarse en escala logarítmica; para predecir precios en millones se debe aplicar la transformación inversa y tener presente el sesgo de retransformación.

4. Modelación de regresión lineal múltiple

La regresión múltiple permite estudiar simultáneamente varias características de los apartamentos. Así, cada coeficiente se interpreta manteniendo constantes las demás variables incluidas en el modelo.

4.1. Modelo múltiple 1: variables cuantitativas

Se incorporan área construida, habitaciones y baños como variables explicativas.

mod_multiple1 <- lm(precio_millon ~ Area_contruida + Habitaciones + Banos,
                    data = datos_sub)
summary(mod_multiple1)
## 
## Call:
## lm(formula = precio_millon ~ Area_contruida + Habitaciones + 
##     Banos, data = datos_sub)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -68.72 -19.94  -2.05  16.07  63.96 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    -43.4133    33.6853  -1.289    0.201    
## Area_contruida   2.9268     0.2969   9.858  2.7e-15 ***
## Habitaciones     6.9157     6.9985   0.988    0.326    
## Banos           11.5475    14.3957   0.802    0.425    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 27.52 on 77 degrees of freedom
## Multiple R-squared:  0.6157, Adjusted R-squared:  0.6007 
## F-statistic: 41.12 on 3 and 77 DF,  p-value: 5.735e-16

Interpretación.

  • Área construida: su coeficiente representa el cambio promedio estimado en el precio por cada metro cuadrado adicional, manteniendo constantes las habitaciones y los baños.
  • Habitaciones: representa el cambio promedio estimado en el precio por una habitación adicional, manteniendo constantes el área y los baños.
  • Baños: representa el cambio promedio estimado en el precio por un baño adicional, manteniendo constantes el área y las habitaciones.
  • R²: indica la proporción de variabilidad del precio explicada conjuntamente por las variables incluidas. El R² ajustado penaliza la incorporación de variables que no aportan suficiente información.

La significancia estadística de cada coeficiente se determina con su valor p. La interpretación definitiva debe considerar los resultados que genere la ejecución del documento.

4.2. Modelo múltiple 2: incorporación de variable dummy

Se crea una variable indicadora para distinguir los apartamentos de estrato 5 de los de estrato 4. La categoría de referencia es el estrato 4.

mod_multiple2 <- lm(precio_millon ~ Area_contruida + Habitaciones +
                      Banos + estrato_5, data = datos_sub)
summary(mod_multiple2)
## 
## Call:
## lm(formula = precio_millon ~ Area_contruida + Habitaciones + 
##     Banos + estrato_5, data = datos_sub)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -81.21 -18.63  -3.16  17.78  66.84 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        -46.5349    32.5785  -1.428   0.1573    
## Area_contruida       2.7737     0.2932   9.459 1.77e-14 ***
## Habitaciones         7.2624     6.7651   1.074   0.2864    
## Banos               15.7443    14.0107   1.124   0.2647    
## estrato_5Estrato 5  18.1263     7.1436   2.537   0.0132 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 26.6 on 76 degrees of freedom
## Multiple R-squared:  0.6457, Adjusted R-squared:  0.627 
## F-statistic: 34.62 on 4 and 76 DF,  p-value: < 2.2e-16

Interpretación de la variable dummy. La variable estrato_5 toma el valor 1 para los apartamentos de estrato 5 y 0 para los de estrato 4. Su coeficiente mide la diferencia promedio estimada de precio entre ambos estratos, manteniendo constantes el área, las habitaciones y los baños. Si el coeficiente es positivo, el estrato 5 presenta un precio estimado mayor que el estrato 4; si es negativo, presenta uno menor. Su valor p permite evaluar si la diferencia es estadísticamente significativa.

table(datos_sub$Estrato, datos_sub$estrato_5)
##    
##     Estrato 4 Estrato 5
##   4        62         0
##   5         0        19

4.3. Validación de supuestos de los modelos múltiples

diagnostico(mod_multiple1, "Diagnóstico del modelo múltiple 1")
## \n\n### Diagnóstico del modelo múltiple 1 \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.98459, p-value = 0.4422
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 4.0529, df = 3, p-value = 0.2558
diagnostico(mod_multiple2, "Diagnóstico del modelo múltiple 2")
## \n\n### Diagnóstico del modelo múltiple 2 \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.98476, p-value = 0.452
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 4.6175, df = 4, p-value = 0.3288

Se aplican los mismos criterios de linealidad, normalidad, homocedasticidad e identificación de observaciones influyentes. Si se presentan patrones en los residuos, desviaciones importantes en el Q-Q plot o evidencia de heterocedasticidad, se debe reconocer esa limitación al interpretar los resultados.

4.4. Evaluación de transformaciones logarítmicas en el modelo múltiple

mod_multiple_log <- lm(log(precio_millon) ~ Area_contruida +
                         Habitaciones + Banos + estrato_5,
                       data = datos_sub)
summary(mod_multiple_log)
## 
## Call:
## lm(formula = log(precio_millon) ~ Area_contruida + Habitaciones + 
##     Banos + estrato_5, data = datos_sub)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.39871 -0.08305 -0.00985  0.08872  0.33499 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        4.036551   0.171395  23.551  < 2e-16 ***
## Area_contruida     0.013271   0.001543   8.603  7.7e-13 ***
## Habitaciones       0.035534   0.035591   0.998   0.3213    
## Banos              0.103113   0.073710   1.399   0.1659    
## estrato_5Estrato 5 0.089353   0.037582   2.378   0.0199 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1399 on 76 degrees of freedom
## Multiple R-squared:  0.6088, Adjusted R-squared:  0.5882 
## F-statistic: 29.57 on 4 and 76 DF,  p-value: 7.833e-15
diagnostico(mod_multiple_log, "Modelo múltiple con logaritmo del precio")
## \n\n### Modelo múltiple con logaritmo del precio \n

## \nPrueba Shapiro-Wilk (normalidad):\n
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo)
## W = 0.98549, p-value = 0.4943
## 
## \nPrueba Breusch-Pagan (homocedasticidad):\n
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 6.1522, df = 4, p-value = 0.1881
comparacion_multiple <- data.frame(
  Modelo = c("Múltiple 1: precio original",
             "Múltiple 2: incluye dummy",
             "Múltiple log: log(precio)"),
  R2 = c(summary(mod_multiple1)$r.squared,
         summary(mod_multiple2)$r.squared,
         summary(mod_multiple_log)$r.squared),
  R2_ajustado = c(summary(mod_multiple1)$adj.r.squared,
                  summary(mod_multiple2)$adj.r.squared,
                  summary(mod_multiple_log)$adj.r.squared),
  AIC = c(AIC(mod_multiple1), AIC(mod_multiple2), AIC(mod_multiple_log))
)
kable(comparacion_multiple, digits = 4,
      caption = "Comparación de modelos múltiples")
Comparación de modelos múltiples
Modelo R2 R2_ajustado AIC
Múltiple 1: precio original 0.6157 0.6007 772.7758
Múltiple 2: incluye dummy 0.6457 0.6270 768.1889
Múltiple log: log(precio) 0.6088 0.5882 -81.8955

La comparación debe considerar que el modelo con respuesta logarítmica está en otra escala, por lo que su R² y AIC no se deben comparar mecánicamente con los modelos de precio original. Se revisan especialmente los diagnósticos de residuos y la interpretación de los coeficientes.

5. Selección de variables: procedimiento Step by Step

Se utiliza el procedimiento paso a paso basado en el criterio AIC, partiendo del modelo completo que incluye las variables cuantitativas y la dummy. El procedimiento agrega o elimina variables para buscar una especificación con menor AIC.

modelo_nulo <- lm(precio_millon ~ 1, data = datos_sub)
modelo_completo <- lm(precio_millon ~ Area_contruida + Habitaciones +
                        Banos + estrato_5, data = datos_sub)

modelo_step <- step(modelo_completo,
                    scope = list(lower = formula(modelo_nulo),
                                 upper = formula(modelo_completo)),
                    direction = "both", trace = 0)
summary(modelo_step)
## 
## Call:
## lm(formula = precio_millon ~ Area_contruida + estrato_5, data = datos_sub)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -80.203 -19.650  -2.262  18.033  69.762 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)         -6.2344    18.8620  -0.331   0.7419    
## Area_contruida       2.9412     0.2733  10.761   <2e-16 ***
## estrato_5Estrato 5  17.0233     7.1111   2.394   0.0191 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 26.67 on 78 degrees of freedom
## Multiple R-squared:  0.6344, Adjusted R-squared:  0.625 
## F-statistic: 67.68 on 2 and 78 DF,  p-value: < 2.2e-16
formula(modelo_step)
## precio_millon ~ Area_contruida + estrato_5

Interpretación. El procedimiento selecciona una combinación de variables de acuerdo con el AIC. Un AIC menor representa un equilibrio entre ajuste y complejidad dentro de los modelos comparados. La selección automática no reemplaza el criterio teórico: se debe verificar que las variables seleccionadas tengan sentido para explicar el precio de los apartamentos de Bochalema.

6. Predicción hipotética y evaluación del error

Se construye un escenario hipotético de un apartamento de 70 m², con 3 habitaciones, 2 baños y estrato 5. La predicción corresponde a una estimación del modelo y no al precio de una vivienda identificada en la base.

nuevo_apartamento <- data.frame(
  Area_contruida = 70,
  Habitaciones = 3,
  Banos = 2,
  estrato_5 = factor("Estrato 5",
                     levels = levels(datos_sub$estrato_5))
)

prediccion <- predict(mod_multiple2, newdata = nuevo_apartamento,
                      interval = "prediction")
prediccion
##        fit      lwr      upr
## 1 219.0228 164.5162 273.5295

La predicción puntual corresponde al precio estimado en millones de pesos. El intervalo de predicción presenta un rango de valores posibles para una observación individual, bajo los supuestos del modelo.

6.1. Evaluación con MAE

Para evaluar el desempeño predictivo, se separan los datos en entrenamiento y prueba. Se utiliza una semilla fija para que la división sea reproducible. El MAE calcula el promedio de los errores absolutos entre los precios observados y los predichos.

set.seed(123)
n <- nrow(datos_sub)
indices_entrenamiento <- sample(seq_len(n), size = floor(0.80 * n))

entrenamiento <- datos_sub[indices_entrenamiento, ]
prueba <- datos_sub[-indices_entrenamiento, ]

modelo_entrenamiento <- lm(
  precio_millon ~ Area_contruida + Habitaciones + Banos + estrato_5,
  data = entrenamiento
)

predicciones_prueba <- predict(modelo_entrenamiento, newdata = prueba)

MAE <- mean(abs(prueba$precio_millon - predicciones_prueba))
MAE
## [1] 22.99057

Interpretación del MAE. El MAE expresa, en millones de pesos, el error absoluto promedio de las predicciones en el conjunto de prueba. Por ejemplo, un MAE de 20 indicaría que las predicciones se alejan en promedio 20 millones de pesos de los precios observados. El resultado concreto se obtiene al ejecutar el código.

evaluacion <- data.frame(
  Precio_observado = prueba$precio_millon,
  Precio_predicho = as.numeric(predicciones_prueba),
  Error_absoluto = abs(prueba$precio_millon - predicciones_prueba)
)
kable(head(evaluacion, 10), digits = 2,
      caption = "Comparación de precios observados y predichos (primeros 10 casos)")
Comparación de precios observados y predichos (primeros 10 casos)
Precio_observado Precio_predicho Error_absoluto
300 270.60 29.40
195 168.32 26.68
175 165.62 9.38
180 197.85 17.85
180 195.26 15.26
147 168.32 21.32
175 214.12 39.12
158 176.19 18.19
230 192.35 37.65
160 176.19 16.19

7. Conclusiones

El análisis se concentra en 81 ofertas de apartamentos registradas en Bochalema y permite estudiar la relación entre el precio y características como el área construida, el número de habitaciones, los baños y el estrato.

Los tres modelos simples permiten observar la relación individual de cada variable con el precio. Los modelos múltiples amplían el análisis al controlar simultáneamente varias características y al incorporar una variable dummy para diferenciar los apartamentos de estrato 5 frente a los de estrato 4.

La evaluación de supuestos y de transformaciones logarítmicas permite determinar si la especificación lineal resulta razonable o si presenta limitaciones. La selección paso a paso aporta una comparación adicional de variables mediante AIC. Finalmente, la predicción hipotética y el MAE permiten ilustrar el uso del modelo y evaluar su error fuera de la muestra de entrenamiento.

Las conclusiones definitivas deben redactarse a partir de los resultados numéricos, pruebas y gráficos generados al ejecutar el documento en RStudio. Los modelos son asociaciones estadísticas y no demuestran relaciones causales.