Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta.
head(data)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parquea banios habitac tipo
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 8312 Zona Oeste 4 6 1300 318 2 4 2 Apart…
## 2 8311 Zona Oeste 1 6 480 300 1 4 4 Casa
## 3 8307 Zona Oeste NA 5 1200 800 4 7 5 Casa
## 4 8296 Zona Sur 2 3 220 150 1 2 4 Casa
## 5 8297 Zona Oeste NA 5 330 112 2 4 3 Casa
## 6 8298 Zona Sur NA 5 1350 390 8 10 10 Casa
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
data$tipo = tolower(data$tipo)
data = data%>% mutate(tipo = ifelse(tipo == "apto","apartamento", tipo))
apartamento_df= subset(data, data$tipo=="apartamento")
head(apartamento_df, 3)
## # A tibble: 3 × 13
## id zona piso estrato preciom areaconst parquea banios habitac tipo
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 8312 Zona Oeste 4 6 1300 318 2 4 2 apart…
## 2 8299 Zona Sur 2 6 305 125 2 3 3 apart…
## 3 8300 Zona Oeste NA 5 480 280 4 4 4 apart…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
pl = ggplot(apartamento_df, aes(x = zona, fill = tipo))
pl = pl + geom_bar(stat = "count")
pl
Con esta grafica podemos verificar que nuestra base de datos solo contiene apartamentos.
faltantes = colSums(is.na(apartamento_df))
faltantes
## id zona piso estrato preciom areaconst parquea banios
## 0 0 1383 0 0 0 869 0
## habitac tipo barrio longitud latitud
## 0 0 0 0 0
Tratamiento de datos faltantes
median_piso = median(apartamento_df$piso)
median_parquea = median(apartamento_df$parquea)
apartamento_df$piso[is.na(apartamento_df$piso)] = median_piso
apartamento_df$parquea[is.na(apartamento_df$parquea)] = median_parquea
faltantes2 = colSums(is.na(apartamento_df))
faltantes2
## id zona piso estrato preciom areaconst parquea banios
## 0 0 0 0 0 0 0 0
## habitac tipo barrio longitud latitud
## 0 0 0 0 0
Eliminare las colunas id, barrio, longitud y latitud, ya que no se necesarias para este estudio. Tambien eliminare la columna Tipo ya que ha dejado de ser una variable y ya corroboramos que nuestra base de datos conitene solo apartamenetos.
apartamento_df = apartamento_df[,c(-1, -10, -11, -12, -13)]
sapply(apartamento_df, class)
## zona piso estrato preciom areaconst parquea
## "character" "numeric" "numeric" "numeric" "numeric" "numeric"
## banios habitac
## "numeric" "numeric"
summary(apartamento_df)
## zona piso estrato preciom
## Length:5106 Min. : 1.000 Min. :3.000 Min. : 58.0
## Class :character 1st Qu.: 3.000 1st Qu.:4.000 1st Qu.: 175.0
## Mode :character Median : 4.000 Median :5.000 Median : 280.0
## Mean : 4.463 Mean :4.729 Mean : 367.6
## 3rd Qu.: 5.000 3rd Qu.:6.000 3rd Qu.: 430.0
## Max. :12.000 Max. :6.000 Max. :1950.0
## areaconst parquea banios habitac
## Min. : 35.0 Min. : 1.000 Min. :0.000 Min. :0.000
## 1st Qu.: 68.0 1st Qu.: 1.000 1st Qu.:2.000 1st Qu.:3.000
## Median : 90.0 Median : 1.000 Median :2.000 Median :3.000
## Mean :112.9 Mean : 1.472 Mean :2.619 Mean :2.972
## 3rd Qu.:130.0 3rd Qu.: 2.000 3rd Qu.:3.000 3rd Qu.:3.000
## Max. :932.0 Max. :10.000 Max. :8.000 Max. :9.000
summary_stats = aggregate(preciom~zona, data = apartamento_df, FUN = mean)
print(summary_stats)
## zona preciom
## 1 Zona Centro 186.5833
## 2 Zona Norte 285.2577
## 3 Zona Oeste 669.2676
## 4 Zona Oriente 152.5968
## 5 Zona Sur 297.3550
boxplot(preciom ~ zona, data = apartamento_df, main = "Precio por Zona", xlab = "Zona", ylab = "Precio")
summary_stats2 = aggregate(preciom~estrato, data = apartamento_df, FUN = mean)
print(summary_stats2)
## estrato preciom
## 1 3 128.9765
## 2 4 206.9651
## 3 5 335.0475
## 4 6 703.7515
boxplot(preciom ~ estrato, data = apartamento_df, main = "Precio por estrato", xlab = "estrato", ylab = "Precio")
fig1 = plot_ly(data = apartamento_df,
x = ~areaconst,
y = ~preciom,
type = 'scatter',
mode = 'markers') %>%
layout(title = "Precio vs Área Construida")
fig1
fig2 = plot_ly(data = apartamento_df,
x = ~piso,
y = ~preciom,
type = 'scatter',
mode = 'markers') %>%
layout(title = "Precio vs Piso")
fig2
fig3 = plot_ly(data = apartamento_df,
x = ~parquea,
y = ~preciom,
type = 'scatter',
mode = 'markers') %>%
layout(title = "Precio vs Parqueaderos")
fig3
fig4 = plot_ly(data = apartamento_df,
x = ~banios,
y = ~preciom,
type = 'scatter',
mode = 'markers') %>%
layout(title = "Precio vs Baños")
fig4
fig5 = plot_ly(data = apartamento_df,
x = ~habitac,
y = ~preciom,
type = 'scatter',
mode = 'markers') %>%
layout(title = "Precio vs Habitaciones")
fig5
corr = apartamento_df[, c("piso", "areaconst", "parquea", "banios", "habitac", "preciom")]
ggpairs(corr, title="GGally")
modelo = lm(preciom ~ areaconst + parquea + banios, data = apartamento_df)
summary(modelo)
##
## Call:
## lm(formula = preciom ~ areaconst + parquea + banios, data = apartamento_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1709.57 -51.10 -5.25 44.44 1084.21
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -180.52016 5.44533 -33.15 <2e-16 ***
## areaconst 2.04354 0.04453 45.89 <2e-16 ***
## parquea 115.06230 3.82759 30.06 <2e-16 ***
## banios 56.48425 2.76699 20.41 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 139.5 on 5102 degrees of freedom
## Multiple R-squared: 0.7688, Adjusted R-squared: 0.7687
## F-statistic: 5656 on 3 and 5102 DF, p-value: < 2.2e-16
par(mfrow=c(2,2))
plot(modelo)
# Check the length of residuals
n_residuals = length(modelo$residuals)
if (n_residuals < 3 || n_residuals > 5000) {
cat("The sample size for the Shapiro-Wilk test should be between 3 and 5000. Current size:", n_residuals)
} else {
shapiro_result <- shapiro.test(modelo$residuals)
print(shapiro_result)
}
## The sample size for the Shapiro-Wilk test should be between 3 and 5000. Current size: 5106
# Set a seed for reproducibility
set.seed(123)
# Sample 5000 residuals randomly
sampled_residuals <- sample(modelo$residuals, size = 5000)
# Perform the Shapiro-Wilk test on the sampled residuals
shapiro_result <- shapiro.test(sampled_residuals)
# Print the result
print(shapiro_result)
##
## Shapiro-Wilk normality test
##
## data: sampled_residuals
## W = 0.83301, p-value < 2.2e-16
Ya que el p-val = 0 < 0.05. No se cumple el supuesto de normalidad de los residuos.
lmtest::bptest(modelo)
##
## studentized Breusch-Pagan test
##
## data: modelo
## BP = 1392.3, df = 3, p-value < 2.2e-16
Ya que el p-val = 0< 0.05. No se cumple el supuesto de homocedasticidad de los residuos.
lmtest::dwtest(modelo)
##
## Durbin-Watson test
##
## data: modelo
## DW = 1.7164, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
Ya que el p-val = 0 < 0.05. No se cumple el supuesto de no autocorrelación de errores de los residuos.
# crear indices aleatorios par la particion
indices = sample(1:nrow(apartamento_df), size = 0.7*nrow(apartamento_df))
#crear conjuntos de entrenamiento y prueba
train_data = apartamento_df[indices, ]
test_data = apartamento_df[indices, ]
# estimar el modelo con la muestra de entrenamiento
modelo2 = lm(preciom ~ areaconst + parquea + banios, data = train_data)
summary(modelo2)
##
## Call:
## lm(formula = preciom ~ areaconst + parquea + banios, data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1559.67 -51.45 -6.11 45.22 1106.09
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -187.63851 6.61724 -28.36 <2e-16 ***
## areaconst 1.86677 0.05284 35.33 <2e-16 ***
## parquea 127.27188 4.70078 27.07 <2e-16 ***
## banios 59.73696 3.34156 17.88 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 141.7 on 3570 degrees of freedom
## Multiple R-squared: 0.7622, Adjusted R-squared: 0.762
## F-statistic: 3814 on 3 and 3570 DF, p-value: < 2.2e-16
# Realizaar predicciones con el modelo
predicciones = predict(modelo2, newdata = test_data)
# agregar predicciones al conjunto de prueba para comaracion
resultados = data.frame(Real = test_data$preciom, Predicho = predicciones)
print(head(resultados))
## Real Predicho
## 1 1350 989.7532
## 2 350 430.9260
## 3 480 623.2034
## 4 153 171.1133
## 5 160 169.2465
## 6 270 223.3827
mae = mean((abs(resultados$Real - resultados$Predicho)))
cat("Error Absoluto Medio (MAE):", mae, "\n")
## Error Absoluto Medio (MAE): 85.26666
Este valor indica que, en promedio, las predicciones del modelo se desvían de los valores reales en aproximadamente 85.27 Millones de pesos.
rmse = sqrt(mean((resultados$Real - resultados$Predicho)^2))
cat("Error Cuadratico Medio (RMSE):", rmse, "\n")
## Error Cuadratico Medio (RMSE): 141.6249
El RMSE de aproximadamente 141.62 indica que la raíz cuadrada del promedio de las diferencias al cuadrado entre las predicciones y los valores reales es de 141.62 unidades. Este valor es más alto que el MAE, lo que puede sugerir que existen algunos errores significativamente grandes que están influyendo en el RMSE. Esto podría indicar que el modelo tiene algunos casos atípicos o predicciones que se desvían mucho de los valores reales.
r2 = 1 - (sum((resultados$Real - resultados$Predicho)^2)/ sum((resultados$Real - mean(resultados$Real))^2))
cat("R-Squared:", r2, "\n")
## R-Squared: 0.7621873
Un R² de 0.7621 significa que aproximadamente el 76.21% de la variabilidad en los datos reales se explica por el modelo. Este es un buen valor, ya que sugiere que el modelo tiene una capacidad razonable para predecir los resultados. Sin embargo, hay un 23.79% de la variabilidad que no se explica, lo que puede ser debido a factores no considerados en el modelo o a la naturaleza aleatoria de los datos.
Los resultados indican que el modelo tiene un desempeño aceptable. El MAE y el RMSE son relativamente altos, lo que sugiere que hay espacio para mejorar en la precisión de las predicciones, tal vez a través de la optimización del modelo o la inclusión de variables adicionales.
El R² indica que el modelo es capaz de explicar una buena parte de la variabilidad de los datos, lo que sugiere que hay una relación significativa entre las variables analizadas.