Primeros 3 registros
apartamentos=subset(vivienda, tipo=="Apartamento")
kable(head(apartamentos, 3))
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1212 | Zona Norte | 01 | 5 | 260 | 90 | 1 | 2 | 3 | Apartamento | acopi | -76.51350 | 3.45891 |
| 1724 | Zona Norte | 01 | 5 | 240 | 87 | 1 | 3 | 3 | Apartamento | acopi | -76.51700 | 3.36971 |
| 2326 | Zona Norte | 01 | 4 | 220 | 52 | 2 | 2 | 3 | Apartamento | acopi | -76.51974 | 3.42627 |
Conteo por tipo de vivienda
#Tabla de Conteo de Apartamentos
table(apartamentos$tipo)
##
## Apartamento
## 5100
Valores únicos de tipo de vivienda
unique(apartamentos$tipo)
## [1] "Apartamento"
#Eliminamos los datos con NA
apartamentos <- na.omit(apartamentos)
# Selección de columnas relevantes para el análisis
datos <- apartamentos %>% select(preciom, areaconst, estrato, parqueaderos, banios, habitaciones, zona)
summary(datos)
## preciom areaconst estrato parqueaderos banios
## Min. : 58 Min. : 40.0 Min. :3.000 Min. :1.000 Min. :0.000
## 1st Qu.: 220 1st Qu.: 75.0 1st Qu.:4.000 1st Qu.:1.000 1st Qu.:2.000
## Median : 300 Median : 96.0 Median :5.000 Median :1.000 Median :2.000
## Mean : 390 Mean :117.1 Mean :4.887 Mean :1.548 Mean :2.752
## 3rd Qu.: 450 3rd Qu.:135.0 3rd Qu.:6.000 3rd Qu.:2.000 3rd Qu.:3.000
## Max. :1900 Max. :932.0 Max. :6.000 Max. :7.000 Max. :7.000
## habitaciones zona
## Min. :0.000 Length:3182
## 1st Qu.:3.000 Class :character
## Median :3.000 Mode :character
## Mean :3.023
## 3rd Qu.:3.000
## Max. :7.000
# Gráfico de dispersión Precio vs Area
plot_area_precio <- plot_ly(datos, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(size = 10, color = 'rgba(152, 0, 0, .8)', line = list(color = 'rgba(152, 0, 0, 1.0)', width = 2)))
# Agregar el título y etiquetas
plot_area_precio <- plot_area_precio %>%
layout(
title = list(text = "Relación entre Precio y Área Construida"),
xaxis = list(title = "Área Construida (m2)"),
yaxis = list(title = "Precio (Millones de Pesos)")
)
# Precio vs Estrato
plot_precio_estrato <- plot_ly(datos, x = ~factor(estrato), y = ~preciom, type = 'box', boxpoints = 'all') %>%
layout(title = 'Distribución del Precio por Estrato',
xaxis = list(title = 'Estrato'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Precio vs Número de Baños
plot_precio_banios <- plot_ly(datos, x = ~factor(banios), y = ~preciom, type = 'box', boxpoints = 'all') %>%
layout(title = 'Distribución del Precio por Número de Baños',
xaxis = list(title = 'Número de Baños'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Precio vs Número de Habitaciones
plot_precio_habitaciones <- plot_ly(datos, x = ~factor(habitaciones), y = ~preciom, type = 'box', boxpoints = 'all') %>%
layout(title = 'Distribución del Precio por Número de Habitaciones',
xaxis = list(title = 'Número de Habitaciones'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Precio vs Zona
plot_precio_zona <- plot_ly(datos, x = ~zona, y = ~preciom, type = 'box', boxpoints = 'all') %>%
layout(title = 'Distribución del Precio por Zona',
xaxis = list(title = 'Zona'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Precio vs Parqueaderos
plot_precio_parqueaderos <- plot_ly(datos, x = ~parqueaderos, y = ~preciom, type = 'box', boxpoints = 'all') %>%
layout(title = 'Distribución del Precio Número de Parqueaderos',
xaxis = list(title = 'Parqueaderos'),
yaxis = list(title = 'Precio (Millones de Pesos)'))
# Mostrar gráficos
plot_area_precio
plot_precio_estrato
plot_precio_banios
plot_precio_habitaciones
plot_precio_zona
plot_precio_parqueaderos
# Crear la matriz de pares
ggpairs(datos,
title = "Matriz de Pares: Correlación entre Precio de la Vivienda y Variables Seleccionadas",
aes(color = zona, alpha = 0.5))
## Warning in cor(x, y): the standard deviation is zero
## Warning in cor(x, y): the standard deviation is zero
## Warning in cor(x, y): the standard deviation is zero
## Warning in cor(x, y): the standard deviation is zero
## Warning in cor(x, y): the standard deviation is zero
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Análisis
Preciom vs areaconst: Existe una fuerte correlación positiva (0.829), lo que indica que a medida que aumenta el área construida, el precio de la vivienda también tiende a aumentar. Esto es coherente con la expectativa de que las viviendas más grandes suelen ser más costosas.
Preciom vs estrato: Hay una correlación positiva moderada (0.667), sugiriendo que las viviendas en estratos más altos tienden a tener precios más altos.
Preciom vs baños: La correlación es alta (0.740), lo que indica que el número de baños está relacionado positivamente con el precio de la vivienda. Esto podría reflejar que viviendas con más baños suelen ser más costosas.
Preciom vs habitaciones: La correlación es moderada (0.297), indicando que el número de habitaciones tiene una relación más débil con el precio en comparación con otras variables como el área construida o el número de baños.
Preciom vs zona: La relación varía según la zona, pero en general, se observa que ciertas zonas tienen precios más altos que otras, siendo los apartamentos de la zona Oeste de mayor valor, lo cual es esperado dado que la ubicación es un factor determinante en el valor de las viviendas.
Preciom vs parqueaderos: el resultado de la correlación es alta, según lo esperado, porque que la vivienda que tenga parqueadero es un factor diferencial en el precio.
Modelo de Regresión Lineal Multiple
# Estimación del modelo de regresión lineal múltiple
modelo <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = apartamentos)
# Resumen del modelo
summary(modelo)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = apartamentos)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1609.23 -55.44 -0.01 47.99 963.98
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -285.9869 17.5604 -16.29 <2e-16 ***
## areaconst 1.9061 0.0549 34.72 <2e-16 ***
## estrato 52.5560 3.4642 15.17 <2e-16 ***
## habitaciones -35.3350 4.2623 -8.29 <2e-16 ***
## parqueaderos 100.3163 4.9734 20.17 <2e-16 ***
## banios 53.5608 3.8771 13.81 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 133.5 on 3176 degrees of freedom
## Multiple R-squared: 0.7823, Adjusted R-squared: 0.7819
## F-statistic: 2282 on 5 and 3176 DF, p-value: < 2.2e-16
Al interpretar el modelo utilizando todas las variables, observamos que el intercepto es negativo (-278). En la práctica, un intercepto negativo puede carecer de una interpretación directa, especialmente cuando algunas variables no pueden ser cero en la realidad. En este caso, la baja correlación entre el precio y el número de habitaciones sugiere que esta variable podría no ser relevante para el modelo y se recomienda considerarla para su exclusión.
Interpretación de los Coeficientes
Intercepto (-286): El intercepto de -286 millones de pesos representa el valor estimado del precio cuando todas las demás variables (área construida, estrato, número de parqueaderos y número de baños) son cero. En la práctica, este valor puede no tener una interpretación directa, ya que es poco realista que un inmueble tenga cero metros cuadrados de área construida o pertenezca a un estrato cero. Este valor negativo podría indicar que hay otros factores no modelados que afectan el precio cuando las variables predictoras son bajas,
Área Construida (1,9): Cada metro cuadrado adicional de área construida está asociado con un incremento de 1.9 millones de pesos en el precio del inmueble, manteniendo constantes las demás variables. Este coeficiente es estadísticamente significativo (p < 2e-16), lo que indica que el área construida tiene un impacto considerable en el precio de las viviendas, lo cual es lógico, ya que más espacio suele traducirse en un mayor valor.
Estrato (52.55): Un aumento de una unidad en el estrato socioeconómico está asociado con un incremento de 52.55 millones de pesos en el precio del inmueble, manteniendo constantes las demás variables. Este coeficiente es también estadísticamente significativo (p < 2e-16), sugiriendo que vivir en un estrato más alto, que generalmente implica mejores servicios y una mejor ubicación, aumenta significativamente el valor del inmueble.
Número de Parqueaderos (100.31): Cada parqueadero adicional está asociado con un aumento de 100.31 millones de pesos en el precio del inmueble, manteniendo constantes las demás variables. Este coeficiente, estadísticamente significativo (p < 2e-16), indica que la disponibilidad de parqueaderos es un factor importante en la determinación del precio de una vivienda, lo cual es coherente con la creciente demanda por estacionamientos, especialmente en zonas urbanas.
Número de Baños (53.56): Cada baño adicional está asociado con un aumento de 53.56 millones de pesos en el precio del inmueble, manteniendo constantes las demás variables. Este coeficiente es significativo (p < 2e-16), lo que sugiere que el número de baños también contribuye de manera positiva al precio, reflejando la importancia de la comodidad y la funcionalidad en la valoración de un inmueble.
Número de Habitaciones (-35.33):Un aumento de una habitación está asociado con una disminución de 35.33 millones de pesos en el precio, manteniendo constantes las demás variables. Aunque este coeficiente es significativo (p < 2e-16), un efecto negativo sobre el precio de las habitaciones es inusual y está asociado a que la correlación del precio de aparamento es muy baja con respecto al número de habitaciones.
Interpretación del R²
𝑅² = El valor de 0.7823 indica que aproximadamente el 78.23% de la variabilidad en el precio de la vivienda es explicada por el modelo que incluye el área construida, estrato, número de habitaciones, parqueaderos y baños.
R² Ajustado = 0.77819: El número de predictores en el modelo, es ligeramente menor pero muy similar al R², lo que indica que las variables seleccionadas no están añadiendo ruido innecesario al modelo.
Dado los resultados del modelo de regresión, algunas sugerencias para ajustar y mejorar el modelo podrían ser:
Revisar la Significancia y Coherencia de las Variables: Habitaciones (-35.33), el coeficiente negativo y significativo para el número de habitaciones es inesperado, ya que normalmente se esperaría que más habitaciones aumenten el valor de la vivienda. Este resultado podría indicar que hay colinealidad entre las variables (por ejemplo, entre el número de habitaciones y el área construida). Se Podría Verificar Colinealidad y reformular la variable, interactuar el número de habitaciones con otra variable como el área construida.
Evaluar la Inclusión del Intercepto: El intercepto negativo sugiere que cuando todas las variables predictoras son cero, el precio predicho es negativo, lo que no tiene sentido práctico. Entonces se dendría que forzar el Intercepto a cero.
Interacciones entre Variables: Las interacciones entre variables como el área construida y el número de habitaciones o entre estrato y el número de parqueaderos podrían capturar mejor la variabilidad en los precios.
Variables Cualitativas: Variables como la zona podrían ser útiles para capturar efectos espaciales que el estrato solo no puede captar.
Evaluar la Transformación de Variables a Transformación Logarítmica: la variable areaconst también muestra una distribución sesgada hacia la derecha, lo que sugiere que una transformación logarítmica podría ser útil.
Análisis de Residuos: Realizar un análisis más detallado de los residuos (normalidad, heterocedasticidad) para aseguranos de que el modelo cumpla con los supuestos de regresión.
Validación cruzada (Cross-Validation): Para asegurarnos de que el modelo generaliza bien y no está sobreajustado a los datos de entrenamiento.
A continuación, se muestran las pruebas de cada supuesto:
- Linealidad: La relación entre las variables independientes y la variable dependiente debe ser lineal.
# 1. Verificación de Linealidad
plot(fitted(modelo), residuals(modelo), main = "Residuals vs Fitted")
abline(h = 0, col = "red")
Aunque hay un cierto grado de alineación alrededor de la línea cero, el patrón observado en la gráfica sugiere que el supuesto de linealidad puede no estar completamente satisfecho para todos los valores ajustados. La curva sugiere que puede haber una relación no lineal que no está siendo capturada por el modelo actual.
- Independencia de los errores: Los residuos deben ser independientes entre sí. Se practica la prueba de Durbin-Watson.
# 2. Prueba de Durbin-Watson para independencia
dwtest(modelo)
##
## Durbin-Watson test
##
## data: modelo
## DW = 1.5868, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
Indica que los residuos están correlacionados positivamente, lo que significa que un error positivo en un período tiende a ser seguido por otro error positivo, y lo mismo ocurre con los errores negativos. Esto puede ser problemático porque viola el supuesto de independencia de los errores, lo cual puede afectar la validez de los resultados del modelo.
- Homoscedasticidad: La varianza de los residuos debe ser constante a lo largo de todos los valores de las variables independientes.
# 3. Verificación de Homoscedasticidad
plot(fitted(modelo), sqrt(abs(residuals(modelo))), main = "Scale-Location")
abline(h = 0, col = "red")
Se observa un patrón en forma de abanico donde la dispersión de los residuos parece aumentar a medida que aumentan los valores ajustados (fitted values). Este patrón es un indicio de heterocedasticidad, es decir, la varianza de los errores no es constante a lo largo de los valores predichos por el modelo
- Normalidad de los residuos: Los residuos del modelo deben seguir una distribución normal.
# 4. Verificación de Normalidad de los Residuos
qqnorm(residuals(modelo))
qqline(residuals(modelo), col = "red")
La presencia de puntos alejados de la línea recta en las colas sugiere que los residuos presentan distribución no normal, con posibles valores atípicos o outliers que podrían estar afectando el modelo.
- Ausencia de multicolinealidad: No debe haber una alta correlación entre las variables independientes.
vif(modelo)
## areaconst estrato habitaciones parqueaderos banios
## 2.518858 1.680141 1.421734 2.207342 2.927053
Los resultados de los VIF sugieren que no hay problemas serios de multicolinealidad en las variables independientes del modelo. Esto significa que las estimaciones de los coeficientes de regresión son confiables y no están distorsionadas por la correlación entre las variables predictoras.
Sugerencias para Ajuste del Modelo:
# Semilla para reproducibilidad
set.seed(123)
# Indice aleatorio para el 70% de los datos
train_index <- sample(seq_len(nrow(apartamentos)), size = 0.7 * nrow(apartamentos))
# Conjuntos de entrenamiento y prueba
train_data <- datos[train_index, ]
test_data <- datos[-train_index, ]
# Contar elementos en cada conjunto
num_train <- nrow(train_data)
num_test <- nrow(test_data)
# Mostrar resultados
cat("Número de elementos en el conjunto de entrenamiento:", num_train, "\n")
## Número de elementos en el conjunto de entrenamiento: 2227
cat("Número de elementos en el conjunto de prueba:", num_test, "\n")
## Número de elementos en el conjunto de prueba: 955
# Estimar el modelo de regresión lineal
modeloTrain <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = train_data)
# Mostrar el resumen del modelo
summary(modeloTrain)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1206.30 -52.70 0.72 47.73 949.70
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -275.85441 20.87286 -13.216 < 2e-16 ***
## areaconst 2.11600 0.06812 31.062 < 2e-16 ***
## estrato 49.66599 4.08581 12.156 < 2e-16 ***
## habitaciones -35.53463 5.10337 -6.963 4.37e-12 ***
## parqueaderos 93.05787 5.98705 15.543 < 2e-16 ***
## banios 50.82708 4.64058 10.953 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 132.5 on 2221 degrees of freedom
## Multiple R-squared: 0.791, Adjusted R-squared: 0.7905
## F-statistic: 1681 on 5 and 2221 DF, p-value: < 2.2e-16
# Predicciones con los datos de prueba
predicciones <- predict(modeloTrain, newdata = test_data)
# Extraer los valores reales del conjunto de prueba
valores_reales <- test_data$preciom
# Data frame para comparar
comparacion <- data.frame(
PrecioReal = valores_reales,
PrecioPrediccion = predicciones
)
# Ver las primeras comparaciones
head(comparacion)
## PrecioReal PrecioPrediccion
## 1 220 214.00766
## 2 320 383.33087
## 3 420 559.91076
## 4 170 163.78733
## 5 78 30.59933
## 6 1130 899.51209
# Error absoluto medio (MAE)
mae <- mean(abs(valores_reales - predicciones))
# Error cuadrático medio (RMSE)
rmse <- sqrt(mean((valores_reales - predicciones)^2))
# Coeficiente de Determinación (R²)
ss_total <- sum((valores_reales - mean(valores_reales))^2)
ss_residual <- sum((valores_reales - predicciones)^2)
r2 <- 1 - (ss_residual / ss_total)
# Mostrar métricas
cat("Error Absoluto Medio:", mae, "\n")
## Error Absoluto Medio: 81.80488
cat("Error Cuadrático Medio):", rmse, "\n")
## Error Cuadrático Medio): 136.8376
cat("R²:", r2, "\n")
## R²: 0.7561123