1 Introducción y problema

Pregunta de investigación: ¿El precio anunciado de las casas en Pance está más relacionado con el espacio disponible, la dotación de baños o la capacidad de parqueo?

El mercado de casas de Pance combina extensiones construidas importantes y diferentes configuraciones de comodidad. Un mayor espacio no necesariamente se traduce en el mismo aumento monetario para todas las propiedades: los baños y la posibilidad de estacionar varios vehículos pueden ofrecer información adicional.

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 una inmobiliaria que necesita construir rangos de referencia para asesorar a propietarios de casas de alta gama. 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 Pance y tipo casas; 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.

La variable parqueaderos puede faltar; se exige que esté registrada para asegurar una muestra común a todos los modelos. No se exige piso porque muchas casas no tienen ese dato y no forma parte de las hipótesis.

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))=="pance" &
                             tolower(trimws(base_original$Tipo))=="casa",,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(parqueaderos) & parqueaderos>=0)
validos <- candidatos[filas_validas,,drop=FALSE]
repetidos <- duplicated(validos[,columnas_base,drop=FALSE])
datos <- validos[!repetidos,,drop=FALSE]
datos$garaje_amplio <- as.integer(datos$parqueaderos>=4)
datos$fold <- as.integer((datos$id_original*73+17) %% 5)+1L
stopifnot(nrow(datos)>30L)
knitr::kable(data.frame(
  Etapa=c("Base completa","Casas en Pance","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
Casas en Pance 206
Registros válidos 200
Anuncios finales sin duplicados 200

La muestra analítica final contiene 200 anuncios, frente a 206 registros originalmente filtrados por barrio y tipo. La pérdida de 6 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
parqueaderos parqueaderos 6
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 200 460 840 1118.14 1100.0 1350 1900 372.92
Area_contruida 200 128 274 403.64 348.5 461 1500 223.54
Banos 200 2 4 5.14 5.0 6 7 1.00
Habitaciones 200 3 4 4.20 4.0 5 7 0.82
parqueaderos 200 1 2 3.75 4.0 4 10 1.66

Interpretación de tendencia central: el precio medio anunciado es de 1.118,14 millones, frente a una mediana de 1.100,00 millones. La distancia entre ambas resume la posible asimetría del mercado. El 50 % central de los precios se sitúa aproximadamente entre 840,00 y 1.350,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. El mercado de casas de Pance combina extensiones construidas importantes y diferentes configuraciones de comodidad. Un mayor espacio no necesariamente se traduce en el mismo aumento monetario para todas las propiedades: los baños y la posibilidad de estacionar varios vehículos pueden ofrecer información adicional.

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 75.0 2115.0 0
Área -6.5 741.5 13

Interpretación del boxplot y atípicos: se marcaron 0 precios y 13 á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 1.500,00 m².

Advertencia específica de Pance: las casas tienen tamaños y dotaciones heterogéneos, de modo que el modelo puede subestimar una casa especialmente equipada o sobreestimar otra más sencilla. Los metros cuadrados no reflejan por sí solos la calidad de construcción ni el tamaño de lote.

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","Banos","parqueaderos")
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.526
Banos Banos 0.415
parqueaderos parqueaderos 0.467
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 ~ Banos, data=datos)
s3 <- lm(precio_millon ~ parqueaderos, 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","parqueaderos"="parqueaderos","garaje_amplio"="parqueaderos amplios (1=4 o más)")
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 -761.30 -242.77 -54.77 183.08 842.07

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 764.0511 46.5031 16.430 < 2e-16 Area_contruida 0.8772 0.1008 8.699 1.29e-15 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 318 on 198 degrees of freedom Multiple R-squared: 0.2765, Adjusted R-squared: 0.2729 F-statistic: 75.67 on 1 and 198 DF, p-value: 1.29e-15

Interpretación completa de Modelo simple 1.

  • Intercepto: 764,05 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,88 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² = 27,65 % y R² ajustado = 27,29 %. 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 ~ Banos, data = datos)

Residuals: Min 1Q Median 3Q Max -678.00 -248.52 -41.75 225.54 958.25

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 320.08 126.64 2.528 0.0123 *
Banos 155.42 24.21 6.419 9.94e-10 *** — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 340.1 on 198 degrees of freedom Multiple R-squared: 0.1722, Adjusted R-squared: 0.1681 F-statistic: 41.2 on 1 and 198 DF, p-value: 9.938e-10

Interpretación completa de Modelo simple 2.

  • Intercepto: 320,08 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.

  • baños: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 155,42 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² = 17,22 % y R² ajustado = 16,81 %. 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 ~ parqueaderos, data = datos)

Residuals: Min 1Q Median 3Q Max -603.58 -264.49 -48.94 213.99 964.97

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 725.75 57.73 12.571 < 2e-16 parqueaderos 104.64 14.08 7.434 3.11e-12 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 330.6 on 198 degrees of freedom Multiple R-squared: 0.2182, Adjusted R-squared: 0.2142 F-statistic: 55.26 on 1 and 198 DF, p-value: 3.112e-12

Interpretación completa de Modelo simple 3.

  • Intercepto: 725,75 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.

  • parqueaderos: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 104,64 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² = 21,82 % y R² ajustado = 21,42 %. 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,0066: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 8. 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,5380: no se detecta heterocedasticidad con esta prueba, aunque conviene revisar el gráfico de residuos. Observaciones con Cook > 4/n: 8. 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,6977: no se detecta heterocedasticidad con esta prueba, aunque conviene revisar el gráfico de residuos. Observaciones con Cook > 4/n: 13. 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 -759.51 -194.79 -39.25 131.37 815.32

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) -1864.99 246.87 -7.555 1.52e-12 log(Area_contruida) 507.33 41.84 12.124 < 2e-16 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 283.2 on 198 degrees of freedom Multiple R-squared: 0.4261, Adjusted R-squared: 0.4232 F-statistic: 147 on 1 and 198 DF, p-value: < 2.2e-16

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

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

  • Intercepto: -1.864,99 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 5,05 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² = 42,61 % y R² ajustado = 42,32 %. 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 -0.70059 -0.18289 -0.00836 0.16589 0.62160

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.99071 0.21836 18.28 <2e-16 log(Area_contruida) 0.50520 0.03701 13.65 <2e-16 — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.2505 on 198 degrees of freedom Multiple R-squared: 0.4848, Adjusted R-squared: 0.4822 F-statistic: 186.3 on 1 and 198 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 0,51. 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: 8. 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,0577: no se detecta evidencia suficiente contra la normalidad; eso no demuestra normalidad perfecta. Breusch-Pagan auxiliar p = 0,0084: hay señales de varianza no constante, lo que limita la confianza en errores estándar clásicos. Observaciones con Cook > 4/n: 10. 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 + Banos + Habitaciones. Evalúa qué características conservan asociación con el precio cuando se mantienen las otras constantes.

Modelo múltiple 2: precio ~ Area_contruida + Banos + Habitaciones + garaje_amplio. Incorpora explícitamente una variable dummy: garaje_amplio. Se asigna 1 si la casa anuncia cuatro o más parqueaderos y 0 si anuncia entre uno y tres.

La dummy compara casas con capacidad amplia de estacionamiento frente a las de menor capacidad, manteniendo constantes las demás características. Es una diferencia asociada, no el efecto causal de construir un garaje.

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

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

Residuals: Min 1Q Median 3Q Max -662.45 -228.22 -69.49 188.08 873.05

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 336.1241 129.2067 2.601 0.00999 ** Area_contruida 0.7294 0.1013 7.200 1.26e-11 Banos 114.3151 26.1942 4.364 2.06e-05 Habitaciones -23.6703 30.4447 -0.777 0.43781
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 303.3 on 196 degrees of freedom Multiple R-squared: 0.3484, Adjusted R-squared: 0.3384 F-statistic: 34.93 on 3 and 196 DF, p-value: < 2.2e-16

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

Interpretación completa de Modelo múltiple 1.

  • Intercepto: 336,12 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,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.

  • baños: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 114,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.

  • habitaciones: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 23,67 millones de pesos menos en el precio anunciado; no existe evidencia estadística suficiente al 5 %. No conviene afirmar que existe un efecto real con este resultado.

  • Ajuste: R² = 34,84 % y R² ajustado = 33,84 %. 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 + Banos + Habitaciones + garaje_amplio, data = datos)

Residuals: Min 1Q Median 3Q Max -673.83 -220.96 -75.61 145.88 827.99

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 337.6440 125.3424 2.694 0.007681 ** Area_contruida 0.6298 0.1020 6.174 3.79e-09 Banos 105.2034 25.5334 4.120 5.59e-05 Habitaciones -25.6007 29.5388 -0.867 0.387181
garaje_amplio 162.7460 44.6695 3.643 0.000345 *** — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 294.2 on 195 degrees of freedom Multiple R-squared: 0.3899, Adjusted R-squared: 0.3774 F-statistic: 31.16 on 4 and 195 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: 337,64 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,63 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 105,20 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,60 millones de pesos menos en el precio anunciado; no existe evidencia estadística suficiente al 5 %. No conviene afirmar que existe un efecto real con este resultado.

  • parqueaderos amplios (1=4 o más): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 162,75 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² = 38,99 % y R² ajustado = 37,74 %. 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.348 0.338 2859.453
Múltiple 2 0.390 0.377 2848.282

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,3248: no se detecta heterocedasticidad con esta prueba, aunque conviene revisar el gráfico de residuos. Observaciones con Cook > 4/n: 12. 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,1651: no se detecta heterocedasticidad con esta prueba, aunque conviene revisar el gráfico de residuos. Observaciones con Cook > 4/n: 12. 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.11
Banos 1.47
Habitaciones 1.35
cat("\n\n**VIF: Múltiple 2**.\n\n")

VIF: Múltiple 2.

print(knitr::kable(calcular_vif(m2)))
Variable VIF
Area_contruida 1.20
Banos 1.49
Habitaciones 1.35
garaje_amplio 1.13

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) + Banos + Habitaciones + garaje_amplio,data=datos)
m_logy <- lm(log(precio_millon) ~ log(Area_contruida) + Banos + Habitaciones + garaje_amplio,data=datos)
print(summary(m_logx))

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

Residuals: Min 1Q Median 3Q Max -700.38 -178.01 -56.85 131.53 768.43

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) -1612.41 257.12 -6.271 2.26e-09 log(Area_contruida) 410.39 47.26 8.683 1.54e-15 Banos 80.14 24.13 3.322 0.00107 ** Habitaciones -36.57 27.40 -1.335 0.18357
garaje_amplio 103.53 42.80 2.419 0.01648 *
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 273.2 on 195 degrees of freedom Multiple R-squared: 0.474, Adjusted R-squared: 0.4633 F-statistic: 43.94 on 4 and 195 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: -1.612,41 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 4,08 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).

  • baños: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 80,14 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 36,57 millones de pesos menos en el precio anunciado; no existe evidencia estadística suficiente al 5 %. No conviene afirmar que existe un efecto real con este resultado.

  • parqueaderos amplios (1=4 o más): manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 103,53 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² = 47,40 % y R² ajustado = 46,33 %. 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) + Banos + Habitaciones + garaje_amplio, data = datos)

Residuals: Min 1Q Median 3Q Max -0.64526 -0.17429 -0.02702 0.14317 0.59628

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.25829 0.22469 18.952 < 2e-16 log(Area_contruida) 0.40694 0.04130 9.853 < 2e-16 Banos 0.07357 0.02108 3.490 0.000598 * Habitaciones -0.03194 0.02395 -1.334 0.183858
garaje_amplio 0.11577 0.03740 3.095 0.002255
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.2387 on 195 degrees of freedom Multiple R-squared: 0.5392, Adjusted R-squared: 0.5297 F-statistic: 57.04 on 4 and 195 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.0000 0.1651
Múltiple con log(área) 0.0000 0.0015
Múltiple con log(precio) y log(área) 0.0018 0.1426
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,0015: 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.

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,0018: se rechaza la normalidad estricta de los residuos; revisar especialmente colas y Q-Q plot. Breusch-Pagan auxiliar p = 0,1426: no se detecta heterocedasticidad con esta prueba, aunque conviene revisar el gráfico de residuos. Observaciones con Cook > 4/n: 12. 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 + Banos + Habitaciones + parqueaderos + garaje_amplio
modelo_completo <- lm(formula_completa,data=datos)
paso <- step(modelo_completo,
             scope=list(lower=~1,upper=formula_completa),
             direction="both",trace=TRUE)

Start: AIC=2271.45 precio_millon ~ Area_contruida + Banos + Habitaciones + parqueaderos + garaje_amplio

             Df Sum of Sq      RSS    AIC
  • garaje_amplio 1 3150 16122786 2269.5
  • Habitaciones 1 67797 16187433 2270.3 16119636 2271.4
  • parqueaderos 1 763925 16883561 2278.7
  • Banos 1 1144424 17264060 2283.2
  • Area_contruida 1 2967990 19087626 2303.2

Step: AIC=2269.49 precio_millon ~ Area_contruida + Banos + Habitaciones + parqueaderos

             Df Sum of Sq      RSS    AIC
  • Habitaciones 1 67587 16190373 2268.3 16122786 2269.5
  • garaje_amplio 1 3150 16119636 2271.4
  • Banos 1 1141314 17264100 2281.2
  • parqueaderos 1 1910060 18032846 2289.9
  • Area_contruida 1 3020595 19143380 2301.8

Step: AIC=2268.32 precio_millon ~ Area_contruida + Banos + parqueaderos

             Df Sum of Sq      RSS    AIC

16190373 2268.3 + Habitaciones 1 67587 16122786 2269.5 + garaje_amplio 1 2940 16187433 2270.3 - Banos 1 1162682 17353055 2280.2 - parqueaderos 1 1898088 18088461 2288.5 - Area_contruida 1 3066576 19256949 2301.0

print(formula(paso))

precio_millon ~ Area_contruida + Banos + parqueaderos

print(summary(paso))

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

Residuals: Min 1Q Median 3Q Max -731.40 -203.29 -80.46 172.17 818.72

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 211.46794 108.25436 1.953 0.052191 .
Area_contruida 0.60614 0.09948 6.093 5.77e-09 Banos 82.53273 21.99866 3.752 0.000231 parqueaderos 63.52254 13.25165 4.794 3.23e-06 *** — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 287.4 on 196 degrees of freedom Multiple R-squared: 0.415, Adjusted R-squared: 0.406 F-statistic: 46.34 on 3 and 196 DF, p-value: < 2.2e-16

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

Interpretación completa de Modelo seleccionado por Stepwise.

  • Intercepto: 211,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.

  • á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,61 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 82,53 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.

  • parqueaderos: manteniendo constantes los otros predictores, una unidad adicional (o el paso de 0 a 1 si es dummy) se asocia con 63,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² = 41,50 % y R² ajustado = 40,60 %. 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, Banos, parqueaderos. Su AIC final es 2.837,90 frente a 2.841,02 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,2751: no se detecta heterocedasticidad con esta prueba, aunque conviene revisar el gráfico de residuos. Observaciones con Cook > 4/n: 12. 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) 222.22 280.06
7 Simple: precio ~ log(área) 225.46 289.11
10 Múltiple: log(precio) ~ log(área) 232.77 297.23
6 Stepwise AIC (ajustado en cada pliegue) 234.70 291.85
8 Simple: log(precio) ~ log(área) 239.94 315.26
5 Múltiple 2 242.21 299.43
4 Múltiple 1 251.57 309.59
1 Simple 1 262.34 324.41
2 Simple 2 274.81 342.96
3 Simple 3 279.78 333.29
11 Referencia: mediana del entrenamiento 325.18 386.99
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 222,22 millones COP de diferencia absoluta promedio entre precio anunciado y estimado. La referencia sin predictores tiene MAE 325,18 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 Pance, 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(350,250),Banos=c(5,4),Habitaciones=c(4,3),parqueaderos=c(4,2),garaje_amplio=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 parqueaderos garaje_amplio
350 5 4 4 1
250 4 3 2 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 1090.37 521.96 1658.78 1149.55 608.03 1691.07
Escenario 2 820.18 249.27 1391.09 864.37 319.84 1408.89
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 1.090,37 millones COP y un intervalo de predicción del 95 % entre 521,96 y 1.658,78 millones. Para el segundo perfil estima 820,18 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 1.149,55 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 222,22 millones de COP de error absoluto promedio, frente a 325,18 millones de la referencia por mediana.

Lectura empresarial. En Pance importa más que una fórmula identifique el rango de negociación que acertar un precio exacto: aun con modelos estadísticamente significativos, la dispersión puede ser costosa para una decisión comercial.

Limitaciones que afectan la decisión. El precio anunciado no equivale al precio final de una negociación. Además, las casas de lujo pueden tener acabados y lotes muy distintos, aspectos que no se observan en la base. 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.