1. Filtro de la base de datos

Se realizó un filtro para conservar únicamente los datos referentes a ‘Apartamento’.

datosVivienda$tipo <- replace (datosVivienda$tipo, datosVivienda$tipo %in% c("casa","CASA","APARTAMENTO","apto"), c("Casa","Casa","Apartamento","Apartamento"))

vivienda5<- subset(datosVivienda,tipo=='Apartamento')

print.data.frame(head(vivienda5, n=3))
##     id       zona piso estrato preciom areaconst parqueaderos banios
## 1 1212 Zona Norte   01       5     260        90            1      2
## 2 1724 Zona Norte   01       5     240        87            1      3
## 3 2326 Zona Norte   01       4     220        52            2      2
##   habitaciones        tipo barrio  longitud latitud
## 1            3 Apartamento  acopi -76.51350 3.45891
## 2            3 Apartamento  acopi -76.51700 3.36971
## 3            3 Apartamento  acopi -76.51974 3.42627
summary(vivienda5)
##        id           zona               piso              estrato     
##  Min.   :   3   Length:5100        Length:5100        Min.   :3.000  
##  1st Qu.:2180   Class :character   Class :character   1st Qu.:4.000  
##  Median :4158   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :4284                                         Mean   :4.727  
##  3rd Qu.:6556                                         3rd Qu.:6.000  
##  Max.   :8317                                         Max.   :6.000  
##                                                                      
##     preciom         areaconst      parqueaderos        banios     
##  Min.   :  58.0   Min.   : 35.0   Min.   : 1.000   Min.   :0.000  
##  1st Qu.: 175.0   1st Qu.: 68.0   1st Qu.: 1.000   1st Qu.:2.000  
##  Median : 279.0   Median : 90.0   Median : 1.000   Median :2.000  
##  Mean   : 366.9   Mean   :112.8   Mean   : 1.568   Mean   :2.617  
##  3rd Qu.: 430.0   3rd Qu.:130.0   3rd Qu.: 2.000   3rd Qu.:3.000  
##  Max.   :1950.0   Max.   :932.0   Max.   :10.000   Max.   :8.000  
##                                   NA's   :869                     
##   habitaciones       tipo              barrio             longitud     
##  Min.   :0.000   Length:5100        Length:5100        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   :2.971                                         Mean   :-76.53  
##  3rd Qu.:3.000                                         3rd Qu.:-76.52  
##  Max.   :9.000                                         Max.   :-76.46  
##                                                                        
##     latitud     
##  Min.   :3.334  
##  1st Qu.:3.380  
##  Median :3.419  
##  Mean   :3.419  
##  3rd Qu.:3.453  
##  Max.   :3.498  
## 
str(vivienda5)
## tibble [5,100 × 13] (S3: tbl_df/tbl/data.frame)
##  $ id          : num [1:5100] 1212 1724 2326 4386 7497 ...
##  $ zona        : chr [1:5100] "Zona Norte" "Zona Norte" "Zona Norte" "Zona Norte" ...
##  $ piso        : chr [1:5100] "01" "01" "01" "01" ...
##  $ estrato     : num [1:5100] 5 5 4 5 6 4 5 3 3 6 ...
##  $ preciom     : num [1:5100] 260 240 220 310 520 320 385 100 175 820 ...
##  $ areaconst   : num [1:5100] 90 87 52 137 98 108 103 49 80 377 ...
##  $ parqueaderos: num [1:5100] 1 1 2 2 2 2 2 NA 1 1 ...
##  $ banios      : num [1:5100] 2 3 2 3 2 3 2 1 2 4 ...
##  $ habitaciones: num [1:5100] 3 3 3 4 2 3 3 2 3 4 ...
##  $ tipo        : chr [1:5100] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
##  $ barrio      : chr [1:5100] "acopi" "acopi" "acopi" "acopi" ...
##  $ longitud    : num [1:5100] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:5100] 3.46 3.37 3.43 3.38 3.44 ...

2. Análisis exploratorio

Se realizó un anális exploratorio revisando la correlación entre la variable respuesta precio de la casa y las siguientes variables:

plot_ly(vivienda5, x = ~areaconst, y = ~preciom)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

La relación con respecto del precio y el área construida muestra una correlación positiva, mucho más marcada en los precios hasta 1000 y áreas menores a 400, depsues de eso la relación comienza a ser menos evidente con algunos outliers.

El precio con respecto al estrato tiene una relación creciente, con un mayor precio total a medida que el estrato aumenta. Sin embargo la varianza entre precios en el mismo estrato.

plot_ly(vivienda5, x = ~estrato, y = ~preciom)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

La relación con los baños no es tan evidente, el precio aumenta generalmente hasta cuatro baños, luego se mantiene relativamente estable. Sin embargo los apartamento sin baño tambien tienen precios altos.

plot_ly(vivienda5, x = ~banios, y = ~preciom)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

La relación con el número de habitaciones se comporta muy similar al número de baños, aumentando de forma positiva hasta cuatro habitaciones y luego se dispersa y disminuye poco a poco.

plot_ly(vivienda5, x = ~habitaciones, y = ~preciom)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

El análisis de las zonas de la ciudad con respecto al precio muestra que la zona Oeste tiene los precios más altos, aunque tienen una varianza grande y precios mínimos comparables al resto de las zonas. La zona Oriente tiene los menores precios seguida de la zona centro.

plot_ly(vivienda5, x = ~zona, y = ~preciom, type = "box")

3. Estimación de un modelo de regresión lineal múltiple

Antes de proceder con la creación del modelo, se realizó un tratamiento de los datos faltantes. Para las variables piso y parqueadero que tienen valores faltantes, se creó un vector con los valores faltantes para esas variables, donde “TRUE” representa los datos faltantes. Estos valores faltantes se analizaron contra algunas variables como tipo de casa y estrato:

Para el caso de piso faltante, no se ve una distribución particular y los faltantes están homogéneamente distribuidos, entonces no es posible imputar esto valores con un 0 o el promedio dado que sería un error, por este motivo se van a eliminar los registros que tengan datos faltantes para esta variables.

Para el caso de parqueadero faltante, se ve una distribución particular cuando se analiza contra estrato, teniendo en cuenta esta distribución es posible inferir que los datos faltantes representan un 0, donde las viviendas de estratos más bajos no tienen casi parqueaderos pero las de estratos altos sí. Por este motivo se van a reemplazar los datos faltantes por 0.

Luego de estos ajustes ya no quedan datos faltantes:

md.pattern(vivienda5)

##      id zona estrato preciom areaconst parqueaderos banios habitaciones tipo
## 3719  1    1       1       1         1            1      1            1    1
## 1381  1    1       1       1         1            1      1            1    1
##       0    0       0       0         0            0      0            0    0
##      barrio longitud latitud piso     
## 3719      1        1       1    1    0
## 1381      1        1       1    0    1
##           0        0       0 1381 1381
vivienda5 = na.omit(vivienda5)

md.pattern(vivienda5)
##  /\     /\
## {  `---'  }
## {  O   O  }
## ==>  V <==  No need for mice. This data set is completely observed.
##  \  \|/  /
##   `-----'

##      id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## 3719  1    1    1       1       1         1            1      1            1
##       0    0    0       0       0         0            0      0            0
##      tipo barrio longitud latitud  
## 3719    1      1        1       1 0
##         0      0        0       0 0

Posterior a resto, se realizó la estimación del modelo:

modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = vivienda5)
summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = vivienda5)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1767.05   -50.51    -3.28    42.56   989.76 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -210.35391   15.03286 -13.993   <2e-16 ***
## areaconst       2.06801    0.04834  42.783   <2e-16 ***
## estrato        44.61633    3.11009  14.346   <2e-16 ***
## habitaciones  -32.80136    3.72542  -8.805   <2e-16 ***
## parqueaderos   67.45598    3.73369  18.067   <2e-16 ***
## banios         52.29583    3.45623  15.131   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 129.4 on 3713 degrees of freedom
## Multiple R-squared:  0.7853, Adjusted R-squared:  0.7851 
## F-statistic:  2717 on 5 and 3713 DF,  p-value: < 2.2e-16

Todos los coeficientes son estadísticamente significativos y el valor del r2 es relativamente bueno, con un 0,78 predice casi el 80% de la varianza del los datos con el modelo creado, para mejorar este modelo de podrían eliminar algunos valores atípico y crear variables dummie para las variables categóricas como estrato, adicionalmente se pueden hacer alguna transformación matemática en los datos para que cumplan los supuestos y mejore su rendimiento.

Los coeficientes de este modelo se pueden interpretrar de la siguiente manera:

Estos resultados son lógicos en su gran mayoria, donde las categorias con

4. Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).

Al realizar un análisis gráfico de los supuestos, se observa que no se cumplen de forma adecuada:

En la primera gráfica se puede observar que la relación no es completamente lineal, dado que la tendencia tiene una curvatura para arriba en las puntas, mucho más marcada .

En la segunda gráfica se puede comprobar que los errores no siguen una distribución normal y no se ajustan a la línea, en especial despues de 2.

En la tercera gráfica se revisa que los datos no son homocedásticos dado que no sigue una línea recta.

En la cuarta gráfica se observa que hay dos valores atípicos muy grandes a más de 0.5 de distancia de cook y uno a más de 1, estos se deberían revisar en detalle porque tienen un gran efecto en el modelo y sería mejor eliminarlos.

plot(modelo1)

5. Realice una partición en los datos de forma aleatoria donde 70% sea un set para entrenar el modelo y 30% para prueba. Estime el modelo con la muestra del 70%. Muestre los resultados.

Se realiza la separación de los datos en 70% y 30%:

set.seed(42)

index<- sample(1:nrow(vivienda5), 7/10 * nrow(vivienda5))

trainingSet<- vivienda5[index,]
testSet<-  vivienda5[-index,]

str(trainingSet)
## tibble [2,603 × 13] (S3: tbl_df/tbl/data.frame)
##  $ id          : num [1:2603] 5243 2507 7649 6700 5886 ...
##  $ zona        : chr [1:2603] "Zona Norte" "Zona Norte" "Zona Sur" "Zona Sur" ...
##  $ piso        : chr [1:2603] "03" "11" "04" "04" ...
##  $ estrato     : num [1:2603] 6 4 4 5 6 5 6 4 4 5 ...
##  $ preciom     : num [1:2603] 740 215 210 220 180 210 650 155 235 235 ...
##  $ areaconst   : num [1:2603] 161 71 69 115 54.5 ...
##  $ parqueaderos: num [1:2603] 2 1 2 1 1 1 2 1 1 1 ...
##  $ banios      : num [1:2603] 3 2 2 2 2 3 4 2 2 2 ...
##  $ habitaciones: num [1:2603] 3 2 3 3 1 3 4 3 2 3 ...
##  $ tipo        : chr [1:2603] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
##  $ barrio      : chr [1:2603] "santa monica" "prados del norte" "el refugio" "el limonar" ...
##  $ longitud    : num [1:2603] -76.5 -76.5 -76.6 -76.5 -76.5 ...
##  $ latitud     : num [1:2603] 3.46 3.47 3.4 3.4 3.45 ...
##  - attr(*, "na.action")= 'omit' Named int [1:1381] 16 17 18 19 20 21 22 23 24 25 ...
##   ..- attr(*, "names")= chr [1:1381] "16" "17" "18" "19" ...
str(testSet)
## tibble [1,116 × 13] (S3: tbl_df/tbl/data.frame)
##  $ id          : num [1:1116] 7497 5424 2323 8109 8179 ...
##  $ zona        : chr [1:1116] "Zona Norte" "Zona Norte" "Zona Norte" "Zona Oeste" ...
##  $ piso        : chr [1:1116] "02" "03" "05" "01" ...
##  $ estrato     : num [1:1116] 6 4 6 4 3 4 6 3 6 3 ...
##  $ preciom     : num [1:1116] 520 320 450 150 140 120 1050 98 950 118 ...
##  $ areaconst   : num [1:1116] 98 108 103 55 60 60 240 62 217 60 ...
##  $ parqueaderos: num [1:1116] 2 2 2 0 1 0 3 0 3 0 ...
##  $ banios      : num [1:1116] 2 3 3 1 2 1 5 2 5 1 ...
##  $ habitaciones: num [1:1116] 2 3 4 2 2 3 4 3 4 2 ...
##  $ tipo        : chr [1:1116] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
##  $ barrio      : chr [1:1116] "acopi" "acopi" "acopi" "aguacatal" ...
##  $ longitud    : num [1:1116] -76.5 -76.5 -76.5 -76.6 -76.6 ...
##  $ latitud     : num [1:1116] 3.44 3.41 3.44 3.46 3.46 ...
##  - attr(*, "na.action")= 'omit' Named int [1:1381] 16 17 18 19 20 21 22 23 24 25 ...
##   ..- attr(*, "names")= chr [1:1381] "16" "17" "18" "19" ...

Se estima de nuevo el modelo con los datos de test:

modeloTest <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = trainingSet)
summary(modeloTest)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = trainingSet)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1662.03   -50.50    -4.93    41.61  1004.56 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -226.80056   18.06827 -12.552  < 2e-16 ***
## areaconst       1.94310    0.05682  34.199  < 2e-16 ***
## estrato        46.77728    3.76348  12.429  < 2e-16 ***
## habitaciones  -25.86682    4.48752  -5.764 9.18e-09 ***
## parqueaderos   70.75755    4.49125  15.755  < 2e-16 ***
## banios         49.93977    4.16528  11.990  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 130.9 on 2597 degrees of freedom
## Multiple R-squared:  0.7728, Adjusted R-squared:  0.7724 
## F-statistic:  1767 on 5 and 2597 DF,  p-value: < 2.2e-16

6. Realice predicciones con el modelo anterior usando los datos de prueba (30%).

Se realiza la predicción con el modelo y se agrega una nueva columna al final del dataset con el resultado:

testSet$prediccion <- predict(modeloTest, newdata=testSet, type='response');  print.data.frame(head(testSet))
##     id       zona piso estrato preciom areaconst parqueaderos banios
## 1 7497 Zona Norte   02       6     520        98            2      2
## 2 5424 Zona Norte   03       4     320       108            2      3
## 3 2323 Zona Norte   05       6     450       103            2      3
## 4 8109 Zona Oeste   01       4     150        55            0      1
## 5 8179 Zona Oeste   01       3     140        60            1      2
## 6 8105 Zona Oeste   02       4     120        60            0      1
##   habitaciones        tipo    barrio  longitud latitud prediccion
## 1            2 Apartamento     acopi -76.54999 3.43505  433.94807
## 2            3 Apartamento     acopi -76.53638 3.40770  383.89749
## 3            4 Apartamento     acopi -76.51972 3.44000  441.86971
## 4            2 Apartamento aguacatal -76.55520 3.45970   65.38527
## 5            2 Apartamento aguacatal -76.55668 3.45832  149.02082
## 6            3 Apartamento aguacatal -76.55502 3.45972   49.23396

7. Calcule el error cuadrático medio, el error absoluto medio y el R2, interprete.

El error cuadratico medio es:

errorCuadraticoMedio<- mse(testSet$preciom, testSet$prediccion); errorCuadraticoMedio
## [1] 16023.22

Este valor es bastante alto y deberían probarse diferentes modelos para intentar disminuir este error.

El error absoluto medio es:

errorAbsolutoMedio<- mae(testSet$preciom, testSet$prediccion); errorAbsolutoMedio
## [1] 78.76266

Se puede interpretar como que en promedio el modelo da un valor de 78 millones diferente al resultado real, este valor es bastante grande teniendo en cuenta que en algunos apartamento puede llegar a ser un porcentaje importante con respecto al precio total y puede disminuir las ganancias del vendedor al tener tanto error.

El R2 es:

summary(modeloTest)$r.squared
## [1] 0.7728333

Es ligeramente inferior al resultado obtenido en el modelo original, pero sigue siendo un resultado aceptable aunque con mucho margen de mejora.