#install.packages("devtools") # solo la primera vez
#devtools::install_github("centromagis/paqueteMODELOS", force =TRUE)
library(paqueteMODELOS)
## Loading required package: boot
## Loading required package: broom
## Loading required package: GGally
## Loading required package: ggplot2
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
## Loading required package: gridExtra
## Loading required package: knitr
## Loading required package: summarytools
data("vivienda")
summary(vivienda)
## id zona piso estrato
## Min. : 1 Length:8322 Length:8322 Min. :3.000
## 1st Qu.:2080 Class :character Class :character 1st Qu.:4.000
## Median :4160 Mode :character Mode :character Median :5.000
## Mean :4160 Mean :4.634
## 3rd Qu.:6240 3rd Qu.:5.000
## Max. :8319 Max. :6.000
## NA's :3 NA's :3
## preciom areaconst parqueaderos banios
## Min. : 58.0 Min. : 30.0 Min. : 1.000 Min. : 0.000
## 1st Qu.: 220.0 1st Qu.: 80.0 1st Qu.: 1.000 1st Qu.: 2.000
## Median : 330.0 Median : 123.0 Median : 2.000 Median : 3.000
## Mean : 433.9 Mean : 174.9 Mean : 1.835 Mean : 3.111
## 3rd Qu.: 540.0 3rd Qu.: 229.0 3rd Qu.: 2.000 3rd Qu.: 4.000
## Max. :1999.0 Max. :1745.0 Max. :10.000 Max. :10.000
## NA's :2 NA's :3 NA's :1605 NA's :3
## habitaciones tipo barrio longitud
## Min. : 0.000 Length:8322 Length:8322 Min. :-76.59
## 1st Qu.: 3.000 Class :character Class :character 1st Qu.:-76.54
## Median : 3.000 Mode :character Mode :character Median :-76.53
## Mean : 3.605 Mean :-76.53
## 3rd Qu.: 4.000 3rd Qu.:-76.52
## Max. :10.000 Max. :-76.46
## NA's :3 NA's :3
## latitud
## Min. :3.333
## 1st Qu.:3.381
## Median :3.416
## Mean :3.418
## 3rd Qu.:3.452
## Max. :3.498
## NA's :3
valores_faltantes <- colSums(is.na(vivienda))
print(valores_faltantes)
## id zona piso estrato preciom areaconst
## 3 3 2638 3 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 1605 3 3 3 3 3
## latitud
## 3
# Eliminando las filas con NA en la columna id
viviendasinna <- vivienda[!is.na(vivienda$id), ]
valores_faltantessinna <- colSums(is.na(viviendasinna))
print(valores_faltantessinna)
## id zona piso estrato preciom areaconst
## 0 0 2635 0 0 0
## parqueaderos banios habitaciones tipo barrio longitud
## 1602 0 0 0 0 0
## latitud
## 0
sapply(viviendasinna, class)
## id zona piso estrato preciom areaconst
## "numeric" "character" "character" "numeric" "numeric" "numeric"
## parqueaderos banios habitaciones tipo barrio longitud
## "numeric" "numeric" "numeric" "character" "character" "numeric"
## latitud
## "numeric"
#Convertir piso a variable numerica
viviendasinna$piso <- as.numeric(viviendasinna$piso)
# Función para calcular el modo
getmode <- function(v) {
uniqv <- unique(v)
uniqv[which.max(tabulate(match(v, uniqv)))]
}
# Reemplazar NA con el modo en 'parqueaderos'
mode_parqueaderos <- getmode(viviendasinna$parqueaderos)
viviendasinna$parqueaderos[is.na(viviendasinna$parqueaderos)] <- mode_parqueaderos
# Calcular el modo de 'piso'
mode_piso <- getmode(viviendasinna$piso[!is.na(viviendasinna$piso)])
mode_piso
## [1] 2
viviendasinna$piso[is.na(viviendasinna$piso)] <- mode_piso
#Validar NA
sapply(viviendasinna, class)
## id zona piso estrato preciom areaconst
## "numeric" "character" "numeric" "numeric" "numeric" "numeric"
## parqueaderos banios habitaciones tipo barrio longitud
## "numeric" "numeric" "numeric" "character" "character" "numeric"
## latitud
## "numeric"
valores_faltantessinna <- colSums(is.na(viviendasinna))
print(valores_faltantessinna)
## id zona piso estrato preciom areaconst
## 0 0 0 0 0 0
## parqueaderos banios habitaciones tipo barrio longitud
## 0 0 0 0 0 0
## latitud
## 0
# Filtrar las ofertas de apartamentos
apartamentos <- subset(viviendasinna, tipo == "Apartamento")
# Verificar los valores únicos en la columna 'tipo'
unique(apartamentos$tipo)
## [1] "Apartamento"
# Mostrar los primeros 3 registros del dataset filtrado
head(apartamentos, 3)
# Limpiar caracteres especiales en las columnas usadas en 'text'
viviendasinna$estrato <- as.character(viviendasinna$estrato)
viviendasinna$banios <- as.character(viviendasinna$banios)
viviendasinna$habitaciones <- as.character(viviendasinna$habitaciones)
viviendasinna$zona <- enc2utf8(viviendasinna$zona)
viviendasinna$estrato <- enc2utf8(viviendasinna$estrato)
viviendasinna$banios <- enc2utf8(viviendasinna$banios)
viviendasinna$habitaciones <- enc2utf8(viviendasinna$habitaciones)
# Convertir todo el DataFrame a UTF-8
viviendasinna <- as.data.frame(lapply(viviendasinna, function(x) {
if (is.character(x)) {
return(iconv(x, from = "latin1", to = "UTF-8", sub = ""))
} else {
return(x)
}
}))
# Instalar plotly
# install.packages("plotly")
library(plotly)
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
# Crear un gráfico de dispersión Precio vs. Estrato
fig_alternative <- plot_ly(viviendasinna, x = ~estrato, y = ~preciom, type = 'scatter', mode = 'markers',
color = ~factor(estrato), colors = 'Set1') %>%
layout(title = 'Precio vs. Estrato',
xaxis = list(title = 'Estrato'),
yaxis = list(title = 'Precio'))
fig_alternative
# Crear gráfico de dispersión para área construida vs. precio
fig_area <- plot_ly(viviendasinna, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
color = ~factor(areaconst), colors = 'Set1') %>%
layout(title = 'Precio vs. Area',
xaxis = list(title = 'Area'),
yaxis = list(title = 'Precio'))
fig_area
fig_banios <- plot_ly(viviendasinna, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers',
color = ~factor(banios), colors = 'Set1') %>%
layout(title = 'Precio vs. Area',
xaxis = list(title = 'Area'),
yaxis = list(title = 'Precio'))
fig_banios
fig_habitaciones <- plot_ly(viviendasinna, x = ~habitaciones, y = ~preciom, type = 'scatter', mode = 'markers',
color = ~factor(habitaciones), colors = 'Set1') %>%
layout(title = 'Precio vs. Area',
xaxis = list(title = 'Area'),
yaxis = list(title = 'Precio'))
fig_habitaciones
# Crear gráfico de caja para precio por zona
fig_zona <- plot_ly(viviendasinna, y = ~preciom, color = ~factor(zona), type = 'box',
colors = 'Set1') %>%
layout(title = 'Precio por Zona',
xaxis = list(title = 'Zona'),
yaxis = list(title = 'Precio'))
fig_zona
# Estimar el modelo de regresión lineal múltiple
modelo <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = viviendasinna)
# Resumen del modelo
summary(modelo)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = viviendasinna)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1405.35 -66.84 -10.63 42.92 1179.03
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 117.57468 25.79698 4.558 5.25e-06 ***
## areaconst 0.85765 0.01887 45.457 < 2e-16 ***
## estrato4 41.59811 6.04497 6.881 6.36e-12 ***
## estrato5 93.49864 6.13663 15.236 < 2e-16 ***
## estrato6 308.10275 7.52211 40.960 < 2e-16 ***
## habitaciones1 18.13875 33.91430 0.535 0.592774
## habitaciones10 -126.99760 35.69356 -3.558 0.000376 ***
## habitaciones2 -18.23550 26.98555 -0.676 0.499218
## habitaciones3 2.98778 26.43377 0.113 0.910010
## habitaciones4 -27.63416 26.53737 -1.041 0.297753
## habitaciones5 -62.44655 26.97404 -2.315 0.020634 *
## habitaciones6 -110.75832 27.84684 -3.977 7.03e-05 ***
## habitaciones7 -105.10005 29.01788 -3.622 0.000294 ***
## habitaciones8 -110.14538 29.85035 -3.690 0.000226 ***
## habitaciones9 -158.17519 32.26086 -4.903 9.62e-07 ***
## parqueaderos 60.09592 2.22454 27.015 < 2e-16 ***
## banios1 -117.98872 32.86163 -3.590 0.000332 ***
## banios10 264.05385 65.54901 4.028 5.67e-05 ***
## banios2 -89.14612 31.98986 -2.787 0.005337 **
## banios3 -55.77182 31.94692 -1.746 0.080889 .
## banios4 26.44296 31.96739 0.827 0.408156
## banios5 89.88283 32.27899 2.785 0.005372 **
## banios6 147.92927 33.23365 4.451 8.65e-06 ***
## banios7 217.22416 35.93500 6.045 1.56e-09 ***
## banios8 171.91130 39.87893 4.311 1.65e-05 ***
## banios9 261.09083 53.85470 4.848 1.27e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 162.8 on 8293 degrees of freedom
## Multiple R-squared: 0.7554, Adjusted R-squared: 0.7546
## F-statistic: 1024 on 25 and 8293 DF, p-value: < 2.2e-16
La mayoría de los coeficientes son estadísticamente significativos, lo que indica que las variables independientes tienen un efecto significativo sobre el precio.
Error Estándar Residual (162.8): Un error estándar residual más bajo indica un mejor ajuste, pero siempre es importante comparar esto con el rango de precios en el dataset para evaluar su significado.
F-statistic (1024): La estadística F es muy alta y el valor p es extremadamente bajo (< 2.2e-16), lo que indica que el modelo en conjunto es significativo y explica una gran parte de la variabilidad en el precio.
Transformaciones: Si los residuos muestran patrones no aleatorios, puede ser útil transformar variables (por ejemplo, usar el logaritmo del precio).
Interacciones: Examinra posibles interacciones entre variables (por ejemplo, cómo el efecto del área construida podría depender del estrato).
Validación Cruzada: Utilizar validación cruzada para evaluar el rendimiento del modelo en diferentes subconjuntos de los datos y evitar el sobreajuste.
# Gráfico de Residuos vs. Valores Ajustados
plot(modelo$fitted.values, modelo$residuals,
xlab = "Valores Ajustados", ylab = "Residuos",
main = "Residuos vs. Valores Ajustados")
abline(h = 0, col = "red")
La relacion entre las variables es lineal
# Instalar y cargar el paquete lmtest si no está instalado
# install.packages("lmtest")
library(lmtest)
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
# Prueba de Durbin-Watson
dwtest(modelo)
##
## Durbin-Watson test
##
## data: modelo
## DW = 1.7517, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
Valor de DW = 1.7517: El valor de Durbin-Watson está cerca de 2, lo que sugiere que no hay evidencia fuerte de autocorrelación en los residuos. Sin embargo, no está exactamente en 2, lo que podría indicar alguna autocorrelación.
Valor p < 2.2e-16: Este valor p extremadamente bajo indica que hay una evidencia muy fuerte contra la hipótesis nula de que la autocorrelación es 0.
Dado que el valor p es muy bajo, es probable que los residuos estén correlacionados positivamente, lo que sugiere que los errores de predicción no son independientes entre sí.
# Prueba de Breusch-Pagan
bptest(modelo)
##
## studentized Breusch-Pagan test
##
## data: modelo
## BP = 1615.6, df = 25, p-value < 2.2e-16
# Histograma de los Residuos
hist(modelo$residuals, main = "Histograma de los Residuos",
xlab = "Residuos", breaks = 50)
El grafico indica que los residuos se comportan de manera normal, esto sugiere que los residuos están distribuidos de manera bastante simétrica y sin sesgo.
# Establecer una semilla para reproducibilidad
set.seed(123)
n <- nrow(viviendasinna)
# Índices para la partición (70% para entrenamiento, 30% para prueba)
indices <- sample(seq_len(n), size = 0.7 * n)
# Crear conjuntos de entrenamiento y prueba
train_data <- viviendasinna[indices, ]
test_data <- viviendasinna[-indices, ]
# Ajustar el modelo de regresión lineal múltiple con el conjunto de entrenamiento
modelo_entrenamiento <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = train_data)
# Resumen del modelo ajustado con el conjunto de entrenamiento
summary(modelo_entrenamiento)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1394.25 -66.55 -9.63 42.77 1169.30
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 119.55027 30.47756 3.923 8.86e-05 ***
## areaconst 0.85456 0.02255 37.890 < 2e-16 ***
## estrato4 40.76144 7.28242 5.597 2.28e-08 ***
## estrato5 93.99351 7.39607 12.709 < 2e-16 ***
## estrato6 302.35169 8.99431 33.616 < 2e-16 ***
## habitaciones1 51.59337 39.94046 1.292 0.196493
## habitaciones10 -101.95150 41.58679 -2.452 0.014254 *
## habitaciones2 4.78368 31.89790 0.150 0.880795
## habitaciones3 25.49552 31.24902 0.816 0.414601
## habitaciones4 -4.66973 31.31995 -0.149 0.881482
## habitaciones5 -38.48331 31.85767 -1.208 0.227106
## habitaciones6 -84.62401 32.82887 -2.578 0.009970 **
## habitaciones7 -76.08980 34.31172 -2.218 0.026620 *
## habitaciones8 -90.80067 35.32007 -2.571 0.010171 *
## habitaciones9 -137.38383 37.72532 -3.642 0.000273 ***
## parqueaderos 57.37242 2.66623 21.518 < 2e-16 ***
## banios1 -139.39600 39.83344 -3.499 0.000470 ***
## banios10 142.29269 90.98756 1.564 0.117903
## banios2 -109.27773 38.67769 -2.825 0.004739 **
## banios3 -81.02552 38.55683 -2.101 0.035644 *
## banios4 11.94155 38.53542 0.310 0.756659
## banios5 72.28242 38.79235 1.863 0.062468 .
## banios6 142.93941 39.86431 3.586 0.000339 ***
## banios7 218.87087 43.00195 5.090 3.70e-07 ***
## banios8 182.65884 47.07559 3.880 0.000106 ***
## banios9 327.45775 67.59509 4.844 1.30e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 162.7 on 5797 degrees of freedom
## Multiple R-squared: 0.7542, Adjusted R-squared: 0.7531
## F-statistic: 711.3 on 25 and 5797 DF, p-value: < 2.2e-16
Estrato 4 (40.76), Estrato 5 (93.99) y Estrato 6 (302.35): Estos coeficientes indican el incremento en el precio comparado con el estrato de referencia. Los coeficientes son significativos y positivos, mostrando que un estrato más alto está asociado con un precio más alto.
Habitaciones 1 (51.59) y Habitaciones 2,3,4,…,10 (-101.95): Algunos coeficientes son significativos, indicando que el número de habitaciones tiene un efecto en el precio, aunque los efectos no son uniformes a través de todas las categorías.
# Predicciones en el conjunto de prueba
predicciones_test <- predict(modelo_entrenamiento, newdata = test_data)
# Comparar las predicciones con los valores reales
resultados <- data.frame(Real = test_data$preciom, Prediccion = predicciones_test)
# Mostrar las primeras filas de los resultados
head(resultados)
# Cálculo del MSE (Error Cuadrático Medio) en el conjunto de prueba
mse_test <- mean((test_data$preciom - predicciones_test)^2)
mse_test
## [1] 26766.4
# Cálculo del MAE (Error Absoluto Medio) en el conjunto de prueba
mae_test <- mean(abs(test_data$preciom - predicciones_test))
mae_test
## [1] 99.78438
# Cálculo del R2 en el conjunto de prueba
ss_total <- sum((test_data$preciom - mean(test_data$preciom))^2)
ss_residual <- sum((test_data$preciom - predicciones_test)^2)
r2_test <- 1 - (ss_residual / ss_total)
r2_test
## [1] 0.7561565
MSE (26766.4): Indica que el error cuadrático medio de las predicciones es relativamente alto. Esto sugiere que hay una cantidad significativa de variabilidad en las predicciones que no es capturada por el modelo.
MAE (99.78438): Significa que, en promedio, el modelo se desvía en aproximadamente 99.78 de precio de los valores reales. Comparado con el rango de precios, este valor puede ser considerado relativamente alto
R2 (0.7561565): Significa que aproximadamente el 75.6% de la variabilidad en el precio de las viviendas es explicada por el modelo. Esto indica que el modelo tiene un buen ajuste, ya que una proporción significativa de la variabilidad en los precios se explica por las variables independientes incluidas en el modelo.