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.
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.
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")
| 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 |
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()
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.
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()
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()
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()
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.
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.
Se comparan tres especificaciones para la relación entre precio y á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")
| 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.
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.
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.
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.
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
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.
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")
| 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.
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.
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.
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)")
| 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 |
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.