Realice un filtro a la base de datos e incluya solo las ofertas de:
base1: casas, de la zona norte de la ciudad.
base2: apartamentos, de la zona sur de la ciudad.
Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta. (Adicional un mapa con los puntos de las bases. Discutir si todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).
# Import data
data("vivienda")
vivienda$zona <- as.factor(vivienda$zona)
vivienda$piso <- as.factor(vivienda$piso)
vivienda$estrato <- as.factor(vivienda$estrato)
vivienda$tipo <- as.factor(vivienda$tipo)
vivienda$banios <- as.factor(vivienda$banios)
vivienda$habitaciones <- as.factor(vivienda$habitaciones)
#Subset base1
base1 <- data.frame(subset(vivienda, tipo == "Casa" & zona == "Zona Norte"))
#Subset base2
base2 <- data.frame(subset(vivienda, tipo == "Apartamento" & zona == "Zona Sur"))
formattable(head(base1, 3))
id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1209 | Zona Norte | 02 | 5 | 320 | 150 | 2 | 4 | 6 | Casa | acopi | -76.51341 | 3.47968 |
1592 | Zona Norte | 02 | 5 | 780 | 380 | 2 | 3 | 3 | Casa | acopi | -76.51674 | 3.48721 |
4057 | Zona Norte | 02 | 6 | 750 | 445 | NA | 7 | 6 | Casa | acopi | -76.52950 | 3.38527 |
summary(base1)
id zona piso estrato preciom
Min. : 58.0 Zona Centro : 0 02 :194 3:235 Min. : 89.0
1st Qu.: 766.2 Zona Norte :722 01 : 84 4:161 1st Qu.: 261.2
Median :2257.0 Zona Oeste : 0 03 : 65 5:271 Median : 390.0
Mean :2574.6 Zona Oriente: 0 04 : 6 6: 55 Mean : 445.9
3rd Qu.:4225.0 Zona Sur : 0 07 : 1 3rd Qu.: 550.0
Max. :8319.0 (Other): 0 Max. :1940.0
NA's :372
areaconst parqueaderos banios habitaciones
Min. : 30.0 Min. : 1.000 3 :187 4 :222
1st Qu.: 140.0 1st Qu.: 1.000 4 :171 3 :171
Median : 240.0 Median : 2.000 2 :165 5 :137
Mean : 264.9 Mean : 2.182 5 :101 6 : 60
3rd Qu.: 336.8 3rd Qu.: 3.000 6 : 46 7 : 42
Max. :1440.0 Max. :10.000 1 : 17 8 : 29
NA's :287 (Other): 35 (Other): 61
tipo barrio longitud latitud
Apartamento: 0 Length:722 Min. :-76.59 Min. :3.333
Casa :722 Class :character 1st Qu.:-76.53 1st Qu.:3.452
Mode :character Median :-76.52 Median :3.468
Mean :-76.52 Mean :3.460
3rd Qu.:-76.50 3rd Qu.:3.482
Max. :-76.47 Max. :3.496
leaflet(c(base1$latitud, base1$longitud)) %>%
addTiles() %>%
addMarkers(lng=base1$longitud, lat=base1$latitud,
popup = paste("Lat:", round(base1$latitud, 2),
"Long:", round(base1$longitud, 2)))
formattable(head(base2, 3))
id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
---|---|---|---|---|---|---|---|---|---|---|---|---|
5098 | Zona Sur | 05 | 4 | 290 | 96 | 1 | 2 | 3 | Apartamento | acopi | -76.53464 | 3.44987 |
698 | Zona Sur | 02 | 3 | 78 | 40 | 1 | 1 | 2 | Apartamento | aguablanca | -76.50100 | 3.40000 |
8199 | Zona Sur | NA | 6 | 875 | 194 | 2 | 5 | 3 | Apartamento | aguacatal | -76.55700 | 3.45900 |
summary(base2)
id zona piso estrato preciom
Min. : 3 Zona Centro : 0 05 :353 3: 201 Min. : 75.0
1st Qu.:2292 Zona Norte : 0 03 :329 4:1091 1st Qu.: 175.0
Median :4004 Zona Oeste : 0 04 :327 5:1033 Median : 245.0
Mean :4131 Zona Oriente: 0 02 :319 6: 462 Mean : 297.3
3rd Qu.:5876 Zona Sur :2787 01 :255 3rd Qu.: 335.0
Max. :8302 (Other):582 Max. :1750.0
NA's :622
areaconst parqueaderos banios habitaciones
Min. : 40.00 Min. : 1.000 2 :1588 3 :1902
1st Qu.: 65.00 1st Qu.: 1.000 3 : 662 2 : 463
Median : 85.00 Median : 1.000 4 : 229 4 : 366
Mean : 97.47 Mean : 1.415 1 : 167 5 : 24
3rd Qu.:110.00 3rd Qu.: 2.000 5 : 123 1 : 19
Max. :932.00 Max. :10.000 6 : 10 0 : 8
NA's :406 (Other): 8 (Other): 5
tipo barrio longitud latitud
Apartamento:2787 Length:2787 Min. :-76.57 Min. :3.334
Casa : 0 Class :character 1st Qu.:-76.54 1st Qu.:3.370
Mode :character Median :-76.53 Median :3.383
Mean :-76.53 Mean :3.390
3rd Qu.:-76.52 3rd Qu.:3.406
Max. :-76.46 Max. :3.497
leaflet(c(base2$latitud, base2$longitud)) %>%
addTiles() %>%
addMarkers(lng = base2$longitud, lat = base2$latitud,
popup = paste("Lat:", round(base2$latitud, 2),
"Long:", round(base2$longitud, 2)))
Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio) 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.
gg_miss_var(base1, show_pct = TRUE) +
labs(title = "Datos Faltantes Casas Zona Sur") +
theme(plot.title = element_text(hjust = 0.5, face = "bold"))
Se observa una gran cantidad de datos faltantes para el atributo piso y parqueaderos, por lo que se determinará la relación con los otros atributos.
par(mfrow = c(2, 3), oma = c(0, 0, 3, 0))
# Plot empty pisos per habitaciones
piso_hab_bar1 <- barplot(piso_hab_base1, names.arg = hab_base1,
main = "Piso = NA por Habitaciones",
ylab = "Registros vacíos",
xlab = "Habitaciones",
las = 2)
# Plot empty pisos per estrato
piso_estr_bar1 <- barplot(piso_estr_base1, names.arg = estr_base1,
main = "Piso = NA por estrato",
ylab = "Registros vacíos",
xlab = "estrato",
las = 2)
# Plot empty pisos per banios
piso_ban_bar1 <- barplot(piso_ban_base1, names.arg = ban_base1,
main = "Piso = NA por banios",
ylab = "Registros vacíos",
xlab = "banios",
las = 2)
# Plot empty pisos per precio
piso_prec_bar1 <- barplot(piso_prec_base1, names.arg = breaks_prec_1,
main = "Piso = NA por precio",
ylab = "Registros vacíos",
xlab = "Precio",
las = 2)
# Plot empty pisos per area
piso_area_bar1 <- barplot(piso_area_base1, names.arg = breaks_area_1,
main = "Piso = NA por area",
ylab = "Registros vacíos",
xlab = "Area",
las = 2)
mtext("Distribución de valores vacíos de piso por atributo",
side = 3, outer = TRUE, cex = 1.2, font = 2)
par(mfrow = c(1, 1))
Se observa que los valores faltantes del atributo piso no se comportan de manera aleatoria respecto a los demás atributos excepto para el estrato. A continuación, se determina la mediana para cada caso con el fin de establecer con qué valor se imputarán los datos faltantes del atributo piso
par(mfrow = c(2, 3),
oma = c(0, 0, 3, 0),
xpd = FALSE)
# Plot empty pisos per habitaciones
piso_hab_box1 <- boxplot(base1$piso ~ base1$habitaciones,
main = "Piso vs Habitaciones",
ylab = "Pisos",
xlab = "Habitaciones",
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
# Plot empty pisos per estrato
piso_estr_box1 <- boxplot(base1$piso ~ base1$estrato,
main = "Piso vs Estrato",
ylab = "Pisos",
xlab = "Estrato",
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
# Plot empty pisos per banios
piso_banios_box1 <- boxplot(base1$piso ~ base1$banios,
main = "Piso vs Banios",
ylab = "Pisos",
xlab = "Banios",
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
# Plot empty pisos per preciom
piso_prec_box1 <- boxplot(base1$piso ~ base1$class_prec,
main = "Piso vs Preciom",
ylab = "Pisos",
xlab = NA,
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
# Plot empty pisos per area
piso_area_box1 <- boxplot(base1$piso ~ base1$class_area,
main = "Piso vs areaconst",
ylab = "Pisos",
xlab = NA,
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
mtext("Distribución de piso por atributo",
side = 3, outer = TRUE, cex = 1.2, font = 2)
par(mfrow = c(1, 1))
Se observa que para la mayoría de los valores de los atributos, la mediana de los pisos es 2 excepto cuando:
Todos los registros con pisos vacíos que no contengan las condiciones anteriores, se imputaron con un valor de 2.
Luego de esa imputación, quedaron 27 valores vacíos en el atributo piso mostrados a continuación.
base1[is.na(base1$piso), c("piso", "banios", "habitaciones", "class_prec", "class_area")]
piso banios habitaciones class_prec class_area
47 NA 8 0 600-800 300-400
63 NA 8 6 400-600 300-400
69 NA 0 0 1200-1400 700-800
114 NA 7 5 1600-1800 700-800
222 NA 4 7 800-1000 700-800
223 NA 5 9 600-800 300-400
229 NA 4 9 400-600 300-400
443 NA 8 8 400-600 300-400
456 NA 6 5 600-800 700-800
480 NA 8 5 1000-1200 500-600
510 NA 5 9 400-600 300-400
512 NA 5 10 1600-1800 700-800
513 NA 8 10 1800-2000 700-800
561 NA 5 9 200-400 300-400
604 NA 6 6 1200-1400 700-800
Para los registros faltantes, se anotan las medianas que cada atributo tiene para el atributo piso:
Asi, todos los valores faltantes de piso, se imputaran por 2.
par(mfrow = c(2, 3), oma = c(0, 0, 3, 0))
# Plot empty parqueaderos per habitaciones
parq_hab_bar1 <- barplot(parq_hab_base1, names.arg = hab_base1,
main = "Parqueaderos = NA por Habitaciones",
ylab = "Registros vacíos",
xlab = "Habitaciones",
las = 2)
# Plot empty parqueaderos per estrato
parq_estr_bar1 <- barplot(parq_estr_base1, names.arg = estr_base1,
main = "Parqueaderos = NA por estrato",
ylab = "Registros vacíos",
xlab = "estrato",
las = 2)
# Plot empty parqueaderos per banios
parq_ban_bar1 <- barplot(parq_ban_base1, names.arg = ban_base1,
main = "Parqueaderos = NA por banios",
ylab = "Registros vacíos",
xlab = "banios",
las = 2)
# Plot empty parqueaderos per precio
parq_prec_bar1 <- barplot(parq_prec_base1, names.arg = breaks_prec_1,
main = "Parqueaderos = NA por precio",
ylab = "Registros vacíos",
xlab = "Precio",
las = 2)
# Plot empty parqueaderos per area
parq_area_bar1 <- barplot(parq_area_base1, names.arg = breaks_area_1,
main = "Parqueaderos = NA por area",
ylab = "Registros vacíos",
xlab = "Area",
las = 2)
mtext("Distribución de valores vacíos de parqueaderos por atributo",
side = 3, outer = TRUE, cex = 1.2, font = 2)
par(mfrow = c(1, 1))
Se observa que los valores faltantes del atributo parqueaderos no se comportan de manera aleatoria respecto a los demás atributos. A continuación, se determina la mediana para cada caso con el fin de establecer con qué valor se imputarán los datos faltantes.
par(mfrow = c(2, 3),
oma = c(0, 0, 3, 0),
xpd = FALSE)
# Plot empty parqueaderos per habitaciones
parq_hab_box1 <- boxplot(base1$parqueaderos ~ base1$habitaciones,
main = "Parqueaderos vs Habitaciones",
ylab = "Parqueaderos",
xlab = "Habitaciones",
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
# Plot empty parqueaderos per estrato
parq_estr_box1 <- boxplot(base1$parqueaderos ~ base1$estrato,
main = "Parqueaderos vs Estrato",
ylab = "Parqueaderos",
xlab = "Estrato",
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
# Plot empty parqueaderos per banios
parq_banios_box1 <- boxplot(base1$parqueaderos ~ base1$banios,
main = "Parqueaderos vs Banios",
ylab = "Parqueaderos",
xlab = "Banios",
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
# Plot empty parqueaderos per preciom
parq_prec_box1 <- boxplot(base1$parqueaderos ~ base1$class_prec,
main = "Parqueaderos vs Preciom",
ylab = "Parqueaderos",
xlab = NA,
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
# Plot empty parqueaderos per area
parq_area_box1 <- boxplot(base1$parqueaderos ~ base1$class_area,
main = "Parqueaderos vs areaconst",
ylab = "Parqueaderos",
xlab = NA,
las = 2)
abline(h = 2, col = "blue")
text(x = 2, y = 2, labels = "Mediana: 2", col = "blue", pos = 3)
mtext("Distribución de parqueaderos por atributo",
side = 3, outer = TRUE, cex = 1.2, font = 2)
par(mfrow = c(1, 1))
Se observa que para la mayoría de los valores de los atributos, la mediana de los parqueaderos es 2 excepto cuando:
Todos los registros con pisos vacíos que no contengan las condiciones anteriores, se imputaron con un valor de 2.
Luego de esa imputación, quedaron 244 valores vacíos.
Para los registros faltantes, se anotan las medianas que cada atributo tiene para el atributo parqueaderos:
gg_miss_var(base2, show_pct = TRUE) +
labs(title = "Datos Faltantes Apartamentos Zona Sur") +
theme(plot.title = element_text(hjust = 0.5, face = "bold"))
Se observa una gran cantidad de datos faltantes para el atributo piso y parqueaderos, por lo que se determinará la relación con los otros atributos.
par(mfrow = c(2, 3), oma = c(0, 0, 3, 0))
# Plot empty pisos per habitaciones
piso_hab_bar2 <- barplot(piso_hab_base2, names.arg = hab_base2,
main = "Piso = NA por Habitaciones",
ylab = "Registros vacíos",
xlab = "Habitaciones",
las = 2)
# Plot empty pisos per estrato
piso_estr_bar2 <- barplot(piso_estr_base2, names.arg = estr_base2,
main = "Piso = NA por estrato",
ylab = "Registros vacíos",
xlab = "estrato",
las = 2)
# Plot empty pisos per banios
piso_ban_bar2 <- barplot(piso_ban_base2, names.arg = ban_base2,
main = "Piso = NA por banios",
ylab = "Registros vacíos",
xlab = "banios",
las = 2)
# Plot empty pisos per precio
piso_prec_bar2 <- barplot(piso_prec_base2, names.arg = breaks_prec_2,
main = "Piso = NA por precio",
ylab = "Registros vacíos",
xlab = "Precio",
las = 2)
# Plot empty pisos per area
piso_area_bar2 <- barplot(piso_area_base2, names.arg = breaks_area_2,
main = "Piso = NA por area",
ylab = "Registros vacíos",
xlab = "Area",
las = 2)
mtext("Distribución de valores vacíos de piso por atributo",
side = 3, outer = TRUE, cex = 1.2, font = 2)
par(mfrow = c(1, 1))
Se observa que los valores faltantes del atributo piso no se comportan de manera aleatoria respecto a los demás atributos. A continuación, se determina la mediana para cada caso con el fin de establecer con qué valor se imputarán los datos faltantes del atributo piso.
par(mfrow = c(2, 3),
oma = c(0, 0, 3, 0),
xpd = FALSE)
# Plot empty pisos per habitaciones
piso_hab_box2 <- boxplot(base2$piso ~ base2$habitaciones,
main = "Piso vs Habitaciones",
ylab = "Pisos",
xlab = "Habitaciones",
las = 2)
abline(h = 4, col = "blue")
text(x = 2, y = 4, labels = "Mediana: 4", col = "blue", pos = 3)
# Plot empty pisos per estrato
piso_estr_box2 <- boxplot(base2$piso ~ base2$estrato,
main = "Piso vs Estrato",
ylab = "Pisos",
xlab = "Estrato",
las = 2)
abline(h = 4, col = "blue")
text(x = 2, y = 4, labels = "Mediana: 4", col = "blue", pos = 3)
# Plot empty pisos per banios
piso_banios_box2 <- boxplot(base2$piso ~ base2$banios,
main = "Piso vs Banios",
ylab = "Pisos",
xlab = "Banios",
las = 2)
abline(h = 4, col = "blue")
text(x = 2, y = 4, labels = "Mediana: 4", col = "blue", pos = 3)
# Plot empty pisos per preciom
piso_prec_box2 <- boxplot(base2$piso ~ base2$class_prec,
main = "Piso vs Preciom",
ylab = "Pisos",
xlab = NA,
las = 2)
# Plot empty pisos per area
piso_area_box2 <- boxplot(base2$piso ~ base2$class_area,
main = "Piso vs areaconst",
ylab = "Pisos",
xlab = NA,
las = 2)
mtext("Distribución de piso por atributo",
side = 3, outer = TRUE, cex = 1.2, font = 2)
par(mfrow = c(1, 1))
Se observa que para la mayoría de los valores de los atributos, la mediana de los pisos es 4 por lo que se imputarán los faltantes con ese valor.
base2[is.na(base2$piso), "piso"] <- 4
par(mfrow = c(2, 3), oma = c(0, 0, 3, 0))
# Plot empty parqueaderos per habitaciones
parq_hab_bar2 <- barplot(parq_hab_base2, names.arg = hab_base2,
main = "parq = NA por Habitaciones",
ylab = "Registros vacíos",
xlab = "Habitaciones",
las = 2)
# Plot empty parqueaderos per estrato
parq_estr_bar2 <- barplot(parq_estr_base2, names.arg = estr_base2,
main = "parq = NA por estrato",
ylab = "Registros vacíos",
xlab = "estrato",
las = 2)
# Plot empty parqueaderos per banios
parq_ban_bar2 <- barplot(parq_ban_base2, names.arg = ban_base2,
main = "parq = NA por banios",
ylab = "Registros vacíos",
xlab = "banios",
las = 2)
# Plot empty parqueaderos per precio
parq_prec_bar2 <- barplot(parq_prec_base2, names.arg = breaks_prec_2,
main = "parq = NA por precio",
ylab = "Registros vacíos",
xlab = "Precio",
las = 2)
# Plot empty parqueaderos per area
parq_area_bar2 <- barplot(parq_area_base2, names.arg = breaks_area_2,
main = "parq = NA por area",
ylab = "Registros vacíos",
xlab = "Area",
las = 2)
mtext("Distribución de valores vacíos de piso por atributo",
side = 3, outer = TRUE, cex = 1.2, font = 2)
par(mfrow = c(1, 1))
par(mfrow = c(2, 3),
oma = c(0, 0, 3, 0),
xpd = FALSE)
# Plot empty parqueaderos per habitaciones
parq_hab_box2 <- boxplot(base2$parqueaderos ~ base2$habitaciones,
main = "parq vs Habitaciones",
ylab = "parqs",
xlab = "Habitaciones",
las = 2)
abline(h = 1, col = "blue")
text(x = 2, y = 1, labels = "Mediana: 1", col = "blue", pos = 3)
# Plot empty parqueaderos per estrato
parq_estr_box2 <- boxplot(base2$parqueaderos ~ base2$estrato,
main = "parq vs Estrato",
ylab = "parqs",
xlab = "Estrato",
las = 2)
abline(h = 1, col = "blue")
text(x = 2, y = 1, labels = "Mediana: 1", col = "blue", pos = 3)
# Plot empty parqueaderos per banios
parq_banios_box2 <- boxplot(base2$parqueaderos ~ base2$banios,
main = "parq vs Banios",
ylab = "parqs",
xlab = "Banios",
las = 2)
abline(h = 1, col = "blue")
text(x = 2, y = 1, labels = "Mediana: 1", col = "blue", pos = 3)
# Plot empty parqueaderos per preciom
parq_prec_box2 <- boxplot(base2$parqueaderos ~ base2$class_prec,
main = "parq vs Preciom",
ylab = "parqs",
xlab = NA,
las = 2)
# Plot empty parqueaderos per area
parq_area_box2 <- boxplot(base2$parqueaderos ~ base2$class_area,
main = "parq vs areaconst",
ylab = "parqs",
xlab = NA,
las = 2)
mtext("Distribución de piso por atributo",
side = 3, outer = TRUE, cex = 1.2, font = 2)
par(mfrow = c(1, 1))
Se imputan los datos de parqueo con la mediana 1.
base1 <- read.csv("base1_imputed.csv")
base2 <- read.csv("base2_imputed.csv")
par(mfrow = c(1, 2), oma = c(0, 0, 1, 0), mar = c(7, 2, 1, 2))
k <- 2.4
box_base1 <- boxplot(base1[, c(3:4, 7:9)], range = k, las = 2)
for (j in seq(1, ncol(box_base1$stats))) {
for (i in seq(1, nrow(box_base1$stats))) {
text(x = j, y = box_base1$stats[i, j],
labels = box_base1$stats[i, j],
pos = 4, col = "blue")
}
}
box2_base1 <- boxplot(base1[, c(5, 6)], range = k, las = 2)
for (j in seq(1, ncol(box2_base1$stats))) {
for (i in seq(1, nrow(box2_base1$stats))) {
text(x = j, y = box2_base1$stats[i, j],
labels = box2_base1$stats[i, j],
pos = 4, col = "blue")
}
}
mtext("Datos atípicos Base1", side = 3, outer = TRUE, font = 2)
par(mfrow = c(1,1))
Se considerarán datos erróneos aquellos inmuebles cuyo número de habitaciones o baños sea 0. Para el resto de atributos, se considerarán datos atípicos los mostrados por el diagrama de cajas y bigotes excepto para el atributo piso ya que los outliers mostrados no se considerarán datos erróneos, pues es posible que haya casa diferentes a 2 pisos.
La base de datos limpia corresponde a un 83% de la base original
par(mfrow = c(1, 2), oma = c(0, 0, 1, 0), mar = c(7, 2, 1, 2))
k <- 2.4
box_base2 <- boxplot(base2[, c(3:4, 7:9)], range = 2.4, las = 2)
for (j in seq(1, ncol(box_base2$stats))) {
for (i in seq(1, nrow(box_base2$stats))) {
text(x = j, y = box_base2$stats[i, j],
labels = box_base2$stats[i, j],
pos = 4, col = "blue")
}
}
box2_base2 <- boxplot(base2[, c(5, 6)], range = 2.4, las = 2)
for (j in seq(1, ncol(box2_base2$stats))) {
for (i in seq(1, nrow(box2_base2$stats))) {
text(x = j, y = box2_base2$stats[i, j],
labels = box2_base2$stats[i, j],
pos = 4, col = "blue")
}
}
mtext("Datos atípicos Base2", side = 3, outer = TRUE, font = 2)
par(mfrow = c(1,1))
Se considerarán datos erróneos aquellos inmuebles cuyo número de habitaciones o baños sea 0. Para el resto de atributos, se considerarán datos atípicos los mostrados por el diagrama de cajas y bigotes excepto para el atributo piso y habitaciones, ya que los outliers mostrados no se considerarán datos erróneos, pues es posible que haya apartamentos en diferentes 2 pisos con hasta 6 habitaciones.
La base de datos limpia corresponde a un 86% de la base original
En las siguientes figuras se observa la relación entre los atributos numéricos.
ggpairs(base1[, c("areaconst", "preciom")], title = "Correlación Base1")
Como era de esperarse, se observa una correlación positiva entre el área construida y el precio del inmueble, sin embargo, no explica de manera suficiente la variable de respuesta, por lo que será necesario considerar más atributos a la hora de predecir. En la siguiente imágen se observa la relación con el resto de atributos.
par(mfrow = c(3, 2), oma = c(0, 0, 2, 0), mar = c(4, 3, 1, 1))
k <- 2.4
piso_base1 <- boxplot(base1$preciom ~ base1$piso,
range = 2.4,
ylab = NA,
xlab = "Pisos",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(piso_base1$stats))) {
text(x = j, y = piso_base1$stats[3, j],
labels = piso_base1$stats[3, j],
pos = 3, col = "blue")
}
estrato_base1 <- boxplot(base1$preciom ~ base1$estrato,
range = 2.4,
ylab = NA,
xlab = "Estrato",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(estrato_base1$stats))) {
text(x = j, y = estrato_base1$stats[3, j],
labels = estrato_base1$stats[3, j],
pos = 3, col = "blue")
}
parqueaderos_base1 <- boxplot(base1$preciom ~ base1$parqueaderos,
range = 2.4,
ylab = NA,
xlab = "Parqueaderos",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(parqueaderos_base1$stats))) {
text(x = j, y = parqueaderos_base1$stats[3, j],
labels = parqueaderos_base1$stats[3, j],
pos = 3, col = "blue")
}
banios_base1 <- boxplot(base1$preciom ~ base1$banios,
range = 2.4,
ylab = NA,
xlab = "Banios",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(banios_base1$stats))) {
text(x = j, y = banios_base1$stats[3, j],
labels = banios_base1$stats[3, j],
pos = 3, col = "blue")
}
habitaciones_base1 <- boxplot(base1$preciom ~ base1$habitaciones,
range = 2.4,
ylab = NA,
xlab = "Habitaciones",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(habitaciones_base1$stats))) {
text(x = j, y = habitaciones_base1$stats[3, j],
labels = habitaciones_base1$stats[3, j],
pos = 3, col = "blue")
}
mtext("Comportamiento del Preciom vs Atributos", side = 3, outer = TRUE, font = 2)
par(mfrow = c(1,1))
Se observan relaciones interesentes en cuanto al precio del inmueble respecto a los demás atributos dentro de las cuales se listan:
# Get Coordinates from variables
var_coords <- as.data.frame(mca_result$var$coord)
var_coords["Variable"] <- ifelse(startsWith(rownames(var_coords), "piso"),
"piso",
ifelse(startsWith(rownames(var_coords), "estrato"),
"estrato",
ifelse(startsWith(rownames(var_coords), "parqueaderos"),
"parqueadero",
ifelse(startsWith(rownames(var_coords), "banios"),
"banios",
ifelse(startsWith(rownames(var_coords), "habitaciones"),
"habitaciones",
"precio")))))
names(var_coords) <- c("Dim1", "Dim2", "Dim3", "Dim4", "Dim5", "Variable")
for (i in seq(35, 42)) {
var_coords[i, "Variable"] <- "area"
}
# Create Graph
g <- ggplot(var_coords, aes(x = Dim1, y = Dim2,
color = Variable,
shape = Variable,
label = rownames(var_coords))) +
geom_point() +
geom_text(vjust = -0.5) +
labs(title = "Análisis de Correspondencia Múltiple (MCA)",
x = paste("Dimensión1(", round(mca_result$eig[1, 2], 2), "%)", sep = ""),
y = paste("Dimensión2(", round(mca_result$eig[2, 2], 2), "%)", sep = "")) +
ylim(-0.5, 2.5) +
xlim(-2, 1.5) +
theme_minimal()
ggplotly(g)
Interpretando los atributos estrato, parqueadero y discretizando los atributos precio y área, se realizó un análisis de correspondencia múltiple que deja las siguientes observaciones para las casas de la Zona Norte:
ggpairs(base2[, c("areaconst", "preciom")], title = "Correlación Base2")
La correlación preciom/area de los apartamentos de la Zona Sur es similar respecto a las casas de la Zona Norte.
par(mfrow = c(3, 2), oma = c(0, 0, 2, 0), mar = c(4, 3, 1, 1))
k <- 2.4
piso_base2 <- boxplot(base2$preciom ~ base2$piso,
range = 2.4,
ylab = NA,
xlab = "Pisos",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(piso_base2$stats))) {
text(x = j, y = piso_base2$stats[3, j],
labels = piso_base2$stats[3, j],
pos = 3, col = "blue")
}
estrato_base2 <- boxplot(base2$preciom ~ base2$estrato,
range = 2.4,
ylab = NA,
xlab = "Estrato",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(estrato_base2$stats))) {
text(x = j, y = estrato_base2$stats[3, j],
labels = estrato_base2$stats[3, j],
pos = 3, col = "blue")
}
parqueaderos_base2 <- boxplot(base2$preciom ~ base2$parqueaderos,
range = 2.4,
ylab = NA,
xlab = "Parqueaderos",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(parqueaderos_base2$stats))) {
text(x = j, y = parqueaderos_base2$stats[3, j],
labels = parqueaderos_base2$stats[3, j],
pos = 3, col = "blue")
}
banios_base2 <- boxplot(base2$preciom ~ base2$banios,
range = 2.4,
ylab = NA,
xlab = "Banios",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(banios_base2$stats))) {
text(x = j, y = banios_base2$stats[3, j],
labels = banios_base2$stats[3, j],
pos = 3, col = "blue")
}
habitaciones_base2 <- boxplot(base2$preciom ~ base2$habitaciones,
range = 2.4,
ylab = NA,
xlab = "Habitaciones",
notch = TRUE,
las = 2)
for (j in seq(1, ncol(habitaciones_base2$stats))) {
text(x = j, y = habitaciones_base2$stats[3, j],
labels = habitaciones_base2$stats[3, j],
pos = 3, col = "blue")
}
mtext("Comportamiento del Preciom vs Atributos", side = 3, outer = TRUE, font = 2)
par(mfrow = c(1,1))
Se observan relaciones interesentes en cuanto al precio del inmueble respecto a los demás atributos dentro de las cuales se listan:
# Get Coordinates from variables
var_coords <- as.data.frame(mca_result$var$coord)
var_coords["Variable"] <- ifelse(startsWith(rownames(var_coords), "piso"),
"piso",
ifelse(startsWith(rownames(var_coords), "estrato"),
"estrato",
ifelse(startsWith(rownames(var_coords), "parqueaderos"),
"parqueadero",
ifelse(startsWith(rownames(var_coords), "banios"),
"banios",
ifelse(startsWith(rownames(var_coords), "habitaciones"),
"habitaciones",
"precio")))))
names(var_coords) <- c("Dim1", "Dim2", "Dim3", "Dim4", "Dim5", "Variable")
for (i in seq(35, 42)) {
var_coords[i, "Variable"] <- "area"
}
# Create Graph
g <- ggplot(var_coords, aes(x = Dim1, y = Dim2,
color = Variable,
shape = Variable,
label = rownames(var_coords))) +
geom_point() +
geom_text(vjust = -0.5) +
labs(title = "Análisis de Correspondencia Múltiple (MCA)",
x = paste("Dimensión1(", round(mca_result$eig[1, 2], 2), "%)", sep = ""),
y = paste("Dimensión2(", round(mca_result$eig[2, 2], 2), "%)", sep = "")) +
theme_minimal()
ggplotly(g)
Interpretando los atributos estrato, parqueadero y discretizando los atributos precio y área, se realizó un análisis de correspondencia múltiple que deja las siguientes observaciones para los apartamentos de la Zona Sur:
Se realizará un modelo considerando los atributos area, estrato, habitaciones, parqueaderos y baños. Inicialmente se dividirá la base de datos en una proporción 70-30 donde el 70% se utilizará para entrenamiento, mientras que el 30% se utilizará para prueba.
set.seed(123)
train_index <- sample(c(TRUE, FALSE),
nrow(base1),
replace = TRUE,
prob = c(0.70, 0.30))
train_base1 <- base1[train_index, ]
test_base1 <- base1[!train_index, ]
mod_base1 <- lm(preciom ~ areaconst
+ estrato
+ habitaciones
+ parqueaderos
+ banios,
data = train_base1)
summary(mod_base1)
Call:
lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
banios, data = train_base1)
Residuals:
Min 1Q Median 3Q Max
-294.53 -60.91 -13.25 45.83 581.54
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -179.30451 28.29196 -6.338 6.02e-10 ***
areaconst 0.73589 0.05617 13.102 < 2e-16 ***
estrato 80.05815 6.93742 11.540 < 2e-16 ***
habitaciones -1.51347 4.52327 -0.335 0.7381
parqueaderos 13.70358 7.48954 1.830 0.0680 .
banios 15.80003 6.52812 2.420 0.0159 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 106.7 on 420 degrees of freedom
Multiple R-squared: 0.6974, Adjusted R-squared: 0.6938
F-statistic: 193.6 on 5 and 420 DF, p-value: < 2.2e-16
Se observa un error en la variable de respuesta considerablemente alto entre -294.53 y 581.54 con una media de -13.25. Respecto a los coeficientes se observa que en su mayoría son significativos a excepción del número de habitaciones, mientras que el número de parqueaderos es el menos significativo dentro de los significativos. Con un intercepto negativo, el resto de parámetros aumentarán el precio del inmueble.
El coeficiente de determinación muestra que el modelo explica la variable de respuesta en un 70%, de igual manera, se observa que el modelo es significativo considerando el p-value de la prueba F.
plot(mod_base1$residuals, train_base1$preciom,
main = "Preciom vs Valores Ajustados")
par(mfrow = c(2, 2), oma = c(0.5,0.5,4,0.5), mar = c(2,2,2,2))
plot(mod_base1)
par(mfrow = c(1, 1))
# Normality
shapiro.test(mod_base1$residuals)
Shapiro-Wilk normality test
data: mod_base1$residuals
W = 0.89861, p-value = 3.259e-16
# Constant variance
bptest(mod_base1)
studentized Breusch-Pagan test
data: mod_base1
BP = 41.883, df = 5, p-value = 6.22e-08
# Residuals independence
dwtest(mod_base1)
Durbin-Watson test
data: mod_base1
DW = 1.4292, p-value = 1.295e-09
alternative hypothesis: true autocorrelation is greater than 0
Al validar el supuesto de los modelos, se observa que no se cumple con la normalidad de los residuos mostrados en la gráfica qq residuals y corroborado con la prueba de hipótesis de shapiro-wilks; el criterio de homocedasticidad tampoco se cumple, pues al observar la varianza de los residuos en el gráfico Residuals vs Fitted, a medida que los valores ajustados son mayores, la varianza va aumentando, no se observan los residuos simétricos a la línea del 0, esto se corrobora con la prueba de Durbin-Whatson; finalmente, se observa en la gráfica de Preciom vs valores ajustados, que la calidad del modelo no es buena.
options(digits = 2, scipen = 999)
table_predictions1 <- data.frame(rbind(R2, MSE, df, RSE))
names(table_predictions1) <- "Value"
formattable(table_predictions1)
Value | |
---|---|
R2 | 0.68 |
MSE | 14607.44 |
df | 170.00 |
RSE | 120.86 |
Al evaluar la calidad de las predicciones, se observa que el coeficiente R^2 se mantiene, con 170 grados de libertad, se obtiene un error estándar residual de 120.86, aumentando un poco respecto al modelo de entrenamiento.
results1
Estrato 4 Estrato 5
Preciom 327 407
Como se observa en las predicciones, sería conveniente que la empresa comprara una casa con las características referenciadas en un barrio de estrato 4 en la Zona Norte, pues las viviendas tendrán un valor estimado de $327 millones, monto que se ajusta al crédito preaprobado; por el contrario, en el estrato 5, el valor estimado estaría por encima del crédito. Ofertas que pueden ajustarse, se encuentran en el siguiente mapa.
offers1 <- subset(base1[order(base1$latitud), ],
preciom < 350
& class_area == "200-300"
& parqueaderos == 1
& banios >= 2
& habitaciones >= 4
& estrato >= 4)
leaflet(c(offers1$latitud, offers1$longitud)) %>%
addTiles() %>%
addMarkers(lng = offers1$longitud, lat = offers1$latitud,
popup = paste("Precio:", offers1$preciom,
" Estrato:", offers1$estrato,
" Area:", offers1$areaconst,
" Hab:", offers1$habitaciones,
" Ban:", offers1$habitaciones,
" Parq:", offers1$parqueadero,
sep = ""))
set.seed(123)
train_index <- sample(c(TRUE, FALSE),
nrow(base2),
replace = TRUE,
prob = c(0.70, 0.30))
train_base2 <- base2[train_index, ]
test_base2 <- base2[!train_index, ]
mod_base2 <- lm(preciom ~ areaconst
+ estrato
+ habitaciones
+ parqueaderos
+ banios,
data = train_base2)
summary(mod_base2)
Call:
lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
banios, data = train_base2)
Residuals:
Min 1Q Median 3Q Max
-194.89 -27.20 -1.42 27.74 293.84
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -146.8409 9.4173 -15.59 < 0.0000000000000002 ***
areaconst 2.1348 0.0737 28.96 < 0.0000000000000002 ***
estrato 42.3806 1.9712 21.50 < 0.0000000000000002 ***
habitaciones -11.8296 2.5642 -4.61 0.0000043 ***
parqueaderos 32.5082 3.5775 9.09 < 0.0000000000000002 ***
banios 7.8156 2.9099 2.69 0.0073 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 50 on 1674 degrees of freedom
Multiple R-squared: 0.742, Adjusted R-squared: 0.741
F-statistic: 962 on 5 and 1674 DF, p-value: <0.0000000000000002
Se observa un error en la variable de respuesta considerablemente alto entre -194.89 y 293.84 con una media de -1.42. Respecto a los coeficientes se observa que todos son significativos. Con un intercepto negativo, el resto de parámetros aumentarán el precio del inmueble a excepción de las habitaciones.
El coeficiente de determinación muestra que el modelo explica la variable de respuesta en un 74%, de igual manera, se observa que el modelo es significativo considerando el p-value de la prueba F.
plot(mod_base2$residuals, train_base2$preciom,
main = "Preciom vs Valores Ajustados")
par(mfrow = c(2, 2), oma = c(0.5,0.5,4,0.5), mar = c(2,2,2,2))
plot(mod_base2)
par(mfrow = c(1, 1))
# Normality
shapiro.test(mod_base2$residuals)
Shapiro-Wilk normality test
data: mod_base2$residuals
W = 1, p-value <0.0000000000000002
# Constant variance
bptest(mod_base2)
studentized Breusch-Pagan test
data: mod_base2
BP = 348, df = 5, p-value <0.0000000000000002
# Residuals independence
dwtest(mod_base2)
Durbin-Watson test
data: mod_base2
DW = 2, p-value <0.0000000000000002
alternative hypothesis: true autocorrelation is greater than 0
Al validar el supuesto de los modelos, se observa que no se cumple con la normalidad de los residuos mostrados en la gráfica qq residuals y corroborado con la prueba de hipótesis de shapiro-wilks; el criterio de homocedasticidad tampoco se cumple, pues al observar la varianza de los residuos en el gráfico Residuals vs Fitted, a medida que los valores ajustados son mayores, la varianza va aumentando, no se observan los residuos simétricos a la línea del 0, esto se corrobora con la prueba de Durbin-Whatson; finalmente, se observa en la gráfica de Preciom vs valores ajustados, que la calidad del modelo no es buena.
options(digits = 2, scipen = 999)
table_predictions2 <- data.frame(rbind(R2, MSE, df, RSE))
names(table_predictions2) <- "Value"
formattable(table_predictions2)
Value | |
---|---|
R2 | 0.76 |
MSE | 2506.77 |
df | 700.00 |
RSE | 50.07 |
Al evaluar la calidad de las predicciones, se observa que el coeficiente R^2 aumenta un 2%, con 700 grados de libertad, se obtiene un error estándar residual de 50.07, manteniendose respecto al modelo de entrenamiento.
results2
Estrato 5 Estrato 6
Preciom 725 756
Como se observa en las predicciones, la empresa podria adquirir el inmueble con las características deseadas en estrato 5 y 6, sin embargo, no hay apartamentos disponibles con 300 metros cuadrados ni de 5 habitaciones. Ofertas que pueden ajustarse, se encuentran en el siguiente mapa.
offers2 <- subset(base2[order(base2$latitud), ],
preciom < 850
& parqueaderos >= 3
& banios >= 3
& estrato >= 5)
offers2 <- head(offers2)
leaflet(c(offers2$latitud, offers2$longitud)) %>%
addTiles() %>%
addMarkers(lng = offers2$longitud, lat = offers2$latitud,
popup = paste("Precio:", offers2$preciom,
" Estrato:", offers2$estrato,
" Area:", offers2$areaconst,
" Hab:", offers2$habitaciones,
" Ban:", offers2$habitaciones,
" Parq:", offers2$parqueadero,
sep = ""))