Contexto

María recibió una carta solicitando asesoría para la compra de dos viviendas por parte de una compañía internacional que desea ubicar a dos de sus empleados con sus familias en la ciudad. Las solicitudes incluyen las siguientes condiciones: María recibió una carta solicitando asesoría para la compra de dos viviendas por parte de una compañía internacional que desea ubicar a dos de sus empleados con sus familias en la ciudad. Las solicitudes incluyen las siguientes condiciones:

Características Vivienda 1 Vivienda 2
Tipo Casa Apartamento
Área construida 200 300
Parqueaderos 1 3
Baños 2 3
Habitaciones 4 5
Estrato 4 o 5 5 o 6
Zona Norte Sur
Crédito preaprobado 350 millones 850 millones

Ayude a María a responder la solicitud mediante técnicas de modelación que usted conoce. Ella requiere que se le envíe un informe ejecutivo en el que se analicen los dos casos y se presenten las recomendaciones correspondientes (Informe). Como soporte del informe, se deben anexar las estimaciones, validaciones y comparación de modelos requeridos (Anexos).

library(devtools)
library(mice)
library(tidyverse)
library(factoextra)
library(cluster)
library(dplyr)
library(FactoMineR)
library(gridExtra)
library(tcltk2)
devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
## 
## ── R CMD build ─────────────────────────────────────────────────────────────────
##      During startup - Warning messages:
##    1: Setting LC_TIME failed, using "C" 
##    2: Setting LC_MESSAGES failed, using "C" 
##    3: Setting LC_MONETARY failed, using "C" 
##      checking for file ‘/private/var/folders/f7/fh96nvx97hz525c07nbtj01r0000gn/T/RtmpR04dYJ/remotes16cb71a509bb/Centromagis-paqueteMODELOS-3b06257/DESCRIPTION’ ...  ✔  checking for file ‘/private/var/folders/f7/fh96nvx97hz525c07nbtj01r0000gn/T/RtmpR04dYJ/remotes16cb71a509bb/Centromagis-paqueteMODELOS-3b06257/DESCRIPTION’
##   ─  preparing ‘paqueteMODELOS’:
##    checking DESCRIPTION meta-information ...  ✔  checking DESCRIPTION meta-information
##   ─  checking for LF line-endings in source and make files and shell scripts
##   ─  checking for empty or unneeded directories
##   ─  building ‘paqueteMODELOS_0.1.0.tar.gz’
##      
## 
library(paqueteMODELOS)
library(psych)
library(ggplot2)
library(patchwork)
library(VIM)
library(leaflet)
library(corrplot)
library (plotly)
library(lmtest)
data("vivienda")

Analisis primera solicitud

Extracion de datos relevantes para la solicitud

#Filtro por interes de la primera solicitud
base1 <- vivienda %>%
  filter(tipo == "Casa", zona == "Zona Norte")

# Primeros 3 registros
head(base1, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1209 Zona N… 02          5     320       150            2      4            6
## 2  1592 Zona N… 02          5     780       380            2      3            3
## 3  4057 Zona N… 02          6     750       445           NA      7            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Comprobacion
table(vivienda$tipo, vivienda$zona)
##              
##               Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
##   Apartamento          24       1198       1029           62     2787
##   Casa                100        722        169          289     1939
table(base1$tipo)
## 
## Casa 
##  722
table(base1$zona)
## 
## Zona Norte 
##        722

Mapeo de registros

# Crea un mapa
map <- leaflet(base1) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~as.character(latitud)
  )

map 

El mapa permite visualizar la distribución geográfica de las casas clasificadas en la zona norte. Sin embargo, se observa que algunos puntos aparecen fuera del límite geográfico esperado. Esto puede deberse a que la variable zona corresponde a una clasificación comercial utilizada por el mercado inmobiliario y no necesariamente a una delimitación geográfica estricta.

Analisis de correlacion

Var_cor <- data.frame(base1$preciom, base1$areaconst, base1$estrato, base1$banios, base1$habitaciones, base1$latitud, base1$longitud)

cor_matrix <- cor(Var_cor, use = "complete.obs")

plot_ly(
  x = colnames(cor_matrix),
  y = rownames(cor_matrix),
  z = cor_matrix,
  type = "heatmap",
  colorscale = "RdBu"
)

El precio de la casa en zona norte se relaciona fuerte y positivamente con el area construida, estrato y numero de baños. El numero de habitaciones se relacion debilmente con el precio de la vivienda. La latitud presena una relacion muy debil con el precio y la longitud una relacion debil con el precio.

Modelo de regresio lineal multiple

modelo_1 <- lm(preciom ~ areaconst + estrato + banios, data=base1)
summary(modelo_1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios, data = base1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -958.78  -79.28  -18.28   49.58 1075.72 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -230.09209   26.57191  -8.659  < 2e-16 ***
## areaconst      0.82806    0.04234  19.556  < 2e-16 ***
## estrato       85.26855    6.99365  12.192  < 2e-16 ***
## banios        27.66782    4.52501   6.114 1.59e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 158.9 on 718 degrees of freedom
## Multiple R-squared:  0.6507, Adjusted R-squared:  0.6492 
## F-statistic: 445.8 on 3 and 718 DF,  p-value: < 2.2e-16

El valor base del modelo cuando las demás variables son cero es de -139.34 millones. Por cada metro cuadrado adicional de área construida, el precio de la vivienda aumenta en promedio 0.92 millones de pesos, manteniendo constantes las demás variables. Un aumento de una unidad en el estrato socioeconómico incrementa el precio de la vivienda en promedio 57.1 millones de pesos, manteniendo constantes las demás variables. Por cada baño adicional incrementa el precio de la vivienda en aproximadamente 23.2 millones de pesos. Todos los coeficientes presentan valores p menores a 0.001, indicando que son estadísticamente significativos. El coeficiente de determinacion de 0.7028, es decir, el 70.28 % de la variabilidad del precio de las viviendas puede ser explicada por las variables incluidas en el modelo (área construida, estrato y número de baños). Este valor indica que el modelo tiene un buen nivel de ajuste, aunque todavía existe cerca del 30% de la variabilidad del precio que no está siendo explicada por el modelo. El modelo explica el 70% de la variabilidad del precio de a vivienda cuando se ajusta por el número de predictores incluidos.

Prediccion usando set de prueba

set.seed(2024)

train_index <- sample(1:nrow(base1), 0.8*nrow(base1))

train <- base1[train_index, ]
test <- base1[-train_index, ]

modelo1 <- lm(preciom ~ areaconst + estrato + banios, data = train)

pred <- predict(modelo1, newdata = test)
RMSE <- sqrt(mean((test$preciom - pred)^2))
MAE <- mean(abs(test$preciom - pred))

RMSE
## [1] 125.3125
MAE
## [1] 91.70191

El modelo tiene un error proedio aproximado de 125,31 millones de pesos en la prediccion del precio de la vivienda. Adicionalmente, las predicciones del modelo difieren del valor real en aproximadamente 91,70 millones.

Validacion de supuestos

residuos <- residuals(modelo_1)
MSE <- summary(modelo_1)$sigma^2

residuales_estandarizados <- residuos / sqrt(MSE)

Normalidad

shapiro.test(residuales_estandarizados)
## 
##  Shapiro-Wilk normality test
## 
## data:  residuales_estandarizados
## W = 0.83689, p-value < 2.2e-16

Los residuales del modelo no cumplen con el supuesto de normalidad. Homocedasticidad

gqtest(modelo_1)
## 
##  Goldfeld-Quandt test
## 
## data:  modelo_1
## GQ = 1.1287, df1 = 357, df2 = 357, p-value = 0.1265
## alternative hypothesis: variance increases from segment 1 to 2

En los residuales del modelo existe homocedasticidad, es decir, se cumple con el supuesto de homogeneidad de varianzas.

Independencia

dwtest(modelo_1)
## 
##  Durbin-Watson test
## 
## data:  modelo_1
## DW = 1.6297, p-value = 2.65e-07
## alternative hypothesis: true autocorrelation is greater than 0

Existe autocorrelacion positiva entre los residuos del modelo.

Los supuestos del modelo de regresión no se cumplen, las inferencias estadísticas pueden ser incorrectas. Es decir, los coeficientes pueden estimarse, pero las pruebas, intervalos de confianza y predicciones pueden ser poco confiables.

Prediccion

nueva_viv1 <- data.frame(
  areaconst = 200,
  estrato = 4.5,
  habitaciones = 4,
  parqueaderos = 1,
  banios = 2
)

predict(modelo_1, newdata = nueva_viv1, interval = "prediction")
##        fit      lwr      upr
## 1 374.5631 61.93098 687.1952

El valor predicho por el modelo es de 348 millones con precio minimo de 164 millones y maximo 532 millones.

Ofertas sugeridas

ofertas_v1 <- base1 %>%
  filter(
    estrato %in% c("4", "5"),
    habitaciones >= 4,
    banios >= 2,
    parqueaderos >= 1,
    preciom <= 350,
    areaconst >=200)
ofertas_v1
## # A tibble: 34 × 13
##       id zona   piso  estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  4210 Zona … 01          5     350       200            3      3            4
##  2  4267 Zona … 01          5     335       202            1      4            5
##  3  4800 Zona … 01          5     340       250            2      4            4
##  4  4209 Zona … 02          5     350       300            3      5            6
##  5  4422 Zona … 02          5     350       240            2      3            6
##  6  4458 Zona … 02          4     315       270            2      4            4
##  7  4483 Zona … 02          5     342       250            1      4            6
##  8  1009 Zona … <NA>        5     250       243            1      4            5
##  9  1270 Zona … <NA>        5     350       203            2      2            5
## 10  3352 Zona … <NA>        4     335       300            3      4            4
## # ℹ 24 more rows
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Mapeo de registros que cumplen los requisitos

# Crea un mapa
map <- leaflet(ofertas_v1) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~as.character(latitud)
  )

map 

De un total de 2566 casas en la zona norte, se obtienen 28 opciones de inmuebles que cumplen con los requisitos del cliente.

Analisis segunda solicitud

Extracion de datos relevantes para la solicitud

#Filtro por interes de la primera solicitud
base2 <- vivienda %>%
  filter(tipo == "Apartamento", zona == "Zona Sur")

# Primeros 3 registros
head(base1, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1209 Zona N… 02          5     320       150            2      4            6
## 2  1592 Zona N… 02          5     780       380            2      3            3
## 3  4057 Zona N… 02          6     750       445           NA      7            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Comprobacion
table(vivienda$tipo, vivienda$zona)
##              
##               Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
##   Apartamento          24       1198       1029           62     2787
##   Casa                100        722        169          289     1939
table(base1$tipo)
## 
## Casa 
##  722
table(base1$zona)
## 
## Zona Norte 
##        722

Mapeo de registros

# Crea un mapa
map <- leaflet(base2) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~as.character(latitud)
  )

map 

El mapa permite visualizar la distribución geográfica de las casas clasificadas en la zona norte. Sin embargo, se observa que algunos puntos aparecen fuera del límite geográfico esperado. Esto puede deberse a que la variable zona corresponde a una clasificación comercial utilizada por el mercado inmobiliario y no necesariamente a una delimitación geográfica estricta.

Analisis de correlacion

Var_cor <- data.frame(base2$preciom, base2$areaconst, base2$estrato, base2$banios, base2$habitaciones, base2$latitud, base2$longitud)

cor_matrix <- cor(Var_cor, use = "complete.obs")

plot_ly(
  x = colnames(cor_matrix),
  y = rownames(cor_matrix),
  z = cor_matrix,
  type = "heatmap",
  colorscale = "RdBu"
)

El precio del apartamento en zona sur se relaciona fuerte y positivamente con el area construida, estrato y numero de baños. El numero de habitaciones se relacion debilmente con el precio de la vivienda. La latitud presena una relacion muy debil con el precio y la longitud una relacion debil con el precio.

Modelo de regresio lineal multiple

modelo_2 <- lm(preciom ~ areaconst + estrato + banios, data=base2)
summary(modelo_2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios, data = base2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1392.66   -40.28    -4.91    38.08   967.21 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -322.37292   10.74722  -30.00   <2e-16 ***
## areaconst      1.60767    0.04888   32.89   <2e-16 ***
## estrato       72.96656    2.78093   26.24   <2e-16 ***
## banios        50.28422    2.93000   17.16   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 100.2 on 2783 degrees of freedom
## Multiple R-squared:  0.7267, Adjusted R-squared:  0.7264 
## F-statistic:  2467 on 3 and 2783 DF,  p-value: < 2.2e-16

El valor base del modelo cuando las demás variables son cero es de -286.05 millones. Por cada metro cuadrado adicional de área construida, el precio de la vivienda aumenta en promedio 1.90 millones de pesos, manteniendo constantes las demás variables. Un aumento de una unidad en el estrato socioeconómico incrementa el precio de la vivienda en promedio 66.77 millones de pesos, manteniendo constantes las demás variables. Por cada baño adicional incrementa el precio de la vivienda en aproximadamente 33.95 millones de pesos. Todos los coeficientes presentan valores p menores a 0.001, indicando que son estadísticamente significativos. El coeficiente de determinacion de 0.7714, es decir, el 77,14 % de la variabilidad del precio de las viviendas puede ser explicada por las variables incluidas en el modelo (área construida, estrato y número de baños). Este valor indica que el modelo tiene un buen nivel de ajuste, aunque todavía existe cerca del 23% de la variabilidad del precio que no está siendo explicada por el modelo. El modelo explica el 77% de la variabilidad del precio de la vivienda cuando se ajusta por el número de predictores incluidos.

Prediccion usando set de prueba

set.seed(2024)

train_index <- sample(1:nrow(base2), 0.8*nrow(base2))

train <- base2[train_index, ]
test <- base2[-train_index, ]

modelo2 <- lm(preciom ~ areaconst + estrato + banios, data = train)

pred <- predict(modelo2, newdata = test)
RMSE <- sqrt(mean((test$preciom - pred)^2))
MAE <- mean(abs(test$preciom - pred))

RMSE
## [1] 129.7196
MAE
## [1] 59.63868

El modelo tiene un error proedio aproximado de 129 millones de pesos en la prediccion del precio de la vivienda. Adicionalmente, las predicciones del modelo difieren del valor real en aproximadamente 59 millones.

Validacion de supuestos

residuos <- residuals(modelo_2)
MSE <- summary(modelo_2)$sigma^2

residuales_estandarizados <- residuos / sqrt(MSE)

Normalidad

shapiro.test(residuales_estandarizados)
## 
##  Shapiro-Wilk normality test
## 
## data:  residuales_estandarizados
## W = 0.77598, p-value < 2.2e-16

Los residuales del modelo no cumplen con el supuesto de normalidad. Homocedasticidad

gqtest(modelo_2)
## 
##  Goldfeld-Quandt test
## 
## data:  modelo_2
## GQ = 0.91786, df1 = 1390, df2 = 1389, p-value = 0.9449
## alternative hypothesis: variance increases from segment 1 to 2

En los residuales del modelo existe homocedasticidad, es decir, se cumple con el supuesto de homogeneidad de varianzas.

Independencia

dwtest(modelo_2)
## 
##  Durbin-Watson test
## 
## data:  modelo_2
## DW = 1.4924, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0

Existe autocorrelacion positiva entre los residuos del modelo.

Los supuestos del modelo de regresión no se cumplen, las inferencias estadísticas pueden ser incorrectas. Es decir, los coeficientes pueden estimarse, pero las pruebas, intervalos de confianza y predicciones pueden ser poco confiables.

Prediccion

nueva_viv2 <- data.frame(
  areaconst = 300,
  estrato = 5.5,
  habitaciones = 5,
  parqueaderos = 3,
  banios = 3
)

predict(modelo_2, newdata = nueva_viv2, interval = "prediction")
##        fit      lwr      upr
## 1 712.0976 514.8402 909.3551

El valor predicho por el modelo es de 754 millones con precio minimo de 606 millones y maximo 902 millones.

Ofertas sugeridas

ofertas_v2 <- base2 %>%
  filter(
    estrato %in% c(5,6),
    habitaciones >= 5,
    banios >= 3,
    parqueaderos >= 3,
    preciom <= 850,
    areaconst >=300)
ofertas_v2
## # A tibble: 2 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  7182 Zona S… <NA>        5     730       573            3      8            5
## 2  7512 Zona S… <NA>        5     670       300            3      5            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Para la solicitud exacta recibida no hay ofertas que cumplan los requisitos, se sigiere flexibilizar el area construida.

ofertas_v2 <- base2 %>%
  filter(
    estrato %in% c(5,6),
    habitaciones >= 5,
    banios >= 3,
    parqueaderos >= 3,
    preciom <= 850,
    areaconst >=200)
ofertas_v2
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  7182 Zona S… <NA>        5     730       573            3      8            5
## 2  7512 Zona S… <NA>        5     670       300            3      5            6
## 3  8036 Zona S… <NA>        5     530       256            3      5            5
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Mapeo de registros que cumplen los requisitos

# Crea un mapa
map <- leaflet(ofertas_v2) %>%
  addTiles() %>%
  addMarkers(
    lng = ~longitud,
    lat = ~latitud,
    popup = ~as.character(latitud)
  )

map 

De un total de 2566 apartamentos en la zona Sur, se obtienen 3 opciones de inmuebles que cumplen con los requisitos del cliente.

Anexos

Anexo A - Version de R y sistema operativo R version 4.5.2 (2025-10-31)
Sistema Operativo: macOS Tahoe 26.2

Anexo B - Paquetes devtools mice tidyverse factoextra cluster dplyr FactoMineR gridExtra paqueteMODELOS tcltk2 psych ggplot2 patchwork VIM leaflet corrplot plotly

Anexo C - Analisis exploratorio y limpieza de datos Dimensiones del dataset

dim(vivienda)
## [1] 8322   13

Se cuenta con un dataset de 8322 registros descritos por 13 variables.

Reconocimiento de la base de datos, en la cual se identificaron 8 variables cuantitativas (4 discretas y 4 continuas) y 4 variables cuantitativas (nominales principalmente). Sin embargo se identifica a su vez que la variable piso tiene datos faltantes y realmente es una variable cuantitativa discreta.

Identificacion correcta de piso

par(cex = 0.8)
md.pattern(vivienda)

##      preciom id zona estrato areaconst banios habitaciones tipo barrio longitud
## 4808       1  1    1       1         1      1            1    1      1        1
## 1909       1  1    1       1         1      1            1    1      1        1
## 876        1  1    1       1         1      1            1    1      1        1
## 726        1  1    1       1         1      1            1    1      1        1
## 1          1  0    0       0         0      0            0    0      0        0
## 2          0  0    0       0         0      0            0    0      0        0
##            2  3    3       3         3      3            3    3      3        3
##      latitud parqueaderos piso     
## 4808       1            1    1    0
## 1909       1            1    0    1
## 876        1            0    1    1
## 726        1            0    0    2
## 1          0            0    0   12
## 2          0            0    0   13
##            3         1605 2638 4275
par(cex = 1)

Se observa que 4808 registros tienen los datos completos para cada atributo, 1909 registros les falta el dato de piso, 876 les falta eel dato de parqueaderos, 726 les faltan ambos datos, existe un registro con un unido dato de precio y dos registros sin datos.

sum(duplicated(vivienda))
## [1] 1

Se identifica un registro duplicado.

summary(vivienda[c("piso", "estrato", "preciom", "areaconst", "parqueaderos", "banios","habitaciones", "latitud", "longitud")])
##       piso           estrato         preciom         areaconst     
##  Min.   : 1.000   Min.   :3.000   Min.   :  58.0   Min.   :  30.0  
##  1st Qu.: 2.000   1st Qu.:4.000   1st Qu.: 220.0   1st Qu.:  80.0  
##  Median : 3.000   Median :5.000   Median : 330.0   Median : 123.0  
##  Mean   : 3.771   Mean   :4.634   Mean   : 433.9   Mean   : 174.9  
##  3rd Qu.: 5.000   3rd Qu.:5.000   3rd Qu.: 540.0   3rd Qu.: 229.0  
##  Max.   :12.000   Max.   :6.000   Max.   :1999.0   Max.   :1745.0  
##  NA's   :2638     NA's   :3       NA's   :2        NA's   :3       
##   parqueaderos        banios        habitaciones       latitud     
##  Min.   : 1.000   Min.   : 0.000   Min.   : 0.000   Min.   :3.333  
##  1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 3.000   1st Qu.:3.381  
##  Median : 2.000   Median : 3.000   Median : 3.000   Median :3.416  
##  Mean   : 1.835   Mean   : 3.111   Mean   : 3.605   Mean   :3.418  
##  3rd Qu.: 2.000   3rd Qu.: 4.000   3rd Qu.: 4.000   3rd Qu.:3.452  
##  Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :3.498  
##  NA's   :1605     NA's   :3        NA's   :3        NA's   :3      
##     longitud     
##  Min.   :-76.59  
##  1st Qu.:-76.54  
##  Median :-76.53  
##  Mean   :-76.53  
##  3rd Qu.:-76.52  
##  Max.   :-76.46  
##  NA's   :3
describe(vivienda[c("piso", "estrato", "preciom", "areaconst", "parqueaderos", "banios","habitaciones", "latitud", "longitud")])
##              vars    n   mean     sd median trimmed    mad    min     max
## piso            1 5684   3.77   2.61   3.00    3.37   1.48   1.00   12.00
## estrato         2 8319   4.63   1.03   5.00    4.67   1.48   3.00    6.00
## preciom         3 8320 433.89 328.65 330.00  374.43 207.56  58.00 1999.00
## areaconst       4 8319 174.93 142.96 123.00  149.15  84.51  30.00 1745.00
## parqueaderos    5 6717   1.84   1.12   2.00    1.62   1.48   1.00   10.00
## banios          6 8319   3.11   1.43   3.00    2.99   1.48   0.00   10.00
## habitaciones    7 8319   3.61   1.46   3.00    3.41   1.48   0.00   10.00
## latitud         8 8319   3.42   0.04   3.42    3.42   0.05   3.33    3.50
## longitud        9 8319 -76.53   0.02 -76.53  -76.53   0.02 -76.59  -76.46
##                range  skew kurtosis   se
## piso           11.00  1.28     1.05 0.03
## estrato         3.00 -0.18    -1.11 0.01
## preciom      1941.00  1.85     3.67 3.60
## areaconst    1715.00  2.69    12.91 1.57
## parqueaderos    9.00  2.33     8.31 0.01
## banios         10.00  0.93     1.13 0.02
## habitaciones   10.00  1.63     3.98 0.02
## latitud         0.16  0.03    -1.15 0.00
## longitud        0.13  0.65     0.58 0.00

Se identifica que el estrato promedio es 4.63 con un costo promedio de 433, en un tercer piso con area construida 174, 1.84 parquederos, 3.11 baños, 3.61 habitaciones.

p1 <- ggplot(vivienda, aes(y = estrato)) +
  geom_boxplot(fill="lightblue",
               outlier.color = "red",
               outlier.size = 1.5) +
  ggtitle("Estrato")+
  theme(
    plot.title = element_text(size = 10,hjust = 0.5))

p2 <- ggplot(vivienda, aes(y = preciom)) +
  geom_boxplot(fill="lightblue",
               outlier.color = "red",
               outlier.size = 1.5)  +
  ggtitle("Precio")+
  theme(
    plot.title = element_text(size = 10,hjust = 0.5))

p3 <- ggplot(vivienda, aes(y = areaconst)) +
  geom_boxplot(fill="lightblue",
               outlier.color = "red",
               outlier.size = 1.5) +
  ggtitle("Área Construida")+
  theme(
    plot.title = element_text(size = 10,hjust = 0.5))

p4 <- ggplot(vivienda, aes(y = parqueaderos)) +
  geom_boxplot(fill="lightblue",
               outlier.color = "red",
               outlier.size = 1.5)  +
  ggtitle("Numero de parqueaderos")+
  theme(
    plot.title = element_text(size = 10,hjust = 0.5))

p5 <- ggplot(vivienda, aes(y =  banios)) +
  geom_boxplot(fill="lightblue",
               outlier.color = "red",
               outlier.size = 1.5)  +
  ggtitle("Numero de baños")+
  theme(
    plot.title = element_text(size = 10,hjust = 0.5))

p6 <- ggplot(vivienda, aes(y =  habitaciones)) +
  geom_boxplot(fill="lightblue",
               outlier.color = "red",
               outlier.size = 1.5)  +
  ggtitle("Numero de habitaciones")+
  theme(
    plot.title = element_text(size = 10,hjust = 0.5))

p7 <- ggplot(vivienda, aes(y = longitud)) +
  geom_boxplot(fill="lightblue",
               outlier.color = "red",
               outlier.size = 1.5)  +
  ggtitle("Longitud")+
  theme(
    plot.title = element_text(size = 10,hjust = 0.5))

p8 <- ggplot(vivienda, aes(y = latitud)) +
  geom_boxplot(fill="lightblue",
               outlier.color = "red",
               outlier.size = 1.5)  +
  ggtitle("Latitud")+
  theme(
    plot.title = element_text(size = 10,hjust = 0.5))

(p1 | p2 | p3 | p4) /
(p5 | p6 | p7 | p8)
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Warning: Removed 2 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Warning: Removed 1605 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Removed 3 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Removed 3 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Removed 3 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

Se identifican outliers en las variables cuantitativas: precio, area construida, numero de parqueaderos, numero de habitaciones y longitud.

lapply(vivienda[c("zona", "tipo", "barrio")], function(x) {
  sort(table(x), decreasing = TRUE)[1]
})
## $zona
## Zona Sur 
##     4726 
## 
## $tipo
## Apartamento 
##        5100 
## 
## $barrio
## valle del lili 
##           1008

Se identifica que las viviendas disponibles comercialmente se encuentran en la zona zur, tipo apartamento en el Valle de Lili.

p1<-ggplot(vivienda, aes(x = zona)) +
  geom_bar(fill = "lightblue") +
  theme_minimal() +
  theme(axis.text.x = element_text(size=8, angle = 90, hjust = 1)) +
  labs(title = "Distribución por Zona",
       x = "Zona",
       y = "Frecuencia")
p2<-ggplot(vivienda, aes(x = tipo)) +
  geom_bar(fill = "lightblue") +
  theme_minimal() +
  theme(axis.text.x = element_text(size=8, angle = 90, hjust = 1)) +
  labs(title = "Distribución por tipo de vivienda",
       x = "Vivienda",
       y = "Frecuencia")
p3<-ggplot(vivienda, aes(x = barrio)) +
  geom_bar(fill = "lightblue") +
  theme_minimal() +
  theme(axis.text.x = element_text(size=1, angle = 90, hjust = 1)) +
  labs(title = "Distribución por barrio",
       x = "Barrio",
       y = "Frecuencia")
(p1 | p2 ) /
(p3) 

Se identifica que la zona y el tipo de vivenda tienen datos faltantes, la zona centro tiene baja frecuencia y podria considerarse dato atipico.

Preprocesamiento de datos 1. Eliminacion de duplicados

vivienda <- vivienda[!duplicated(vivienda), ]
sum(duplicated(vivienda))
## [1] 0

2. Manejo de datos faltantes 2.1 Eliminar registros con mas de dos datos faltantes

na_fila <- rowSums(is.na(vivienda))
vivienda <- vivienda[na_fila < 2, ]

2.3 Imputacion de datos a registros con 1 a 2 datos faltantes

vivienda <-  kNN(vivienda, variable = c("piso", "parqueaderos"), k = 10)
par(cex = 0.8)
md.pattern(vivienda)
##  /\     /\
## {  `---'  }
## {  O   O  }
## ==>  V <==  No need for mice. This data set is completely observed.
##  \  \|/  /
##   `-----'

##      id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## 7593  1    1    1       1       1         1            1      1            1
##       0    0    0       0       0         0            0      0            0
##      tipo barrio longitud latitud piso_imp parqueaderos_imp  
## 7593    1      1        1       1        1                1 0
##         0      0        0       0        0                0 0
par(cex = 1)

3. Manejo de datos atipicos 3.1 Eliminacion de datos atipicos en variables cualitativas

vivienda <- vivienda[vivienda$zona != "Zona Centro", ]

3.2 Eliminacion de outliers en variables cuantitativas

variables_cuantitativas <- c("piso", "estrato", "preciom", "areaconst", "parqueaderos", "banios","habitaciones", "latitud", "longitud")
limites <- t(sapply(variables_cuantitativas, function(v) {
  x <- vivienda[[v]]
  Primer_cuartil<- quantile(x, 0.25)
  Tercer_cuartil <- quantile(x, 0.75)
  RIC  <- IQR(x)
  c(lim_inf = Primer_cuartil - 1.5*RIC, lim_sup = Tercer_cuartil + 1.5*RIC)
}))

vivienda<- vivienda[
  vivienda$estrato >= limites["estrato","lim_inf.25%"] &
  vivienda$estrato <= limites["estrato","lim_sup.75%"] &

  vivienda$preciom >= limites["preciom","lim_inf.25%"] &
  vivienda$preciom <= limites["preciom","lim_sup.75%"] &

  vivienda$areaconst >= limites["areaconst","lim_inf.25%"] &
  vivienda$areaconst <= limites["areaconst","lim_sup.75%"] &

  vivienda$parqueaderos >= limites["parqueaderos","lim_inf.25%"] &
  vivienda$parqueaderos <= limites["parqueaderos","lim_sup.75%"] &

  vivienda$banios >= limites["banios","lim_inf.25%"] &
  vivienda$banios <= limites["banios","lim_sup.75%"] &

  vivienda$habitaciones >= limites["habitaciones","lim_inf.25%"] &
  vivienda$habitaciones <= limites["habitaciones","lim_sup.75%"] &

  vivienda$latitud >= limites["latitud","lim_inf.25%"] &
  vivienda$latitud <= limites["latitud","lim_sup.75%"] &

  vivienda$longitud >= limites["longitud","lim_inf.25%"] &
  vivienda$longitud <= limites["longitud","lim_sup.75%"],
]
dim(vivienda)
## [1] 5944   15
vivienda <- vivienda[, !(names(vivienda) %in% c("piso_imp", "parqueaderos_imp"))]

Posterior al pretratamiento de los datos se obtiene un dataset con 5944 registros y 15 atributos.