1 Introducción y problema

Pregunta de investigación: ¿Qué predice mejor el precio anunciado de un apartamento en Valle del Lili: el área, la distribución de habitaciones o su ubicación vertical y estrato?

En Valle del Lili existe una oferta numerosa de apartamentos con áreas relativamente próximas. Esto permite examinar si unas pocas características —área, piso y estrato— aportan información suficiente para estimar precios. La presencia de un apartamento con área muy superior al resto también abre una pregunta importante sobre la sensibilidad de los modelos a registros extremos.

La variable dependiente es precio_millon, expresada en millones de pesos colombianos. Se propone una regresión lineal sobre precios anunciados, no sobre ventas efectivas. La posible usuaria del análisis es un analista de oferta inmobiliaria que orienta comparaciones entre apartamentos del mismo barrio. La interpretación será de asociación estadística, no de causalidad.

Hipótesis general: algunas características físicas de las viviendas del mismo barrio se asocian con variaciones del precio publicado, pero esas relaciones pueden perder utilidad ante observaciones extremas o elementos no medidos como calidad de acabados, ubicación microterritorial y estado del inmueble.

2 Lectura, filtro y limpieza de la base

Esta fase se ejecuta en R a partir del Excel original. El criterio de inclusión es barrio Valle del Lili y tipo apartamentos; se descartan observaciones con precio, área u otras variables indispensables faltantes o imposibles y, después, duplicados exactos en las columnas originales. No se eliminan automáticamente las viviendas caras o grandes por ser atípicas.

Se necesita piso para estudiar ubicación vertical; muchos anuncios no lo informan. Por eso el análisis utiliza únicamente los apartamentos con piso registrado y se reconoce el posible sesgo de selección.

if (!file.exists("Datos_Vivienda.xlsx")) stop("Falta Datos_Vivienda.xlsx: descomprime TODO el ZIP y abre el proyecto .Rproj de esta carpeta.")
if (!requireNamespace("readxl",quietly=TRUE)) stop("Instala readxl: install.packages('readxl')")
base_original <- as.data.frame(readxl::read_excel("Datos_Vivienda.xlsx", sheet="Datos Vivienda"))
base_original$id_original <- seq_len(nrow(base_original))+1L
columnas_base <- setdiff(names(base_original),"id_original")
for (v in c("precio_millon","Area_contruida","Banos","Habitaciones","parqueaderos","piso","Estrato")) {
  base_original[[v]] <- suppressWarnings(as.numeric(as.character(base_original[[v]])))
}
candidatos <- base_original[tolower(trimws(base_original$Barrio))=="valle del lili" &
                             tolower(trimws(base_original$Tipo))=="apartamento",,drop=FALSE]
filas_validas <- with(candidatos,
  is.finite(precio_millon) & precio_millon>0 &
  is.finite(Area_contruida) & Area_contruida>0 &
  is.finite(Banos) & Banos>=1 &
  is.finite(Habitaciones) & Habitaciones>=1 &
  is.finite(piso) & piso>=1 & piso<=30 &
  is.finite(Estrato) & Estrato>=1 & Estrato<=6)
validos <- candidatos[filas_validas,,drop=FALSE]
repetidos <- duplicated(validos[,columnas_base,drop=FALSE])
datos <- validos[!repetidos,,drop=FALSE]
datos$estrato_alto <- as.integer(datos$Estrato>=5)
datos$fold <- as.integer((datos$id_original*73+17) %% 5)+1L
stopifnot(nrow(datos)>30L)
knitr::kable(data.frame(
 Etapa=c("Base completa","Apartamentos en Valle del Lili","Registros válidos","Anuncios finales sin duplicados"),
 Registros=c(nrow(base_original),nrow(candidatos),nrow(validos),nrow(datos))),
 caption="Trazabilidad del filtro aplicado en R")
Trazabilidad del filtro aplicado en R
Etapa Registros
Base completa 8319
Apartamentos en Valle del Lili 841
Registros válidos 649
Anuncios finales sin duplicados 639

La muestra analítica final contiene 639 anuncios, frente a 841 registros originalmente filtrados por barrio y tipo. La pérdida de 202 registros se explica por requisitos de completitud, valores inválidos y/o duplicados exactos. No es una muestra aleatoria representativa de todas las ventas del barrio.

relevantes <- c("precio_millon","Area_contruida","Banos","Habitaciones")
relevantes <- c(relevantes, if ("piso" %in% names(datos) && "estrato_alto" %in% names(datos)) c("piso","Estrato") else "parqueaderos")
faltantes_candidatos <- data.frame(Variable=relevantes,
  N_faltantes=sapply(candidatos[relevantes],function(x)sum(!is.finite(x))))
knitr::kable(faltantes_candidatos,caption="Calidad original de las variables indispensables")
Calidad original de las variables indispensables
Variable N_faltantes
precio_millon precio_millon 0
Area_contruida Area_contruida 0
Banos Banos 0
Habitaciones Habitaciones 0
piso piso 192
Estrato Estrato 0
cat("**Lectura de calidad.** Las filas se retiraron únicamente por la ausencia o invalidez de las variables necesarias para comparar los modelos en idénticas observaciones. La exclusión de anuncios incompletos puede inducir sesgo si estos anuncios corresponden a segmentos particulares del mercado.\n\n")
## **Lectura de calidad.** Las filas se retiraron únicamente por la ausencia o invalidez de las variables necesarias para comparar los modelos en idénticas observaciones. La exclusión de anuncios incompletos puede inducir sesgo si estos anuncios corresponden a segmentos particulares del mercado.

3 Estadística descriptiva y visualizaciones

Para cada variable se presentan tendencia central, dispersión y rango. La unidad de precio siempre es millones de COP y la unidad de área es m².

vars_numericas <- c("precio_millon","Area_contruida","Banos","Habitaciones")
vars_numericas <- c(vars_numericas, if ("estrato_alto" %in% names(datos)) c("piso","Estrato") else "parqueaderos")
resumen_descriptivo <- do.call(rbind,lapply(vars_numericas,function(v){
 x <- datos[[v]]
 data.frame(Variable=v,N=length(x),Min=min(x),P25=unname(quantile(x,.25)),
            Media=mean(x),Mediana=median(x),P75=unname(quantile(x,.75)),
            Max=max(x),Desv=sd(x))
}))
resumen_redondeado <- resumen_descriptivo
resumen_redondeado[-1] <- lapply(resumen_redondeado[-1],round,2)
knitr::kable(resumen_redondeado, caption="Estadísticos de las viviendas seleccionadas")
Estadísticos de las viviendas seleccionadas
Variable N Min P25 Media Mediana P75 Max Desv
precio_millon 639 116 165 224.35 225 260 415 63.44
Area_contruida 639 43 60 75.50 72 85 932 37.05
Banos 639 1 2 2.17 2 2 3 0.42
Habitaciones 639 2 3 2.77 3 3 4 0.46
piso 639 1 2 5.19 5 8 12 2.97
Estrato 639 3 4 4.39 4 5 5 0.49

Interpretación de tendencia central: el precio medio anunciado es de 224,35 millones, frente a una mediana de 225,00 millones. La distancia entre ambas resume la posible asimetría del mercado. El 50 % central de los precios se sitúa aproximadamente entre 165,00 y 260,00 millones; no deben confundirse estos valores con precios de venta negociados.

par(mfrow=c(1,2),mar=c(4,4,3,1))
hist(datos$precio_millon,breaks="FD",col="#D8E5F0",border="white",
     main="Precios anunciados",xlab="Millones de COP")
hist(datos$Area_contruida,breaks="FD",col="#D3E9DE",border="white",
     main="Áreas construidas",xlab="Metros cuadrados")

par(mfrow=c(1,1))

Interpretación de histogramas: el primero muestra si el precio se concentra alrededor de un rango o si existe una cola de inmuebles caros. El segundo permite comprobar si las áreas típicas son homogéneas o si unos pocos inmuebles muy grandes pueden dominar la pendiente de una recta. En Valle del Lili existe una oferta numerosa de apartamentos con áreas relativamente próximas. Esto permite examinar si unas pocas características —área, piso y estrato— aportan información suficiente para estimar precios. La presencia de un apartamento con área muy superior al resto también abre una pregunta importante sobre la sensibilidad de los modelos a registros extremos.

par(mfrow=c(1,2),mar=c(4,4,3,1))
boxplot(datos$precio_millon,horizontal=TRUE,col="#BDD1E4",main="Precio",
        xlab="Millones COP")
boxplot(datos$Area_contruida,horizontal=TRUE,col="#B8DFC8",main="Área",
        xlab="m²")

par(mfrow=c(1,1))
fence <- function(x) {
 q <- quantile(x,c(.25,.75)); c(inferior=q[1]-1.5*IQR(x),superior=q[2]+1.5*IQR(x))
}
p_at <- fence(datos$precio_millon)
a_at <- fence(datos$Area_contruida)
conteo_p <- sum(datos$precio_millon<p_at[1]|datos$precio_millon>p_at[2])
conteo_a <- sum(datos$Area_contruida<a_at[1]|datos$Area_contruida>a_at[2])
knitr::kable(data.frame(Variable=c("Precio","Área"),
  Limite_inferior=c(p_at[1],a_at[1]),Limite_superior=c(p_at[2],a_at[2]),
  Fuera_de_limites=c(conteo_p,conteo_a)),digits=2,caption="Alertas de atípicos por 1,5 × IQR")
Alertas de atípicos por 1,5 × IQR
Variable Limite_inferior Limite_superior Fuera_de_limites
Precio 22.5 402.5 4
Área 22.5 122.5 1

Interpretación del boxplot y atípicos: se marcaron 4 precios y 1 áreas fuera de los límites IQR. Son alertas, no una prueba de error de digitación; una vivienda grande puede ser legítima. Se conservan y se examina su impacto por el diagnóstico de influencia y la validación cruzada. En particular, el área máxima observada es 932,00 m².

Advertencia específica de Valle del Lili: el registro con mayor área informa 932,00 m², muy por encima del límite IQR de 122,50 m². No disponemos de una verificación independiente del anuncio: excluirlo por conveniencia sería incorrecto. Compararemos modelos lineales y logarítmicos para estudiar cuánto cambia la estabilidad predictiva sin esconder el dato.

4 Exploración bivariada y correlaciones

Las asociaciones de Pearson evalúan relaciones lineales; no prueban causalidad. En cada diagrama, la recta roja es el ajuste lineal simple estimado con las observaciones del barrio.

variables_simple <- c("Area_contruida","piso","Habitaciones")
correlaciones <- data.frame(Predictor=variables_simple,
  Correlacion_Pearson=sapply(variables_simple,function(x)cor(datos$precio_millon,datos[[x]])))
knitr::kable(correlaciones,digits=3,caption="Correlaciones de Pearson con el precio")
Correlaciones de Pearson con el precio
Predictor Correlacion_Pearson
Area_contruida Area_contruida 0.408
piso piso 0.269
Habitaciones Habitaciones 0.370
par(mfrow=c(1,3),mar=c(4,4,3,1))
for (v in variables_simple) {
 plot(jitter(datos[[v]]),datos$precio_millon,pch=19,cex=.55,
      col=rgb(.10,.25,.40,.28), xlab=v,ylab="Precio (millones COP)",main=paste("Precio vs",v))
 abline(lm(reformulate(v,"precio_millon"),data=datos),col="#BF5151",lwd=2)
}

par(mfrow=c(1,1))

Lectura de los tres diagramas: una nube ascendente sugiere asociación positiva, pero una gran dispersión vertical indica que inmuebles similares pueden tener precios muy distintos. En predictores discretos (baños, habitaciones, piso o parqueaderos) aparecen columnas de puntos; se agregó una pequeña separación visual para apreciar la concentración, sin modificar los datos usados en la regresión. Las correlaciones se interpretan junto al modelo y no de forma aislada.

5 Modelación de regresión lineal simple

Los tres modelos mantienen la misma Y y usan predictores distintos. Cada coeficiente expresa una diferencia promedio asociada, no un cambio que necesariamente ocurrirá si se modifica físicamente un inmueble.

s1 <- lm(precio_millon ~ Area_contruida, data=datos)
s2 <- lm(precio_millon ~ piso, data=datos)
s3 <- lm(precio_millon ~ Habitaciones, data=datos)
modelos_simples <- list("Modelo simple 1"=s1,"Modelo simple 2"=s2,"Modelo simple 3"=s3)
mapa <- c("Area_contruida"="área construida (m²)","Banos"="baños","Habitaciones"="habitaciones","piso"="piso","estrato_alto"="estrato alto (1=5 o 6)")
for (nm in names(modelos_simples)) {
 cat("\n\n### ",nm,"\n\n",sep="")
 print(summary(modelos_simples[[nm]]))
 lectura_coef(modelos_simples[[nm]],nm,mapa)
}

5.0.1 Modelo simple 1

Call: lm(formula = precio_millon ~ Area_contruida, data = datos)

Residuals: Min 1Q Median 3Q Max -523.94 -48.52 2.99 30.22 166.54

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 171.58283 5.20729 32.95 <2e-16 Area_contruida 0.69888 0.06193 11.29 <2e-16 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 57.96 on 637 degrees of freedom Multiple R-squared: 0.1666, Adjusted R-squared: 0.1653 F-statistic: 127.4 on 1 and 637 DF, p-value: < 2.2e-16

Interpretación completa de Modelo simple 1.

  • Intercepto: 171,58 millones de pesos es la predicción cuando todos los predictores valen cero. Si ese perfil no existe en la muestra, el intercepto es principalmente un punto de referencia matemático.

  • área construida (m²): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 0,70 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • Ajuste: R² = 16,66 % y R² ajustado = 16,53 %. La porción restante de la dispersión del precio sigue sin explicar. Un R² mayor no demuestra causalidad ni garantiza mejor predicción fuera de la muestra.

5.0.2 Modelo simple 2

Call: lm(formula = precio_millon ~ piso, data = datos)

Residuals: Min 1Q Median 3Q Max -112.915 -50.692 -2.522 38.942 199.674

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 194.5939 4.8715 39.945 < 2e-16 piso 5.7321 0.8146 7.037 5.09e-12 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 61.16 on 637 degrees of freedom Multiple R-squared: 0.07213, Adjusted R-squared: 0.07068 F-statistic: 49.52 on 1 and 637 DF, p-value: 5.087e-12

Interpretación completa de Modelo simple 2.

  • Intercepto: 194,59 millones de pesos es la predicción cuando todos los predictores valen cero. Si ese perfil no existe en la muestra, el intercepto es principalmente un punto de referencia matemático.

  • piso: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 5,73 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • Ajuste: R² = 7,21 % y R² ajustado = 7,07 %. La porción restante de la dispersión del precio sigue sin explicar. Un R² mayor no demuestra causalidad ni garantiza mejor predicción fuera de la muestra.

5.0.3 Modelo simple 3

Call: lm(formula = precio_millon ~ Habitaciones, data = datos)

Residuals: Min 1Q Median 3Q Max -115.729 -45.229 -5.229 39.271 183.771

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 84.23 14.15 5.953 4.36e-09 Habitaciones 50.50 5.03 10.040 < 2e-16 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 58.99 on 637 degrees of freedom Multiple R-squared: 0.1366, Adjusted R-squared: 0.1353 F-statistic: 100.8 on 1 and 637 DF, p-value: < 2.2e-16

Interpretación completa de Modelo simple 3.

  • Intercepto: 84,23 millones de pesos es la predicción cuando todos los predictores valen cero. Si ese perfil no existe en la muestra, el intercepto es principalmente un punto de referencia matemático.

  • habitaciones: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 50,50 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • Ajuste: R² = 13,66 % y R² ajustado = 13,53 %. La porción restante de la dispersión del precio sigue sin explicar. Un R² mayor no demuestra causalidad ni garantiza mejor predicción fuera de la muestra.

for (nm in names(modelos_simples)) {
  cat("\n\n### Diagnóstico: ",nm,"\n\n",sep="")
  mostrar_diagnostico(modelos_simples[[nm]],nm)
}

5.0.4 Diagnóstico: Modelo simple 1

Interpretación diagnóstica — Modelo simple 1. Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = < 0,001: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 16. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

5.0.5 Diagnóstico: Modelo simple 2

Interpretación diagnóstica — Modelo simple 2. Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = 0,2459: no se detecta heterocedasticidad con esta prueba, aunque conviene revisar el gráfico de residuos. Observaciones con Cook > 4/n: 26. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

5.0.6 Diagnóstico: Modelo simple 3

Interpretación diagnóstica — Modelo simple 3. Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = 0,0254: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 18. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

Los cuatro paneles usados en cada modelo son: residuos frente a valores ajustados (linealidad y varianza), Q-Q normal (forma de los errores), Scale-Location (dispersión de errores) y residuos frente a leverage (puntos influyentes). Se debe revisar el conjunto de evidencias: una sola prueba no confirma todos los supuestos.

6 Transformaciones logarítmicas en los modelos simples

Comparamos la especificación original con precio ~ log(área) y log(precio) ~ log(área). La primera conserva el precio en millones de pesos y interpreta cambios porcentuales de área. La segunda modela elasticidad precio-área. En los modelos con logaritmo del precio, no se compara directamente el R² con el de Y original; se retransfieren predicciones para evaluar MAE en millones de COP.

log_x_simple <- lm(precio_millon ~ log(Area_contruida),data=datos)
log_yx_simple <- lm(log(precio_millon) ~ log(Area_contruida),data=datos)
print(summary(log_x_simple))

Call: lm(formula = precio_millon ~ log(Area_contruida), data = datos)

Residuals: Min 1Q Median 3Q Max -527.73 -20.01 -1.00 19.05 114.29

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) -790.433 27.226 -29.03 <2e-16 log(Area_contruida) 236.519 6.337 37.32 <2e-16 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 35.56 on 637 degrees of freedom Multiple R-squared: 0.6862, Adjusted R-squared: 0.6857 F-statistic: 1393 on 1 and 637 DF, p-value: < 2.2e-16

lectura_coef(log_x_simple,"precio ~ log(área)",mapa)

Interpretación completa de precio ~ log(área).

  • Intercepto: -790,43 millones de pesos es la predicción cuando todos los predictores valen cero. Si ese perfil no existe en la muestra, el intercepto es principalmente un punto de referencia matemático.

  • Logaritmo del área: un aumento aproximado del 1 % en el área se asocia con 2,35 millones de pesos de cambio en el precio anunciado, manteniendo las otras variables constantes; hay evidencia estadística de una asociación (p < 0,05).

  • Ajuste: R² = 68,62 % y R² ajustado = 68,57 %. La porción restante de la dispersión del precio sigue sin explicar. Un R² mayor no demuestra causalidad ni garantiza mejor predicción fuera de la muestra.

print(summary(log_yx_simple))

Call: lm(formula = log(precio_millon) ~ log(Area_contruida), data = datos)

Residuals: Min 1Q Median 3Q Max -2.37738 -0.08847 0.01191 0.09683 0.50400

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.81705 0.12175 6.711 4.28e-11 log(Area_contruida) 1.06193 0.02834 37.472 < 2e-16 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.159 on 637 degrees of freedom Multiple R-squared: 0.6879, Adjusted R-squared: 0.6874 F-statistic: 1404 on 1 and 637 DF, p-value: < 2.2e-16

cat("**Elasticidad log-log:** el coeficiente del área es ",
  formatear(coef(log_yx_simple)["log(Area_contruida)"]),
  ". Esto representa aproximadamente ese porcentaje de variación del precio anunciado ante un 1 % de diferencia en área, sin atribuir causalidad.\n\n",sep="")

Elasticidad log-log: el coeficiente del área es 1,06. Esto representa aproximadamente ese porcentaje de variación del precio anunciado ante un 1 % de diferencia en área, sin atribuir causalidad.

mostrar_diagnostico(log_x_simple,"precio ~ log(área)")

Interpretación diagnóstica — precio ~ log(área). Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = < 0,001: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 25. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

mostrar_diagnostico(log_yx_simple,"log(precio) ~ log(área)")

Interpretación diagnóstica — log(precio) ~ log(área). Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = < 0,001: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 9. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

7 Dos modelos de regresión lineal múltiple

Modelo múltiple 1: precio ~ Area_contruida + Habitaciones + Banos. Evalúa qué características conservan asociación con el precio cuando se mantienen las otras constantes.

Modelo múltiple 2: precio ~ Area_contruida + piso + Banos + estrato_alto. Incorpora explícitamente una variable dummy: estrato_alto. Se asigna 1 a los apartamentos de estrato 5 o 6 y 0 a los de estrato 3 o 4.

La dummy estrato alto compara dos segmentos del mismo barrio, después de considerar área, piso y baños. No demuestra que cambiar el estrato de una vivienda cause una revalorización.

m1 <- lm(precio_millon ~ Area_contruida + Habitaciones + Banos,data=datos)
m2 <- lm(precio_millon ~ Area_contruida + piso + Banos + estrato_alto,data=datos)
print(summary(m1))

Call: lm(formula = precio_millon ~ Area_contruida + Habitaciones + Banos, data = datos)

Residuals: Min 1Q Median 3Q Max -303.066 -35.655 1.676 28.756 155.987

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) -33.96495 13.04053 -2.605 0.00941 ** Area_contruida 0.36349 0.05328 6.823 2.09e-11 Habitaciones 25.95724 4.19194 6.192 1.07e-09 Banos 73.12971 4.76032 15.362 < 2e-16 *** — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 46.86 on 635 degrees of freedom Multiple R-squared: 0.4569, Adjusted R-squared: 0.4544 F-statistic: 178.1 on 3 and 635 DF, p-value: < 2.2e-16

lectura_coef(m1,"Modelo múltiple 1",mapa)

Interpretación completa de Modelo múltiple 1.

  • Intercepto: -33,96 millones de pesos es la predicción cuando todos los predictores valen cero. Si ese perfil no existe en la muestra, el intercepto es principalmente un punto de referencia matemático.

  • área construida (m²): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 0,36 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • habitaciones: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 25,96 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • baños: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 73,13 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • Ajuste: R² = 45,69 % y R² ajustado = 45,44 %. La porción restante de la dispersión del precio sigue sin explicar. Un R² mayor no demuestra causalidad ni garantiza mejor predicción fuera de la muestra.

print(summary(m2))

Call: lm(formula = precio_millon ~ Area_contruida + piso + Banos + estrato_alto, data = datos)

Residuals: Min 1Q Median 3Q Max -277.959 -32.041 -3.017 31.134 147.258

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 26.02783 9.39507 2.770 0.00576 ** Area_contruida 0.31478 0.04998 6.299 5.61e-10 piso 3.59169 0.58975 6.090 1.96e-09 Banos 64.96628 4.51395 14.392 < 2e-16 estrato_alto 37.51514 3.78296 9.917 < 2e-16 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 43.75 on 634 degrees of freedom Multiple R-squared: 0.5273, Adjusted R-squared: 0.5243 F-statistic: 176.8 on 4 and 634 DF, p-value: < 2.2e-16

lectura_coef(m2,"Modelo múltiple 2 (con dummy)",mapa)

Interpretación completa de Modelo múltiple 2 (con dummy).

  • Intercepto: 26,03 millones de pesos es la predicción cuando todos los predictores valen cero. Si ese perfil no existe en la muestra, el intercepto es principalmente un punto de referencia matemático.

  • área construida (m²): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 0,31 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • piso: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 3,59 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • baños: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 64,97 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • estrato alto (1=5 o 6): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 37,52 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • Ajuste: R² = 52,73 % y R² ajustado = 52,43 %. La porción restante de la dispersión del precio sigue sin explicar. Un R² mayor no demuestra causalidad ni garantiza mejor predicción fuera de la muestra.

knitr::kable(data.frame(Modelo=c("Múltiple 1","Múltiple 2"),
 R2=c(summary(m1)$r.squared,summary(m2)$r.squared),
 R2_ajustado=c(summary(m1)$adj.r.squared,summary(m2)$adj.r.squared),
 AIC=c(AIC(m1),AIC(m2))),digits=3,
 caption="Comparación de ajuste y complejidad (misma Y y mismas filas)")
Comparación de ajuste y complejidad (misma Y y mismas filas)
Modelo R2 R2_ajustado AIC
Múltiple 1 0.457 0.454 6736.065
Múltiple 2 0.527 0.524 6649.428

Interpretación del contraste: una mejoría en R² al añadir predictores es esperable; por eso debe revisarse también el R² ajustado, el AIC y, sobre todo, el MAE fuera de muestra. Los coeficientes que pierdan significancia al incluir otras variables pueden reflejar correlación entre características, no ausencia absoluta de relación.

mostrar_diagnostico(m1,"Múltiple 1")

Interpretación diagnóstica — Múltiple 1. Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = < 0,001: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 26. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

mostrar_diagnostico(m2,"Múltiple 2")

Interpretación diagnóstica — Múltiple 2. Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = < 0,001: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 33. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

cat("\n\n**VIF: Múltiple 1** (inflación de varianza por asociación entre predictores).\n\n")

VIF: Múltiple 1 (inflación de varianza por asociación entre predictores).

print(knitr::kable(calcular_vif(m1)))
Variable VIF
Area_contruida 1.13
Habitaciones 1.10
Banos 1.19
cat("\n\n**VIF: Múltiple 2**.\n\n")

VIF: Múltiple 2.

print(knitr::kable(calcular_vif(m2)))
Variable VIF
Area_contruida 1.14
piso 1.02
Banos 1.22
estrato_alto 1.14

Lectura de VIF: valores cercanos a 1 implican poca colinealidad. Como regla exploratoria, cifras superiores a 5 ameritan revisar la estabilidad de los coeficientes. El VIF no mide calidad predictiva y, si un coeficiente es inestable, no debe interpretarse como un efecto aislado preciso.

8 Transformaciones logarítmicas en modelación múltiple

Se contrasta el modelo múltiple con logaritmo del área como predictor y otro con logaritmo del precio como respuesta. Se revisan sus residuos y se calcula MAE en las unidades originales de la vivienda.

m_logx <- lm(precio_millon ~ log(Area_contruida) + piso + Banos + estrato_alto,data=datos)
m_logy <- lm(log(precio_millon) ~ log(Area_contruida) + piso + Banos + estrato_alto,data=datos)
print(summary(m_logx))

Call: lm(formula = precio_millon ~ log(Area_contruida) + piso + Banos + estrato_alto, data = datos)

Residuals: Min 1Q Median 3Q Max -430.05 -18.14 -1.40 17.71 97.23

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) -637.4689 28.5204 -22.351 < 2e-16 log(Area_contruida) 183.6572 7.6002 24.165 < 2e-16 piso 2.1002 0.4435 4.735 2.70e-06 Banos 25.3204 3.7800 6.699 4.65e-11 estrato_alto 20.1299 2.9158 6.904 1.23e-11 *** — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 32.54 on 634 degrees of freedom Multiple R-squared: 0.7385, Adjusted R-squared: 0.7369 F-statistic: 447.7 on 4 and 634 DF, p-value: < 2.2e-16

lectura_coef(m_logx,"Múltiple con log(área)",mapa)

Interpretación completa de Múltiple con log(área).

  • Intercepto: -637,47 millones de pesos es la predicción cuando todos los predictores valen cero. Si ese perfil no existe en la muestra, el intercepto es principalmente un punto de referencia matemático.

  • Logaritmo del área: un aumento aproximado del 1 % en el área se asocia con 1,83 millones de pesos de cambio en el precio anunciado, manteniendo las otras variables constantes; hay evidencia estadística de una asociación (p < 0,05).

  • piso: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 2,10 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • baños: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 25,32 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • estrato alto (1=5 o 6): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 20,13 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • Ajuste: R² = 73,85 % y R² ajustado = 73,69 %. La porción restante de la dispersión del precio sigue sin explicar. Un R² mayor no demuestra causalidad ni garantiza mejor predicción fuera de la muestra.

print(summary(m_logy))

Call: lm(formula = log(precio_millon) ~ log(Area_contruida) + piso + Banos + estrato_alto, data = datos)

Residuals: Min 1Q Median 3Q Max -2.00174 -0.07119 0.00763 0.09417 0.46513

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.431046 0.129545 11.047 < 2e-16 log(Area_contruida) 0.859539 0.034522 24.898 < 2e-16 piso 0.009112 0.002015 4.523 7.27e-06 Banos 0.077613 0.017169 4.520 7.36e-06 estrato_alto 0.097559 0.013244 7.366 5.48e-13 *** — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.1478 on 634 degrees of freedom Multiple R-squared: 0.7317, Adjusted R-squared: 0.73 F-statistic: 432.3 on 4 and 634 DF, p-value: < 2.2e-16

cat("**Modelo log-log múltiple:** log(precio) es la respuesta. El coeficiente de log(área) es una elasticidad condicional; los coeficientes de otras variables aproximan variaciones relativas del precio. Los R² no se comparan directamente con los modelos cuya respuesta sigue en millones.\n\n")

Modelo log-log múltiple: log(precio) es la respuesta. El coeficiente de log(área) es una elasticidad condicional; los coeficientes de otras variables aproximan variaciones relativas del precio. Los R² no se comparan directamente con los modelos cuya respuesta sigue en millones.

knitr::kable(data.frame(Especificacion=c("Múltiple 2 original","Múltiple con log(área)","Múltiple con log(precio) y log(área)"),
 Shapiro_p=c(pruebas(m2)$Shapiro_p,pruebas(m_logx)$Shapiro_p,pruebas(m_logy)$Shapiro_p),
 BP_p=c(pruebas(m2)$BP_p,pruebas(m_logx)$BP_p,pruebas(m_logy)$BP_p)),
 digits=4,caption="Contraste de supuestos antes y después de las transformaciones")
Contraste de supuestos antes y después de las transformaciones
Especificacion Shapiro_p BP_p
Múltiple 2 original 0 0
Múltiple con log(área) 0 0
Múltiple con log(precio) y log(área) 0 0
mostrar_diagnostico(m_logx,"Múltiple con log(área)")

Interpretación diagnóstica — Múltiple con log(área). Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = < 0,001: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 37. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

mostrar_diagnostico(m_logy,"Múltiple con log(precio) y log(área)")

Interpretación diagnóstica — Múltiple con log(precio) y log(área). Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = < 0,001: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 14. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

Interpretación de las transformaciones: preferimos un cambio funcional solo cuando mejora la forma de los residuos y/o reduce el MAE medido en millones de pesos. La normalidad perfecta no es requisito para predecir; sí importa comprender si los errores aumentan con el nivel de precio o si unas pocas observaciones dominan el ajuste.

9 Selección de variables Step by Step mediante AIC

Se parte de un modelo completo con variables disponibles y se aplica step() en ambas direcciones, considerando AIC. El procedimiento busca un balance de ajuste y complejidad, no identifica variables causalmente necesarias. En validación cruzada se repite la selección usando exclusivamente el conjunto de entrenamiento, para evitar utilizar información de la prueba.

formula_completa <- precio_millon ~ Area_contruida + Habitaciones + Banos + piso + estrato_alto
modelo_completo <- lm(formula_completa,data=datos)
paso <- step(modelo_completo,
             scope=list(lower=~1,upper=formula_completa),
             direction="both",trace=TRUE)

Start: AIC=4793.18 precio_millon ~ Area_contruida + Habitaciones + Banos + piso + estrato_alto

             Df Sum of Sq     RSS    AIC

1135050 4793.2 - Area_contruida 1 60094 1195144 4824.1 - piso 1 73939 1208989 4831.5 - Habitaciones 1 78716 1213766 4834.0 - estrato_alto 1 179725 1314775 4885.1 - Banos 1 304012 1439062 4942.8

print(formula(paso))

precio_millon ~ Area_contruida + Habitaciones + Banos + piso + estrato_alto

print(summary(paso))

Call: lm(formula = precio_millon ~ Area_contruida + Habitaciones + Banos + piso + estrato_alto, data = datos)

Residuals: Min 1Q Median 3Q Max -249.262 -30.765 -1.696 27.354 140.671

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) -26.83369 12.09661 -2.218 0.0269 *
Area_contruida 0.28150 0.04863 5.789 1.11e-08 Habitaciones 25.11775 3.79102 6.626 7.40e-11 Banos 58.34985 4.48126 13.021 < 2e-16 piso 3.66577 0.57087 6.421 2.65e-10 estrato_alto 36.67520 3.66332 10.011 < 2e-16 *** — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 42.35 on 633 degrees of freedom Multiple R-squared: 0.5579, Adjusted R-squared: 0.5544 F-statistic: 159.8 on 5 and 633 DF, p-value: < 2.2e-16

lectura_coef(paso,"Modelo seleccionado por Stepwise",mapa)

Interpretación completa de Modelo seleccionado por Stepwise.

  • Intercepto: -26,83 millones de pesos es la predicción cuando todos los predictores valen cero. Si ese perfil no existe en la muestra, el intercepto es principalmente un punto de referencia matemático.

  • área construida (m²): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 0,28 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • habitaciones: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 25,12 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • baños: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 58,35 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • piso: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 3,67 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • estrato alto (1=5 o 6): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 36,68 millones de pesos más en el precio anunciado; hay evidencia estadística de una asociación (p < 0,05). La relación es estadísticamente detectable.

  • Ajuste: R² = 55,79 % y R² ajustado = 55,44 %. La porción restante de la dispersión del precio sigue sin explicar. Un R² mayor no demuestra causalidad ni garantiza mejor predicción fuera de la muestra.

cat("**Lectura de la selección:** las variables que permanecen son: ",
    paste(names(coef(paso))[-1],collapse=", "),
    ". Su AIC final es ",formatear(AIC(paso)),
    " frente a ",formatear(AIC(modelo_completo)),
    " del modelo completo. Un AIC menor favorece parsimonia SOLO cuando los modelos usan la misma respuesta y las mismas filas.\n\n",sep="")

Lectura de la selección: las variables que permanecen son: Area_contruida, Habitaciones, Banos, piso, estrato_alto. Su AIC final es 6.608,58 frente a 6.608,58 del modelo completo. Un AIC menor favorece parsimonia SOLO cuando los modelos usan la misma respuesta y las mismas filas.

mostrar_diagnostico(paso,"Stepwise seleccionado")

Interpretación diagnóstica — Stepwise seleccionado. Shapiro-Wilk p = < 0,001: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = < 0,001: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 30. Son señales para revisión; no se eliminan automáticamente. La independencia de los anuncios y la ausencia de variables omitidas no se prueban solo con estos gráficos.

10 Validación cruzada y métricas de predicción

Usamos cinco pliegues reproducibles y las mismas particiones para todos los modelos. Cada vez se entrena en cuatro pliegues y se predice el quinto. Para modelos con log(precio), se convierte la predicción a millones de pesos mediante exponencial y factor de smearing calculado exclusivamente sobre el entrenamiento. La comparación se realiza con MAE (error absoluto medio) y RMSE (penaliza más los errores muy grandes).

# Los pliegues quedaron definidos antes del modelado a partir del ID del Excel.
formulas_evaluar <- list(
 "Simple 1"=formula(s1),"Simple 2"=formula(s2),"Simple 3"=formula(s3),
 "Múltiple 1"=formula(m1),"Múltiple 2"=formula(m2),
 "Stepwise AIC (ajustado en cada pliegue)"=formula_completa,
 "Simple: precio ~ log(área)"=formula(log_x_simple),
 "Simple: log(precio) ~ log(área)"=formula(log_yx_simple),
 "Múltiple: precio ~ log(área)"=formula(m_logx),
 "Múltiple: log(precio) ~ log(área)"=formula(m_logy))
lista_cv <- lapply(names(formulas_evaluar),function(nm) {
 res <- comparar_cv(formulas_evaluar[[nm]],datos,
   es_log_y=grepl("log[(]precio_millon[)]",paste(deparse(formulas_evaluar[[nm]]),collapse="")),
   paso_a_paso=grepl("Stepwise",nm))
 data.frame(Modelo=nm,MAE_millones=res[["MAE"]],RMSE_millones=res[["RMSE"]])
})
tabla_cv <- do.call(rbind,lista_cv)
# Baseline, sin usar el precio de las filas evaluadas.
precios_reales <- numeric(0); base_estimado <- numeric(0)
for (k in 1:5) {
  prueba <- datos[datos$fold==k,,drop=FALSE]
  train <- datos[datos$fold!=k,,drop=FALSE]
  precios_reales <- c(precios_reales,prueba$precio_millon)
  base_estimado <- c(base_estimado,rep(median(train$precio_millon),nrow(prueba)))
}
mae_base <- mean(abs(precios_reales-base_estimado))
tabla_cv <- rbind(tabla_cv,data.frame(Modelo="Referencia: mediana del entrenamiento",
   MAE_millones=mae_base,RMSE_millones=sqrt(mean((precios_reales-base_estimado)^2))))
tabla_cv <- tabla_cv[order(tabla_cv$MAE_millones),]
knitr::kable(tabla_cv,digits=2,caption="Comparación predictiva en COP millones (menor es mejor)")
Comparación predictiva en COP millones (menor es mejor)
Modelo MAE_millones RMSE_millones
9 Múltiple: precio ~ log(área) 22.74 36.58
7 Simple: precio ~ log(área) 23.96 39.28
10 Múltiple: log(precio) ~ log(área) 28.59 177.41
8 Simple: log(precio) ~ log(área) 31.69 225.75
6 Stepwise AIC (ajustado en cada pliegue) 35.17 120.64
5 Múltiple 2 36.48 120.98
4 Múltiple 1 39.05 131.59
1 Simple 1 45.29 137.90
3 Simple 3 47.04 58.96
2 Simple 2 49.57 61.11
11 Referencia: mediana del entrenamiento 51.20 63.39
mejor_nombre <- tabla_cv$Modelo[tabla_cv$Modelo!="Referencia: mediana del entrenamiento"][1]
mejor_error <- tabla_cv$MAE_millones[tabla_cv$Modelo==mejor_nombre]
cat("\n\n**Interpretación del MAE:** el menor error entre los modelos estudiados corresponde a **",
    mejor_nombre,"**, con **",formatear(mejor_error)," millones COP** de diferencia absoluta promedio entre precio anunciado y estimado. ",
    "La referencia sin predictores tiene MAE **",formatear(mae_base)," millones**. ",
    "Esto NO significa que cada predicción falle exactamente ese monto; el error individual puede ser mucho mayor. ",
    "El RMSE permite identificar modelos más vulnerables a anuncios extremos.\n\n",sep="")

Interpretación del MAE: el menor error entre los modelos estudiados corresponde a Múltiple: precio ~ log(área), con 22,74 millones COP de diferencia absoluta promedio entre precio anunciado y estimado. La referencia sin predictores tiene MAE 51,20 millones. Esto NO significa que cada predicción falle exactamente ese monto; el error individual puede ser mucho mayor. El RMSE permite identificar modelos más vulnerables a anuncios extremos.

11 Predicción hipotética con predict()

Se plantean dos perfiles plausibles para Valle del Lili, sin sustituir una tasación profesional ni suponer una compra real. Se proyecta con el modelo Stepwise y con el modelo múltiple que usa logaritmo del área (para observar cómo cambia la estimación con distinta forma funcional).

escenarios <- data.frame(Area_contruida=c(75,65),Banos=c(2,2),Habitaciones=c(3,2),piso=c(7,3),estrato_alto=c(1,0))
print(knitr::kable(escenarios,caption="Dos perfiles hipotéticos usados en predict()"))
Dos perfiles hipotéticos usados en predict()
Area_contruida Banos Habitaciones piso estrato_alto
75 2 3 7 1
65 2 2 3 0
pronostico_step <- as.data.frame(predict(paso,newdata=escenarios,
                                        interval="prediction",level=.95))
pronostico_logx <- as.data.frame(predict(m_logx,newdata=escenarios,
                                        interval="prediction",level=.95))
tabla_pred <- data.frame(Perfil=c("Escenario 1","Escenario 2"),
  Step_fit=pronostico_step$fit,Step_inferior=pronostico_step$lwr,Step_superior=pronostico_step$upr,
  LogArea_fit=pronostico_logx$fit,LogArea_inferior=pronostico_logx$lwr,
  LogArea_superior=pronostico_logx$upr)
print(knitr::kable(tabla_pred,digits=2,caption="Predicciones e intervalos para un nuevo anuncio (millones COP)"))
Predicciones e intervalos para un nuevo anuncio (millones COP)
Perfil Step_fit Step_inferior Step_superior LogArea_fit LogArea_inferior LogArea_superior
Escenario 1 248.67 165.25 332.08 240.94 176.86 305.03
Escenario 2 169.40 85.94 252.86 186.13 122.12 250.14
cat("\n\n**Interpretación:** para el primer perfil, el modelo Stepwise estima ",
    formatear(pronostico_step$fit[1])," millones COP y un intervalo de predicción del 95 % entre ",
    formatear(pronostico_step$lwr[1])," y ",formatear(pronostico_step$upr[1])," millones. ",
    "Para el segundo perfil estima ",formatear(pronostico_step$fit[2])," millones. ",
    "Este es un rango para un nuevo anuncio individual bajo los supuestos del modelo, no una garantía de venta. ",
    "La alternativa log(área) estima ",formatear(pronostico_logx$fit[1]),
    " millones para el primer caso; las diferencias muestran sensibilidad a la especificación.\n\n",sep="")

Interpretación: para el primer perfil, el modelo Stepwise estima 248,67 millones COP y un intervalo de predicción del 95 % entre 165,25 y 332,08 millones. Para el segundo perfil estima 169,40 millones. Este es un rango para un nuevo anuncio individual bajo los supuestos del modelo, no una garantía de venta. La alternativa log(área) estima 240,94 millones para el primer caso; las diferencias muestran sensibilidad a la especificación.

12 Conclusiones críticas y recomendación

Respuesta a la pregunta del trabajo. La base filtrada permite identificar relaciones entre características físicas y precios de oferta, pero la utilidad práctica depende de la magnitud de los errores fuera de muestra. El modelo de menor MAE es Múltiple: precio ~ log(área) con 22,74 millones de COP de error absoluto promedio, frente a 51,20 millones de la referencia por mediana.

Lectura empresarial. En Valle del Lili la forma funcional importa tanto como el número de predictores: un área extrema puede hacer fallar una regresión lineal ordinaria y volver más útil una transformación del área.

Limitaciones que afectan la decisión. La base representa precios publicados y no transacciones cerradas. La ausencia del piso en algunos anuncios y un área extrema exigen prudencia al generalizar los resultados. Se desconoce si los anuncios representan propiedades independientes y no hay observación directa de estado de conservación, acabados, negociaciones efectivas ni fecha de publicación. Un valor de p pequeño no demuestra que modificar una característica cause un incremento de precio.

Recomendación. Usar los modelos únicamente como punto de partida para estimar rangos de precio anunciado y cotejar con visitas, comparables recientes y juicio profesional. No recomendar un precio final de cierre, una inversión o una decisión de crédito basándose en esta regresión por sí sola.

13 Referencia del procedimiento

Base Datos_Vivienda.xlsx proporcionada en clase. La estructura sigue los dos ejemplos docentes adjuntos: filtro por barrio/tipo, estadística descriptiva y gráficos, modelos lm(), interpretación de coeficientes, diagnóstico plot(lm), transformaciones logarítmicas, dummy, step(), predict() y MAE con evaluación externa al entrenamiento.