head(vivienda)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… <NA> 3 250 70 1 3 6
## 2 1169 Zona O… <NA> 3 320 120 1 2 3
## 3 1350 Zona O… <NA> 3 350 220 2 2 4
## 4 5992 Zona S… 02 4 400 280 3 5 3
## 5 1212 Zona N… 01 5 260 90 1 2 3
## 6 1724 Zona N… 01 5 240 87 1 3 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
dim(vivienda)
## [1] 8322 13
colSums(is.na(vivienda))
## 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
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
table(vivienda$tipo)
##
## Apartamento Casa
## 5100 3219
table(vivienda$zona)
##
## Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
## 124 1920 1198 351 4726
table(vivienda$piso)
##
## 01 02 03 04 05 06 07 08 09 10 11 12
## 860 1450 1097 607 567 245 204 211 146 130 84 83
table(vivienda$estrato)
##
## 3 4 5 6
## 1453 2129 2750 1987
df_cleaned <- vivienda %>% filter(!is.na(id) & id != "")
colSums(is.na(df_cleaned))
## 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
df_cleaned$piso <- as.numeric(df_cleaned$piso)
head(df_cleaned)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… NA 3 250 70 1 3 6
## 2 1169 Zona O… NA 3 320 120 1 2 3
## 3 1350 Zona O… NA 3 350 220 2 2 4
## 4 5992 Zona S… 2 4 400 280 3 5 3
## 5 1212 Zona N… 1 5 260 90 1 2 3
## 6 1724 Zona N… 1 5 240 87 1 3 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
print(table(df_cleaned$estrato))
##
## 3 4 5 6
## 1453 2129 2750 1987
df_cleaned$E4 <- as.numeric(df_cleaned$estrato==4)
df_cleaned$E5 <- as.numeric(df_cleaned$estrato==5)
df_cleaned$E6 <- as.numeric(df_cleaned$estrato==6)
df_cleaned$T1 <- as.numeric(df_cleaned$tipo=='Casa')
df_cleaned$Z1 <- as.numeric(df_cleaned$zona=='Zona Centro')
df_cleaned$Z2 <- as.numeric(df_cleaned$zona=='Zona Norte')
df_cleaned$Z3 <- as.numeric(df_cleaned$zona=='Zona Oeste')
df_cleaned$Z4 <- as.numeric(df_cleaned$zona=='Zona Sur')
head(df_cleaned)
## # A tibble: 6 × 21
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… NA 3 250 70 1 3 6
## 2 1169 Zona O… NA 3 320 120 1 2 3
## 3 1350 Zona O… NA 3 350 220 2 2 4
## 4 5992 Zona S… 2 4 400 280 3 5 3
## 5 1212 Zona N… 1 5 260 90 1 2 3
## 6 1724 Zona N… 1 5 240 87 1 3 3
## # ℹ 12 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # E4 <dbl>, E5 <dbl>, E6 <dbl>, T1 <dbl>, Z1 <dbl>, Z2 <dbl>, Z3 <dbl>,
## # Z4 <dbl>
df_cleaned <- df_cleaned %>% dplyr::select(-id)
head(df_cleaned)
## # A tibble: 6 × 20
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Zona O… NA 3 250 70 1 3 6 Casa
## 2 Zona O… NA 3 320 120 1 2 3 Casa
## 3 Zona O… NA 3 350 220 2 2 4 Casa
## 4 Zona S… 2 4 400 280 3 5 3 Casa
## 5 Zona N… 1 5 260 90 1 2 3 Apar…
## 6 Zona N… 1 5 240 87 1 3 3 Apar…
## # ℹ 11 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, E4 <dbl>,
## # E5 <dbl>, E6 <dbl>, T1 <dbl>, Z1 <dbl>, Z2 <dbl>, Z3 <dbl>, Z4 <dbl>
# Subconjunto de datos para "Casa"
dfCasa <- subset(df_cleaned, tipo == "Casa")
dfApto <- subset(df_cleaned, tipo == "Apartamento")
mediaPisoCasa <- round(mean(dfCasa$piso, na.rm = TRUE))
mediaPisoApto <- round(mean(dfApto$piso, na.rm = TRUE))
df_cleaned <- df_cleaned %>%
dplyr::mutate(piso = ifelse(tipo == "Casa" & is.na(piso), mediaPisoCasa, piso)) %>%
dplyr::mutate(piso = ifelse(tipo == "Apartamento" & is.na(piso), mediaPisoApto, piso))
colSums(is.na(df_cleaned))
## zona piso estrato preciom areaconst parqueaderos
## 0 0 0 0 0 1602
## banios habitaciones tipo barrio longitud latitud
## 0 0 0 0 0 0
## E4 E5 E6 T1 Z1 Z2
## 0 0 0 0 0 0
## Z3 Z4
## 0 0
## zona piso estrato preciom areaconst parqueaderos
## 0 0 0 0 0 0
## banios habitaciones tipo barrio longitud latitud
## 0 0 0 0 0 0
## E4 E5 E6 T1 Z1 Z2
## 0 0 0 0 0 0
## Z3 Z4
## 0 0
Realice un filtro a la base de datos e incluya sólo las ofertas de apartamentos. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta.
dfApto <- subset(df_cleaned, tipo == "Apartamento")
head(dfApto, 3)
## # A tibble: 3 × 20
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Zona N… 1 5 260 90 1 2 3 Apar…
## 2 Zona N… 1 5 240 87 1 3 3 Apar…
## 3 Zona N… 1 4 220 52 2 2 3 Apar…
## # ℹ 11 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>, E4 <dbl>,
## # E5 <dbl>, E6 <dbl>, T1 <dbl>, Z1 <dbl>, Z2 <dbl>, Z3 <dbl>, Z4 <dbl>
Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio de la casa) en función del área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.
cor_matrix <- dfApto %>%
select(preciom, areaconst, banios, habitaciones, parqueaderos) %>%
cor()
cor_data <- as.data.frame(as.table(cor_matrix))
# Crear el gráfico de calor con valores de correlación
p_heatmap <- ggplot(cor_data, aes(Var1, Var2, fill = Freq)) +
geom_tile(color = "white") +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1, 1), space = "Lab",
name = "Correlación") +
labs(title = "Imágen 2.1. Mapa de calor de correlaciones", x = "", y = "") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, vjust = 1,
size = 12, hjust = 1)) +
coord_fixed() +
geom_text(aes(label = round(Freq, 2)), color = "black", size = 4) # Añadir valores
# Convertir el gráfico en interactivo con plotly
ggplotly(p_heatmap)
p1 <- ggplot(dfApto, aes(x = preciom, y = areaconst)) +
geom_point(colour = '#F8766D', size = 1, shape=5) +
labs(title = "Imagen 2.2. Relación entre Área Precio y Construida", x = "Precio de la Vivienda", y = "Área Construida")
ggplotly(p1)
p1 <- ggplot(dfApto, aes(x = preciom, y = estrato)) +
geom_point(colour = '#F8766D', size = 1, shape=5) +
labs(title = "Imagen 2.3. Relación entre Precio y Estrato", x = "Precio en millones de pesos", y = "Estrato")
ggplotly(p1)
p1 <- ggplot(dfApto, aes(x = preciom, y = banios)) +
geom_point(colour = '#F8766D', size = 1, shape=5) +
labs(title = "Imagen 2.4 Relación entre Precio y Número de baños", x = "Precio en millones", y = "Numero de baños")
ggplotly(p1)
p1 <- ggplot(dfApto, aes(x = preciom, y = habitaciones)) +
geom_point(colour = '#F8766D', size = 1, shape=5) +
labs(title = "Imagen 2.5 Relación entre Precio y Número de habitaciones", x = "Precio en millones", y = "Numero de habitaciones")
ggplotly(p1)
p2 <- ggplot(dfApto, aes(x = zona, y = preciom, fill = zona)) +
geom_boxplot() +
labs(title = "Imagen 2.6. Distribución de Precio por Zona", x = "Zona", y = "Precio de la Vivienda")
ggplotly(p2)
p1 <- ggplot(dfApto, aes(x = areaconst, y = parqueaderos)) +
geom_point(colour = '#F8766D', size = 1, shape=5) +
labs(title = "Imagen 2.7 Relación entre areaconst y Parqueaderos", x = "Area construida", y = "Numero de parqueaderos")
ggplotly(p1)
p1 <- ggplot(dfApto, aes(x = areaconst, y = banios)) +
geom_point(colour = '#F8766D', size = 1, shape=5) +
labs(title = "Imagen 2.7 Relación entre areaconst y Baños", x = "Area construida", y = "Numero de baños")
ggplotly(p1)
Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deber están contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).
modelo <- lm(preciom ~ areaconst + E4 + E5 + E6 + parqueaderos + banios, data = dfApto)
summary(modelo)
##
## Call:
## lm(formula = preciom ~ areaconst + E4 + E5 + E6 + parqueaderos +
## banios, data = dfApto)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1570.36 -46.68 0.40 40.22 976.75
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -139.98484 6.62400 -21.133 < 2e-16 ***
## areaconst 1.89670 0.04224 44.899 < 2e-16 ***
## E4 32.24345 6.28857 5.127 3.05e-07 ***
## E5 50.21416 6.40333 7.842 5.37e-15 ***
## E6 193.79512 8.04815 24.079 < 2e-16 ***
## parqueaderos 78.76461 3.73532 21.086 < 2e-16 ***
## banios 37.54780 2.70023 13.905 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 129.5 on 5093 degrees of freedom
## Multiple R-squared: 0.7997, Adjusted R-squared: 0.7995
## F-statistic: 3390 on 6 and 5093 DF, p-value: < 2.2e-16
set.seed(123)
n <- nrow(dfApto)
train_indices <- sample(1:n, size = 0.7 * n)
train_data <- df_cleaned[train_indices, ] # 70% entrenamiento
test_data <- df_cleaned[-train_indices, ] # 30% validación
modelo_train <- lm(preciom ~ areaconst + E4 + E5 + E6 + parqueaderos + banios, data = train_data)
summary(modelo_train)
##
## Call:
## lm(formula = preciom ~ areaconst + E4 + E5 + E6 + parqueaderos +
## banios, data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1267.04 -70.22 -7.20 46.48 1224.32
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -67.13288 7.96801 -8.425 < 2e-16 ***
## areaconst 0.76638 0.02652 28.902 < 2e-16 ***
## E4 54.22494 8.45144 6.416 1.58e-10 ***
## E5 105.84973 8.10811 13.055 < 2e-16 ***
## E6 312.60479 9.60989 32.529 < 2e-16 ***
## parqueaderos 73.63249 3.45341 21.322 < 2e-16 ***
## banios 34.85708 2.60837 13.364 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 163.8 on 3563 degrees of freedom
## Multiple R-squared: 0.7296, Adjusted R-squared: 0.7291
## F-statistic: 1602 on 6 and 3563 DF, p-value: < 2.2e-16
predicciones_test <- predict(modelo_train, newdata = test_data)
# Hacer predicciones en el conjunto de validación
predicciones_test <- predict(modelo_train, newdata = test_data)
# Calcular el MSE (Error Cuadrático Medio)
mse <- mean((test_data$preciom - predicciones_test)^2)
# Calcular el MAE (Error Absoluto Medio)
mae <- mean(abs(test_data$preciom - predicciones_test))
# Calcular el R^2
ss_total <- sum((test_data$preciom - mean(test_data$preciom))^2)
ss_residual <- sum((test_data$preciom - predicciones_test)^2)
r_squared <- 1 - (ss_residual / ss_total)
# Mostrar los resultados
cat("El Error Cuadrático Medio (MSE) es:", mse, "\n")
## El Error Cuadrático Medio (MSE) es: 28247.91
cat("El Error Absoluto Medio (MAE) es:", mae, "\n")
## El Error Absoluto Medio (MAE) es: 98.85741
cat("El coeficiente de determinación (R^2) es:", r_squared, "\n")
## El coeficiente de determinación (R^2) es: 0.7537592
Este valor es relativamente alto, lo que sugiere que el modelo tiene algunos errores en las predicciones. El modelo aunque explica un buen porcentaje, al rededor de 75%, no puede explicar el 25% y esto produce un MSE relativamente alto.
El MAE indica que, en promedio, el modelo se desvía en aproximadamente 98.86 unidades monetarias de los precios reales. Este valor proporciona una idea más intuitiva del tamaño promedio de los errores en las predicciones. Aunque los errores en el MAE son relativamente pequeños, sugiere que el modelo comete errores consistentes al predecir los precios, pero no penaliza tanto los errores más grandes como lo hace el MSE.
Este valor nos indica que el modelo esta capturando 75% de la variabilidad de los precios de las viviendas. Esto sugiere que las variables (área construida, estrato, número de parqueaderos y baños) son factores importantes en la determinación del precio pero no explican 25% de la variabilidad.