Enunciado

Maria comenzó como agente de bienes raíces en Cali hace 10 años. Después de laborar dos años para una empresa nacional, se traslado a Bogotá y trabajó para otra agencia de bienes raíces. Sus amigos y familiares la convencieron de que con su experiencia y conocimientos del negocio debía abrir su propia agencia. Terminó por adquirir la licencia de intermediario y al poco tiempo fundó su propia compañía, C&A (Casas y Apartamentos) en Cali. Santiago y Lina, dos vendedores de la empresa anterior aceptaron trabajar en la nueva compaña. En la actualidad ocho agentes de bienes raíces colaboran con ella en C&A.

Actualmente las ventas de bienes raíces en Cali se han visto disminuidas de manera significativa en lo corrido del año. Durante este periodo muchas instituciones bancarias de ahorro y vivienda están prestando grandes sumas de dinero para la industria y la construcción comercial y residencial. Cuando el efecto producto de las tensiones políticas y sociales disminuya, se espera que la actividad económica de este sector se reactive.

Hace dos días, 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:

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

#install.packages("devtools") # solo la primera vez
#devtools::install_github("dgonxalex80/paqueteMODELOS", force =TRUE)
library(paqueteMODELOS)
## Loading required package: boot
## 
## Attaching package: 'boot'
## The following object is masked from 'package:psych':
## 
##     logit
## Loading required package: broom
## Loading required package: GGally
## Registered S3 method overwritten by 'GGally':
##   method from   
##   +.gg   ggplot2
## Loading required package: knitr
## Loading required package: summarytools
## 
## Attaching package: 'summarytools'
## The following object is masked from 'package:lessR':
## 
##     label
## The following object is masked from 'package:tibble':
## 
##     view
library(dplyr)
data(vivienda)

Ordenar DATA

En el dataframe data01 se encuentran datos en forma de texto, que contienen mayúsculas o abreviaciones de las palabras, por tanto se decide cambiar todo a la opción minúsculas, para que los resultados no muestren distintas formas de un mismo dato, ejemplo:

Apartamento, APARTAMENTO, apto.

# Convertir todos los datos en minúsculas, para Mayúsculas usa toupper en vez de tolower
base1 <- mutate_if(vivienda, is.character, tolower)
base1$tipo[base1$tipo == "apto"] <- "apartamento"
unique(base1$tipo)
## [1] "casa"        "apartamento" NA
unique(base1$estrato)
## [1]  3  4  5  6 NA

Actividad

Punto 1

Realice un filtro a la base de datos e incluya solo las ofertas de : base1: casas, de la zona norte de la ciudad. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta.

# Filtro para apartamentos de toda la ciudad
conflicts_prefer(mice::filter)
## [conflicted] Will prefer mice::filter over any other package.
base1 <- filter(base1, tipo == "casa",zona == "zona norte")
# quitamos las variables id, piso, barrio
base1 <- base1 [, c(2,4, 5, 6, 7,8,9,10,12,13)] 
head(base1,3)
#Número total de apartamentos
print(paste("El numero casas en la zona norte de la ciudad de Cali es de:", nrow(base1)))
## [1] "El numero casas en la zona norte de la ciudad de Cali es de: 722"

Casas-Estratos

tabla_ce = data.frame(table(base1$estrato))
colnames(tabla_ce) = c("estrato", "casas")
tabla_ce

Mapa Casas

library(leaflet)
base2 <- na.omit(base1)
mapa_casas = leaflet() %>% addCircleMarkers(lng = base2$longitud,
                                          lat = base2$latitud,
                                          radius = 0.3,
                                          color = "red",
                                          label = base1$id) %>% addTiles()

mapa_casas

Punto 2

Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio de las casa) en función del área construida, estrato, numero de baños, numero de habitaciones. Use gráficos interactivos con el paquete plotly e interprete los resultados.

base3 <- base1 [, c(2,3,4,6, 7)] 
skim(base3)
Data summary
Name base3
Number of rows 722
Number of columns 5
_______________________
Column type frequency:
numeric 5
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
estrato 0 1 4.20 0.98 3 3.00 4 5.00 6 ▇▅▁▇▂
preciom 0 1 445.91 268.36 89 261.25 390 550.00 1940 ▇▃▁▁▁
areaconst 0 1 264.85 167.17 30 140.00 240 336.75 1440 ▇▃▁▁▁
banios 0 1 3.56 1.52 0 2.00 3 4.00 10 ▅▇▃▁▁
habitaciones 0 1 4.51 1.83 0 3.00 4 5.00 10 ▁▇▅▂▁

Variables dummy

  • El estrato socioeconómico es una variable categórica ordinal y se crearan dicótomas o dummies que se requieren.

  • Se considera que los atributos de la vivienda, como habitaciones, baños y número de parqueaderos pueden considerarse variables seudocategóricas. Para efectos metodológicos se considerarán cuantitativas.

Para Crear variables dicótomas a partir del estrato (Se usa el comando dummy_cols de la librería fastDummies):

library(fastDummies)
## Thank you for using fastDummies!
## To acknowledge our work, please cite the package:
## Kaplan, J. & Schlegel, B. (2023). fastDummies: Fast Creation of Dummy (Binary) Columns and Rows from Categorical Variables. Version 1.7.1. URL: https://github.com/jacobkap/fastDummies, https://jacobkap.github.io/fastDummies/.
base4 <- dummy_cols(base3,select_columns = "estrato")
# base 4 contiene 9 variables que incluyen estrato_3,estrato_4,estrato_5,estrato_6

Análisis Exploratorio

Es importante destacar que hay casas que carecen de baños o habitaciones, lo cual no es del todo común. Debido a esto, se ha tomado la decisión de excluirlas, También conociendo que el estrato y la zona son de tipo categórico y algún análisis exploratorio de esas variables no genera gran aporte a la investigación se decide solo dejar las variable PRECIO y AREA de los apartamentos de todas las zonas de la ciudad de Cali

base5 <- base4 [, c(2, 3)] 
summary(base5)
##     preciom         areaconst     
##  Min.   :  89.0   Min.   :  30.0  
##  1st Qu.: 261.2   1st Qu.: 140.0  
##  Median : 390.0   Median : 240.0  
##  Mean   : 445.9   Mean   : 264.9  
##  3rd Qu.: 550.0   3rd Qu.: 336.8  
##  Max.   :1940.0   Max.   :1440.0

Podemos observar que el precio de las casas de la zona norte de la ciudad de Cali oscila entre 89 millones y 1.940 millones de pesos. Además, en promedio, la mitad de las casas tienen un precio de 390 millones de pesos. Por otra parte, podemos apreciar que el área construida tiene un promedio de 240 metros cuadrados. Sin embargo, notamos que algunas casas tienen un área mínima de 30 metros cuadrados.

Correlación

#base6 <- base1 [, c(2,3,4, 6, 7)] 
chart.Correlation(base3, hist = TRUE, method = "pearson")

  • Se aprecia que el precio de las casas posee una fuerte relación con el área construida, esto significa que a mayor área, mayor será el precio.

  • se observa una relación positiva entre el estrato y el precio de la casa.

  • Sin embargo, al examinar la relación entre el precio y habitaciones, se presenta una relación débil. De igual manera, ocurre con la relación entre el precio y el número de baños.

Precio-Area

library(plotly)
ggplotly(ggplot(base5,
                aes(y=preciom, x=areaconst)) + geom_point() + geom_smooth() + theme_bw())
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

podemos observar la relación entre el precio de las casas y el área construida. En una primera instancia, notamos una relación directa y lineal entre ambas variables, lo cual también fue indicado por la matriz de correlación. Sin embargo, a medida que el tamaño de la vivienda aumenta, se observa que algunas casas tienen un precio mucho menor de lo esperado, por ejemplo, hay una casa que posee un area de 1440 metros cuadrados y cuesta solo 370 millones de pesos, lo cual puede ser un valor no muy congruente o se encuentra en un estrato de menor valor, tampoco sería algo ilógico pues una casa con un área de ejemplo 200 metros cuadrados no tiene el mismo precio en el estrato 3 que en el estrato 6.

# Distribución de densidad de las variables precio y área
require(psych)
multi.hist(x = base5, dcol = c("blue", "red"), 
           dlty = c("dotted", "solid"), main = "" )

Precio-Estrato

Antes de empezar se decide crear la variable “estrato2” como una variable de tipo texto para que pase como categórica en la visualización de la data. la variable original se llama “estrato”

#copiamos base3 para mantener la variable original del estrato como tipo númerico
base6 <- base3
estrato2 <- as.character(base3$estrato)
base6 <- cbind(base6,estrato2) #Se corre una vez
p_estrato <- ggplot(base6,aes(x=estrato2,y=preciom, fill=estrato2))+
            geom_boxplot()+
            labs(x="Estrato",y="Precio en Millones",title="Casas Norte de Cali") + 
            theme (panel.background = element_blank()
            )

plotly::ggplotly(p_estrato)

Es importante aclarar que el estrato socieconómico es una variable categórica que se podría no incorporar con su valor a nivel (1, 2, 3, 4, 5, 6), sino con el nombre de la categoría en su orden: (bajo bajo, bajo, medio bajo, medio, medio alto, alto. )

Teóricamente se espera que los estratos socioeconómicos de mayores ingresos posean viviendas de mayor precio, y eso es lo que muestra el gráfico.

Precio-baños

plot_ly(base6,x=~banios,y=~preciom,type="scatter", mode = "markers",
        color=~estrato2, symbol = ~estrato2)

Precio-habitaciones

plot_ly(base6,x=~habitaciones,y=~preciom,type="scatter", mode = "markers",
        color=~estrato2, symbol = ~estrato2)

Punto 3

Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área, estrato, habitaciones, 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).

Respuesta

Se constata que se crearon las variables “dummy” de cada uno de los estratos. Se opta por simplificar el dataset, para efectos de mejorar el análisis:

#la base4 contiene las 9 variables resultado de la variable dummy
base_mlineal <- base4[,c(2,3,4,5,6,7,8,9)]
base_mlineal <- na.omit(base_mlineal) # en caso de que haya algún NA 
glimpse(base_mlineal)
## Rows: 722
## Columns: 8
## $ preciom      <dbl> 320, 780, 750, 625, 750, 600, 420, 490, 230, 190, 180, 50…
## $ areaconst    <dbl> 150, 380, 445, 355, 237, 160, 200, 118, 160, 435, 120, 21…
## $ banios       <dbl> 4, 3, 7, 5, 6, 4, 4, 4, 2, 0, 3, 6, 5, 5, 3, 3, 4, 5, 5, …
## $ habitaciones <dbl> 6, 3, 6, 5, 6, 5, 5, 4, 3, 0, 3, 6, 4, 8, 4, 3, 4, 6, 4, …
## $ estrato_3    <int> 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, …
## $ estrato_4    <int> 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, …
## $ estrato_5    <int> 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, …
## $ estrato_6    <int> 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …

Regresión lineal

mod_casas <- lm(preciom ~ areaconst + estrato_4 + estrato_5 + estrato_6 + habitaciones + banios, data = base_mlineal)
summary(mod_casas)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato_4 + estrato_5 + estrato_6 + 
##     habitaciones + banios, data = base_mlineal)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -972.05  -73.02  -15.60   45.95 1064.25 
## 
## Coefficients:
##               Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)   30.27964   17.60512   1.720               0.0859 .  
## areaconst      0.82657    0.04289  19.274 < 0.0000000000000002 ***
## estrato_4     85.86991   17.27886   4.970           0.00000084 ***
## estrato_5    139.49127   16.13506   8.645 < 0.0000000000000002 ***
## estrato_6    330.33116   26.46332  12.483 < 0.0000000000000002 ***
## habitaciones   1.81876    4.10123   0.443               0.6576    
## banios        25.83183    5.34112   4.836           0.00000162 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 156.9 on 715 degrees of freedom
## Multiple R-squared:  0.6611, Adjusted R-squared:  0.6583 
## F-statistic: 232.5 on 6 and 715 DF,  p-value: < 0.00000000000000022

Los resultados son los siguientes:

La prueba F y el p-value del modelo indica que el modelo globalmente es significativo desde el punto de vista estadístico. Los parámetros en su conjunto son estadísticamente difernetes a cero.

El intercepto a nivel indica que una vivienda en la zona norte cuesta 30 millones de forma autónoma.

El parámetro de área indica que un metro cuadrado adicional aumenta el valor de la vivienda en 0.82 millones o lo que es igual, en 826570 mil pesos para este subgrupo. Es teóricamente correcto, se supone que a mayor número de metros cuadrados, el precio debe ser mayor, y es estadísticamente significativa

Para el caso de estrato, no entra al juego la variable de estrato 3. Incluirla habría tenido un problema de estimación por multicolinealidad perfecta. Los parámetros para estrato 3, 4 y 5 son estadísticamente significativos, e indican que manteniendo todo lo demás constante, * el ser estrato 4 le agrega 85 millones al precio, * el ser estrato 5 le agrega 139 millones * el ser estrato 6 le agrega 330 millones al precio final de la vivienda.

En el caso de las habitaciones, el parámetro es estadísticamente no significativo, y posiblemente podria salir del modelo. El hecho que haya sido positivo(mayor a cero, teóricamente correcto), y que una habitación adicional le agrega 1 millón al precio de la vivienda, puede ser alentador, pero no relevante ni concluyente estadísticamente hablando.

En el caso del número de baños, el parámetro es estadísticamente significativo aunque con un nivel de confianza del 95%, mas bajo que los otros parámetros. Podemos concluir que un baño adicional valoriza la casa en 25 millones de pesos.

El R2 ajustado está en el orden del 66% lo que indica que los regresores en su conjunto explican las variaciones del 66% del precio de una vivienda. Al parecer, el ajuste del modelo puede no ser del todo preciso o satisfactorio, y podría generar incertidumbre al momento de escoger la mejor opción de vivienda o valorar correctamente una casa a partir de los atributos objeto del estudio.


Para mejorar el nivel de ajuste del modelo, podríamos optar por alguna de las siguientes características:

  • Incorporar nuevos determinantes del precio de la vivienda: Accesibilidad, servicios públicos disponibles, cercanía a dotacionales como parques, hospitales, escuelas, universidades, accesibilidad a transporte público, cercanía a zonas contaminadas o industriales

  • Pensar en una forma funcional diferente: Posiblemente el modelo no sea lineal.

Punto 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).

par(mfrow = c(2, 2)) 
plot(mod_casas)

En la parte superior, se puede ver que el gráfico “Residuasl Vs Fitted” los residuos rotan alrededor del cero, lo que es un indicio de linealidad en los parámetros.

Test Shapiro

Distribución Normal de Residuos:

shapiro.test(mod_casas$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  mod_casas$residuals
## W = 0.83094, p-value < 0.00000000000000022

El resultado, de acuerdo con el test de Shapiro-Wilk indica que los residuos no siguen una distribucion normal

Test Breusch-P

Varianza constante de los errores, homocedasticidad:

library(lmtest)
bptest(mod_casas)
## 
##  studentized Breusch-Pagan test
## 
## data:  mod_casas
## BP = 136.91, df = 6, p-value < 0.00000000000000022

Los resultados de la prueba de Breusch-Pagan generan un p-valor menor a 5%, es decir, los residuos no tienen varianza constante, o no son homocedásticos.

Multicolinealidad

Se hace un gráfico con el objetivo de detectar posible relación lineal entre regresores

library(corrplot)
pairs(base3[, c("estrato", "areaconst", "banios", "habitaciones")])

grado de relación lineal entre el número de baños y el número de habitaciones (Lo cual es lógico, es de presumir que a mayor número de habitaciones, una casa debería tener una cantidad mayor de baños). Para efectos de determinar la presencia de un grado no manejable de multicolinealidad en el modelo, se procede analizando el factor inflador de la varianza:

library(car)
## Loading required package: carData
vif_mod_casas <- vif(mod_casas)
vif_mod_casas
##    areaconst    estrato_4    estrato_5    estrato_6 habitaciones       banios 
##     1.505726     1.517649     1.790770     1.445872     1.646112     1.940813

Dado que no se presentan valores mayores a 5, se puede concluir que la posible relacion de linealidad observada en algunas variables aparentemente no representaría problemas representativos por la existencia de multicolinealidad.

Punto 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.

División Datos

  • Para dividir los datos en una muestra de entrenamiento y otra de test se usa el comando createDataPartition.
  • En el código siguiente p representa la proporción de datos en la muestra de entrenamiento.
  • La partición se lleva a cabo para cada nivel de la variable y que aparece como primer argumento. * El resultado es un vector con los índices de las filas seleccionadas para formar parte de la muestra de entrenamiento.
  • El argumento list=FALSE se usa para evitar que el resultado sea una lista.
library(caret)
## Loading required package: lattice
## 
## Attaching package: 'lattice'
## The following object is masked from 'package:boot':
## 
##     melanoma
## Registered S3 methods overwritten by 'pROC':
##   method    from
##   print.roc fmsb
##   plot.roc  fmsb
set.seed(100)  # semilla para reproducir los mismos resultados
train_base3 <- createDataPartition(y = base_mlineal$preciom,
                                            p = 0.7,
                                            list = FALSE)
train_casa <- base_mlineal[train_base3,]
test_casa <- base_mlineal[-train_base3,]

Train_Casas

dim(train_casa)
## [1] 507   8

Test_Casas

dim(test_casa)
## [1] 215   8
resul_obs_casas <- dim(train_casa) + dim(test_casa)
resul_obs_casas <- resul_obs_casas[1]
resul_obs_casas
## [1] 722

la suma de los datos de entrenamiento + los datos de prueba = total de observaciones que corresponden a las 722 de las casas de la zona norte de la ciudad de Cali

Estimar Train_casas

normalizar los valores precio area distintos a los valores de las demás variables,

head(scale(train_casa, center = TRUE, scale = TRUE),2)
##         preciom  areaconst     banios habitaciones  estrato_3  estrato_4
## [1,] -0.4671681 -0.6915067  0.2824166    0.8353268 -0.6783698 -0.5410995
## [2,]  1.1566928  0.7361690 -0.3684253   -0.7648395 -0.6783698 -0.5410995
##      estrato_5  estrato_6
## [1,]  1.284985 -0.2963263
## [2,]  1.284985 -0.2963263
mod_casas_train <- lm(preciom ~ areaconst + estrato_4 + estrato_5 + estrato_6 + habitaciones + banios, data = train_casa)
summary(mod_casas_train)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato_4 + estrato_5 + estrato_6 + 
##     habitaciones + banios, data = train_casa)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -425.40  -78.23  -11.28   47.94  977.00 
## 
## Coefficients:
##               Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)   -0.60595   20.86128  -0.029             0.976839    
## areaconst      1.05115    0.05379  19.540 < 0.0000000000000002 ***
## estrato_4     63.61121   20.51120   3.101             0.002036 ** 
## estrato_5    115.55208   19.37284   5.965        0.00000000464 ***
## estrato_6    273.74873   31.14725   8.789 < 0.0000000000000002 ***
## habitaciones   3.94653    4.83705   0.816             0.414948    
## banios        22.59433    6.28352   3.596             0.000355 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 157.7 on 500 degrees of freedom
## Multiple R-squared:  0.6937, Adjusted R-squared:   0.69 
## F-statistic: 188.7 on 6 and 500 DF,  p-value: < 0.00000000000000022

Los resultados para el dataset de entrenamiento muestra un aumento en los parámetros incluso el R cuadrado sube del 66% con el dataset de las 722 casas a un R2 de 69% para el train_casas


Punto 6

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

head(scale(test_casa, center = TRUE, scale = TRUE),2)
##         preciom  areaconst    banios habitaciones  estrato_3 estrato_4
## [1,]  1.3923322  0.9514260  2.317868    0.7755171 -0.7302209 -0.520503
## [2,] -0.8754485 -0.6248943 -1.022223   -0.9857806  1.3630790 -0.520503
##      estrato_5  estrato_6
## [1,] -0.768008  3.7802600
## [2,] -0.768008 -0.2633017
predicciones <- predict(object =  mod_casas_train, newdata = test_casa)
predicciones_df <- data.frame(test_casa, predicciones)
head(predicciones_df,3)

En el encabezado de las predicciones se puede observar casas de la zona norte de Cali, las cuales se encuentran en estratos 6 y 3, con áreas de construcción entre los 160 m2 y los 445 m2, teniendo en cuenta que entre más área encontramos más número de baños y habitaciones, y el precio predicho está por encima del precio de entreno para el primer valor del dataset, y por debajo del precio para los 2 siguientes valores, cabe resaltar que hay más valores en el dataframe predicciones_df que se pueden evaluar según algunos requerimientos del cliente más especificamente como el precio, el área y número de habitaciones

Punto 7

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

library(Metrics)
library(kableExtra)
MAE(train_casa$preciom, predicciones)
## [1] 267.3523
rmse(train_casa$preciom, predicciones)
## [1] 355.5563
g1 <- glance(mod_casas)
g2 <- glance(mod_casas_train)


kable(rbind(g1, g2), digits = 2)
r.squared adj.r.squared sigma statistic p.value df logLik AIC BIC deviance df.residual nobs
0.66 0.66 156.88 232.49 0 6 -4670.99 9357.99 9394.64 17596091 715 722
0.69 0.69 157.72 188.72 0 6 -3281.71 6579.42 6613.25 12437583 500 507