El presente informe es presentado por la compañía C&A (Casas y Apartamentos) como respuesta a una carta recibida de la empresa Bayer, solicitando asesoría para la compra de dos viviendas con el objetivo de ubicar a dos de sus empleados y sus familias en la ciudad de Cali, Colombia. Las solicitudes incluyen las siguientes condiciones:
knitr::include_graphics("condiciones_viviendas.png")
Partiendo de esta solicitud, el presente informe se divide en 2 partes, una para cada vivienda. Cada sección presenta 6 puntos fundamentales de análisis de los datos para dar respuesta a los requerimientos del cliente usando Modelos de Regrsión Lineal Múltiple para generar las mejores recomendaciones. Esta técnica permitirá encontrar un modelo matemático que describa el comportamiento de los precios de los inmuebles (variable respuesta) frente al conjunto de características de los mismos (variables predictoras) como el número de habitaciones, número de baños, el área construida, entre otras.
Cada sección se organiza de la siguiente forma: En primer lugar, se presenta la depuración de los datos y construcción del subset de datos que corresponde a la solicitud realizada. Segundo, se realiza un análisis exploratorio de los datos. Tercero, se estima un modelo de regresión múltiple que ayude con el análisis del mercado y a dar respuesta a la empresa Bayer, explicando los resultados del modelo. En cuarto lugar se validan los supuestos del modelo. En el quinto punto se hace una predicción del valor de la vivienda, teniendo en cuenta las características solicitadas y por último se presentan las recomendaciones de viviendas más adecuadas para los trabajadores, teniendo en cuenta la solicitud presentada.
Al final se adjuntan anexos sobre el proceso de limpieza general de la base de datos.
A continuación, se crea el subset base1 con las viviendas que corresponden al primer conjunto de requerimientos.
base1 <- data_clean %>%
filter(tipo == "casa", zona == "zona norte")
tabla1 <- kable(head(base1))
tabla1
| id | zona | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1209 | zona norte | 5 | 320 | 150 | 2 | 4 | 4 | casa | acopi | -76.51341 | 3.47968 |
| 1592 | zona norte | 5 | 780 | 380 | 2 | 3 | 3 | casa | acopi | -76.51674 | 3.48721 |
| 4057 | zona norte | 6 | 750 | 445 | 2 | 7 | 7 | casa | acopi | -76.52950 | 3.38527 |
| 4460 | zona norte | 4 | 625 | 355 | 3 | 5 | 5 | casa | acopi | -76.53179 | 3.40590 |
| 6081 | zona norte | 5 | 750 | 237 | 2 | 6 | 6 | casa | acopi | -76.54044 | 3.36862 |
| 7824 | zona norte | 4 | 600 | 160 | 1 | 4 | 4 | casa | acopi | -76.55210 | 3.42125 |
Ahora, con el fin de visualizar más claramente la oferta, se presenta un mapa donde se distribuyen las viviendas de la zona norte:
color <- colorFactor(palette = c( "navy"), domain = base1$zona)
mapa1 <- leaflet(base1) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~color(zona), radius = 4)
mapa1
La visualización en el mapa nos permite identificar que hay un número considerable de propiedades con errores de codificación en la variable Zona pues, aunque sólo se presenta la zona norte, hay puntos representando viviendas en todas las zonas de la ciudad.
Para corroborar que existe un error se presenta un mapa con todas las 5 zonas disponibles en el dataset, Norte, Sur, Oeste, Oriente y Centro.
colores <- colorFactor(palette = c( "gold","lightgreen", "blue", "red", "purple"), domain = data_clean$zona)
mapa2 <- leaflet(data_clean) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~colores(zona), radius = 3)
mapa2
Al igual que con la zona norte, las cuatro zonas restantes tienen errores en la codificación, en ese sentido surge la necesidad de volver a hacer la codificación de la variable zona. Para los fines de este informe sólo se recodifican las propiedades en las zonas norte y sur, teniendo en cuenta las latitudes y longitudes presentes en la base de datos. Para realizar el reemplazo de estos datos y reorganizar por completo la variable se definen dos cuadrantes, uno para la zona norte y otro para la zona sur.
La zona norte estará contemplada desde la latitud que coincide con la Torre de Cali como el punto más al sur del cuadrante, la longitud que coincide con la Iglesia la Ermita como el punto más al oeste y la longitud que se superpone a la intersección de la autopista oriental con la carrera octava o el Puente de Alfonso López como el punto más al oriente del cuadrante. Se define por las coordenadas:
Latitud más al sur: 3.452595 Longitud del oeste: -76.531996 Longitud del Oriente: -76.486768
base1 <- data_clean %>%
select(-zona) %>%
filter(tipo == "casa", latitud >= 3.452595, longitud >= -76.531996 & longitud <= -76.486768 )
color1 <- colorFactor(palette = c( "navy"), domain = base1$tipo)
mapa1 <- leaflet(base1) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~color1(tipo), radius = 4)
mapa1
Con la reclasificación de las propiedades en la zona norte, usando el cuadrante definido, el número de casas en el norte pasó de 722 a 525, para una disminución de 197 casos. Aunque esto pueda parecer significativo, la depuración es necesaria para garantizar la correcta identificación de la propiedad solicitada por la empresa Bayer. Como se puede apreciar en el mapa, todas las casas dentro del subset están en la zona norte.La variable zona también fue excluida del subset pues, como ya se dijo, no puede confiarse en la codificación de la misma, además todas las casas en este conjunto pertenecen a la zona norte, por lo que no tiene sentido conservar la variable.
Con las bases depuradas y organizadas, podemos corroborar el contenido de la base1 subset con el que se trabaja en esta sección del informe:
tabla1 <- kable(head(base1))
tabla1
| id | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|
| 1209 | 5 | 320 | 150 | 2 | 4 | 4 | casa | acopi | -76.51341 | 3.47968 |
| 1592 | 5 | 780 | 380 | 2 | 3 | 3 | casa | acopi | -76.51674 | 3.48721 |
| 504 | 3 | 180 | 120 | 2 | 3 | 3 | casa | acopi | -76.49768 | 3.47060 |
| 604 | 5 | 520 | 455 | 2 | 5 | 5 | casa | acopi | -76.49966 | 3.46284 |
| 1003 | 3 | 380 | 300 | 2 | 5 | 5 | casa | acopi | -76.50743 | 3.46566 |
| 1840 | 5 | 395 | 165 | 2 | 4 | 4 | casa | acopi | -76.51797 | 3.47651 |
dim(base1)
## [1] 525 11
summary(base1)
## id estrato preciom areaconst parqueaderos
## Min. : 155 3:195 Min. : 100.0 Min. : 30.0 Min. : 1.000
## 1st Qu.: 543 4:115 1st Qu.: 235.0 1st Qu.: 122.0 1st Qu.: 2.000
## Median :1206 5:197 Median : 350.0 Median : 224.0 Median : 2.000
## Mean :1682 6: 18 Mean : 407.6 Mean : 247.1 Mean : 2.135
## 3rd Qu.:2896 3rd Qu.: 505.0 3rd Qu.: 318.0 3rd Qu.: 2.000
## Max. :4483 Max. :1700.0 Max. :1500.0 Max. :10.000
## banios habitaciones tipo barrio
## Min. :1.000 Min. :0.000 Length:525 Length:525
## 1st Qu.:2.000 1st Qu.:2.000 Class :character Class :character
## Median :3.000 Median :3.000 Mode :character Mode :character
## Mean :3.518 Mean :3.514
## 3rd Qu.:4.000 3rd Qu.:4.000
## Max. :9.000 Max. :9.000
## longitud latitud
## Min. :-76.53 Min. :3.453
## 1st Qu.:-76.52 1st Qu.:3.468
## Median :-76.51 Median :3.476
## Mean :-76.51 Mean :3.476
## 3rd Qu.:-76.50 3rd Qu.:3.484
## Max. :-76.49 Max. :3.496
Una vez se cuenta con la base depurada y la reasignación de las propiedades en el mapa, podemos pasar a realizar un análisis exploratorio de los datos, con especial énfasis en conocer mejor las correlaciones que existen entre las variables del dataset. Lo anterior, teniendo en cuenta que la finalidad de este documento es presentar un modelo de regresión lineal múltiple capaz de predecir el precio de una vivienda tomando algunas de sus características, por lo que la variable preciom se comprende como la variable respuesta o dependiente, en tanto el valor de una propiedad depende de la variación de las características de la misma.
Antes de observar las relaciones, exploremos el comportamiento de la variable Precio en un histograma:
base1 %>%
ggplot(aes(preciom)) +
geom_histogram(binwidth = 90,fill = "#95EBDF") +
theme_bw()+
scale_x_continuous(breaks = seq(0, 1800, by = 300)) +
labs(x = "Valor de las propiedades en millones",
y = "Conteo propiedades",
title = "Distribución del valor de las propiedades")
El histograma presenta una distribución irregular de los valores, con un claro sesgo a la izquierda y algunos valores atípicos por encima de los 1000 millones.
Ahora, para empezar con el análisis de las relacines entre las variables, tenemos el área construida y el precio de la vivienda, visualizado mediante un gráfico de dispersión.
plot_ly(base1, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers') %>%
layout(title = "Precio vs Área Construida",
xaxis = list(title = "Área Construida (m²)"),
yaxis = list(title = "Precio (millones)"))
Este gráfico permite observar una posible relación lineal entre las variables, pues entre mayor es el área construida de la propiedad, mayor es el precio en millones de pesos. El gráfico también nos permite observar algunos datos atípicos, por ejemplo, una vivienda de 1500 metros cuadrados con un valor de 1650 millones, ubicada en el extremo superior izquierdo del gráfico.
Una relación que puede resultar interesante es la distribución de los valores de las viviendas según el estrato. A continuación, un gráfico de Cajas y Bigotes para ilustrar esta relación.
plot_ly(base1, x = ~factor(estrato), y = ~preciom, type = 'box') %>%
layout(title = "Distribución del Precio por Estrato",
xaxis = list(title = "Estrato"),
yaxis = list(title = "Precio (millones)"))
Como es de esperarse, las viviendas en el estrato 6 tienen costos significativamente más elevados que en los estratos 3, 4 y 5, además tienen mayor dispersión, representada por una caja más grande. Llama la atención que las cajas y bigotes de los estratos 4 y 5 son medianamente similares y que los estratos 3 y 5 tienen un número significativo de observaciones atípicas, por fuera del rango intercuartílico.
Para conocer mejor la distribución de las casas en el norte con respecto a los estratos, se realiza una gráfica de torta, que muestra la proporción de viviendas para cada estrato dentro del subset base1.
frecuencia_estrato <- as.data.frame(table(base1$estrato))
plot_ly(frecuencia_estrato,
labels = ~Var1,
values = ~Freq,
type = 'pie',
textinfo = 'label+percent',
insidetextorientation = 'radial',
marker = list(colors = c('#4CAF50', '#FF9800', '#2196F3', '#9C27B0')),
hoverinfo = 'text') %>%
layout(title = 'Distribución por Estrato')
Puede verse en el gráfico que hay una cantidad muy similar de viviendas estrato 3 y estrato 5, 37.1 y 37.5 por ciento respectivamente. El siguiente estrato con mayor número de propiedades es el 4, con 21.9% mientras que el estrato con menor número de inmuebles es el estrato 6 con tan sólo 3.43%.
Ahora bien, para tener una visualización más clara de las correlaciones entre las variables cuantitativas y su comportamiento comparado, se presenta la siguiente cuadrícula.
ggpairs(base1[,3:7], title="Correlaciones base1")
El conjunto de gráficos que presenta la cuadricula anterior resulta de gran relevancia pues reúne mucha información. En la diagonal, se presentan las densidades de cada variables, aquí podemos ver que todas tienen un sesgo a la izquierda, mientras que las variables baños y habitaciones tienen una forma bastante irregular. Debajo de la diagonal se encuentran los diagramas de dispersión, donde encontramos de nuevo la relación entre el precio y el área construida. Entre estos gráficos nos interesa observar de cerca la relación entre número de baños y número de habitaciones, pues describe una relación lineal entre las dos variables, que para nuestro interés deberían ser independientes.
Lo anterior se corrobora con los coeficientes de correlación descritos sobre la diagonal, donde las variables habitación y baños alcanzan el 0.990, valor muy cercano a uno que quiere decir que ambas variables están muy correlacionadas. Este vínculo estrecho se puede explicar si pensamos en la finalidad que tienen los baños y las habitaciones en una vivienda y el hecho de que cada habitación pueda estar ocupada por un miembro de la familia y esa persona también necesite un baño.
En lo que se refiere a las otras variables explicativas encontramos relaciones relativamente pequeñas, desde 0.294 entre el número de parqueaderos y el área construida, hasta 0.504 entre el número de baños y el área construida. Ahora bien, el coeficiente de correlación que tienen las variables independientes con la variable respuesta, el precio de la vivienda, es favorable, pero ninguno es muy significativo, el más alto es entre el área construida y el precio en millones de pesos, con 0.742, lo que corrobora lo encontrado con el gráfico de dispersión, una posible relación lineal. El número de baños y de habitaciones tienen coeficientes de 0.532 y 0.527 respectivamente, ambos valores muy cercanos, en tanto estas dos variables tienen una correlación muy alta entre ellas, es necesario seleccionar una de ellas para generar el modelo de regresión lineal múltiple con el objetivo de evitar la multicolinealidad de las variables, es decir, redundar la información que es entregada al modelo.
Para la siguiente sección, donde se estima el modelo, se realiza una nueva modificación de la base1 excluyendo la variable habitaciones, que tiene un valor menor en la correlación con el precio de las viviendas.
Teniendo en cuenta que la variable estrato no corresponde a una variable cuantitativa no se incluyó en el análisis anterior, que utiliza el método de Pearson para calcular las correlaciones. Sin embargo, dado que se contempla utilizar el estrato como variable explicativa en el modelo, se presenta una nueva matriz de correlaciones, esta vez utilizando el método de Spearman, que funciona para describir la correlación con variables ordinales, como es el caso del estrato, que tienen un orden propio de menor a mayor.
#Se genera una variable aparte que no altere el manejo del estrato más adelante
base1$estrato_num <- as.numeric(base1$estrato)
variables_numericas <- base1 %>%
select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato_num)
#Se calcula la correlación con el método de Spearman
matriz_correlacion_spearman <- cor(variables_numericas, method = "spearman")
print(matriz_correlacion_spearman)
## preciom areaconst parqueaderos banios habitaciones
## preciom 1.0000000 0.8525026 0.2999690 0.6558743 0.6507947
## areaconst 0.8525026 1.0000000 0.2764253 0.6180360 0.6103484
## parqueaderos 0.2999690 0.2764253 1.0000000 0.2914853 0.2910203
## banios 0.6558743 0.6180360 0.2914853 1.0000000 0.9916192
## habitaciones 0.6507947 0.6103484 0.2910203 0.9916192 1.0000000
## estrato_num 0.6799673 0.5647589 0.2047748 0.4442343 0.4385411
## estrato_num
## preciom 0.6799673
## areaconst 0.5647589
## parqueaderos 0.2047748
## banios 0.4442343
## habitaciones 0.4385411
## estrato_num 1.0000000
Para el caso del cálculo de la correlación usando el método de Spearman, se encuentra que el estrato no tiene una correlación significativa que pueda interferir con la estimación del modelo. El valor más alto lo adquiere en relación con el precio, 0.679, lo que tiene sentido si se piensa que entre mayor el estrato, mayor será el precio, como se presentó más arriba en el gráfico de cajas y bigotes Distribución de peso por estrato. La relación más baja la tiene con la variable parqueadero, 0.204, que también se explica al pensar que sin importar el estrato una casa debe contar con al menos un parqueadero según la imputación realizada al principio.
A continuación, la base final que servirá de insumo para la estimación del modelo:
head(base1)
## # A tibble: 6 × 12
## id estrato preciom areaconst parqueaderos banios habitaciones tipo barrio
## <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
## 1 1209 5 320 150 2 4 4 casa acopi
## 2 1592 5 780 380 2 3 3 casa acopi
## 3 504 3 180 120 2 3 3 casa acopi
## 4 604 5 520 455 2 5 5 casa acopi
## 5 1003 3 380 300 2 5 5 casa acopi
## 6 1840 5 395 165 2 4 4 casa acopi
## # ℹ 3 more variables: longitud <dbl>, latitud <dbl>, estrato_num <dbl>
Estimación del modelo
Se ejecuta la estimación del modelo para la predicción de la variable respuesta preciom usando las variables independientes seleccionadas en el análisis de datos, es decir: el área construida, el número de baños, el estrato donde se ubica la vivienda y el número de parqueaderos.
regresion_multiple1 <- lm(preciom ~ areaconst + banios + estrato + parqueaderos, data = base1)
summary(regresion_multiple1)
##
## Call:
## lm(formula = preciom ~ areaconst + banios + estrato + parqueaderos,
## data = base1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -838.45 -62.24 -16.61 41.28 953.32
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 16.43464 17.98740 0.914 0.361
## areaconst 0.75129 0.04523 16.609 < 2e-16 ***
## banios 20.74846 5.22537 3.971 8.18e-05 ***
## estrato4 77.42744 16.94199 4.570 6.10e-06 ***
## estrato5 113.16204 15.63129 7.239 1.64e-12 ***
## estrato6 439.69039 37.25013 11.804 < 2e-16 ***
## parqueaderos 27.16314 5.38438 5.045 6.29e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 138.6 on 518 degrees of freedom
## Multiple R-squared: 0.6985, Adjusted R-squared: 0.695
## F-statistic: 200 on 6 and 518 DF, p-value: < 2.2e-16
Análisis
El modelo de regresión lineal múltiple que se presenta arriba puede ser expresado mediante la siguiente ecuación:
preciom = 16.43464 + 0.75129 × areaconst + 20.7484 × banios + 77.42744 × estrato4 + 113.16204 × estrato5 + 439.69039 × estrato6 + 27.16314 × parqueaderos
Aunque la ecuación por sí sola no dice mucho, puede ayudar a comprender cómo se interpretan los coeficientes de estimación para cada variable. En breve, cada coeficiente explica la magnitud en que cambia la variable respuesta (precio) según el cambio en cada variable, cuando las demás se mantienen constantes. Puede ser más claro explicando el coeficiente del área construída:
areaconst (0.75129): Por cada unidad adicional en el área construida (un metro cuadrado adicional), se espera que el precio en millones aumente en 0.75129, cuando se mantienen constantes las demás variables.
Ahora bien, como se comentó en la sección anterior, la variable estrato se incluye en este modelo a través de lo que se conoce como “Variables dummy”, que son variables binarias que indican la pertenencia, o no a la categoría (por ejemplo una casa en estrato 4 tendría un 1 la columna correspondiente a estrato 4 y ceros en las columnas de estrato 3, 5 y 6). Esta clasificación se hace de manera automática en R, que para este caso toma el estrato 3 como la categoría de referencia, desde la que se compara el cambio de los valores de las viviendas.
Lo anterior puede ser más claro viendo en detalle el coeficiente del estrato 4:
estrato4 (77.42744): Si una propiedad está en el estrato 4 (comparado con el estrato 3, que es la categoría de referencia), se espera que el precio en millones aumente en 77.42744, manteniendo constantes las demás variables.
Una última anotación sobre la sección de coeficientes es que todos tienen un p-value muy pequeño, por debajo de 0.005, lo que significa que todos tienen un efecto estadísticamente significativo en el precio de las viviendas. En otras palabras, al menos en primera instancia, parece que todas las variables son valiosas para la estimación de valores de propiedades usando este modelo.
Frente a los otros indicadores retornados con respecto al modelo, se puede encontrar que:
Residuals: Los residuales, que presentan cómo las observaciones individuales se desvían de los valores predichos por el modelo, tienen una distribución cercana a la simétrica, que es lo deseable. La mediana de los residuales es cercana a 0 (-16.61), aunque hay algunos valores extremos (residuales mínimos y máximos).
R-cuadrado (0.6985): Indica que el 69.85% de la variabilidad del precio de los inmuebles se explica por las variables independientes incluidas en el modelo. Esto sugiere que el modelo tiene un buen ajuste, aunque todavía hay un 30.15% de la variabilidad que no es explicada por el modelo.
F-statistic (200): Un valor elevado en el estadístico F, en este caso 200, indica que el modelo se ajusta mejor que un modelo nulo, que sólo cuenta en el intercepto de los datos. Adicionalmente, el p-valor muy bajo (< 2.2e-16) de la prueba F indica que el modelo es significativo, lo que significa que al menos una de las variables independientes tiene un efecto significativo en la variable dependiente.
En últimas, el modelo de regresión lineal múltiple sugiere que todas las variables, asumidas como independientes, incluidas (área construida, número de baños, estrato, y número de parqueaderos) tienen un impacto significativo en el precio de las casas ubicadas en el norte de la ciudad. Además, el ajuste general del modelo es fuerte, explicando aproximadamente el 70% de la variabilidad en los precios. La variable estrato particularmente en los niveles más altos (estrato 5 y 6), tiene un efecto notable en el aumento del precio.
Ahora bien, con el objetivo de tener el mejor modelo con las variables disponibles, se realiza el proceso de Stepwise (en ambas direcciones), donde se examina el efecto que tiene cada variable independiente (predictoras), dentro de el modelo y evalúa el uso de aquellas que son más significativas.Esta validación se hace eliminando una a una las variables y observando el efecto que tiene en la capacidad predictiva del modelo.
modelo_all <- lm(preciom ~ areaconst + banios + estrato + parqueaderos, data = base1)
modelo_step <- step(modelo_all, direction = "both")
## Start: AIC=5185.43
## preciom ~ areaconst + banios + estrato + parqueaderos
##
## Df Sum of Sq RSS AIC
## <none> 9956466 5185.4
## - banios 1 303049 10259515 5199.2
## - parqueaderos 1 489175 10445641 5208.6
## - estrato 3 2903287 12859753 5313.8
## - areaconst 1 5302284 15258750 5407.6
# Resumen del modelo final
modelo_step
##
## Call:
## lm(formula = preciom ~ areaconst + banios + estrato + parqueaderos,
## data = base1)
##
## Coefficients:
## (Intercept) areaconst banios estrato4 estrato5
## 16.4346 0.7513 20.7485 77.4274 113.1620
## estrato6 parqueaderos
## 439.6904 27.1631
El resultado del proceso Stepwise indica que todas las variables presentes en el modelo son relevantes, pues el Criterio de Información de Akaike (AIC en inglés), que evalúa la calidad del modelo (A mayor valor, peor es el modelo), empeora cada vez que se extrae una variable del mismo. Teniendo en cuenta lo anterior, este análisis también refleja que las variables estrato y área construida son las más significativas dentro del modelo, pues su extracción tiene el mayor impacto en el valor del AIC.
Con el objetivo de verificar la veracidad de los resultados del modelo se realiza la validación de los supuestos, lo que puede tener implicaciones sobre su interpretación. La primera herramienta para esta validación será graficar los residuales del modelo:
par(mfrow=c(2,2))
plot(regresion_multiple1)
Supuesto de Normalidad El supuesto de normalidad implica que los errores del modelo, es decir, la varianza que no es explicada por el modelo, están distribuidos de manera normal. Este supuesto puede validarse observando el gráfico Q-Q Residuals, en el caso que los residuales se distribuyesen de forma normal, los puntos seguirían la diagonal en el gráfico. Sin embargo, para este caso el gráfico parece expresar que no sucede de esta manera.
Una segunda forma de validar el supuesto de normalidad es mediante el uso del test de normalidad Shapiro-Wilk.
shapiro.test(regresion_multiple1$residuals)
##
## Shapiro-Wilk normality test
##
## data: regresion_multiple1$residuals
## W = 0.81745, p-value < 2.2e-16
El p-value extremadamente bajo, como este, indica que hay suficiente evidencia para rechazar la hipótesis nula de que los residuales siguen una distribución normal. En otras palabras, los resultados sugieren que los residuales no son normalmente distribuidos.
Supuesto de linealidad El supuesto de linealidad implica que existe una relación lineal entre las variables independientes (predictoras) y la variable dependiente, en este caso el precio de las viviendas. Podemos encontrar evidencias de este supuesto en el gráfico de dispersión Precio vs Área Construida, presentado en el punto B de esta sección, sin embargo, no es tan clara la relación lineal con el resto de las variables. Una forma de validar este supuesto, una vez se ha generado el modelo, es a través del gráfico Q-Q Resiguals que, al igual que con la normalidad de los residuales, si las observaciones se alinean con la diagonal predictora, podemos hablar de que se cumple el supuesto. Sin embargo, como sucede con la normalidad, este supuesto no se cumple del todo, particularmente con los valores más extremos.
Supuesto de Homocedasticidad (variación constante de los residuales) Al representar los residuos frente a los valores ajustados por el modelo, los primeros deberían distribuírse de forma aleatoria en torno a cero, manteniendo aproximadamente la misma variabilidad a lo largo del eje X. En este caso, en el gráfico Residuals vs Fitted, se observa un parón, una forma cónica con mayor concentración a la izquierda del gráfico, lo que significa que la variabilidad es dependiente del valor ajustado y por lo tanto no hay homocedasticidad.
Multicolinealidad En la etapa de análisis de los datos se exploró la correlación entre las variables, de este proceso se concluyó que era necesario eliminar la variable habitaciones del subset de datos por su alta correlación con la variable baños. Hasta ese punto, se espera que no haya una colinealidad significativa entre las variables, sin embargo, existe la posibilidad de validar si hay otras formas en las que se introduzca multicolinealidad al modelo, usando el Factor de Inflación de Varianza (VIF), que indica cuánto se inflan las varianzas de los coeficientes de regresión debido a la colinealidad entre las variables predictoras.
vif(regresion_multiple1)
## GVIF Df GVIF^(1/(2*Df))
## areaconst 1.546574 1 1.243613
## banios 1.459022 1 1.207900
## estrato 1.383143 3 1.055548
## parqueaderos 1.163520 1 1.078666
La manera de interpretar el VIF es que los valores entre 1 y 5 indican una baja correlación entre las variables independientes, por lo que puede decirse que no hay multicolinealidad entre las variables empleadas en el modelo.
Sugerencias de mejora Una posibilidad para mejorar los supuestos del modelo es simplificarlo un poco, por ejemplo, eliminando la variable baño, que según los análisis anteriores puede ser la que menos aporta al modelo en general. Además, la transformación logarítmica de algunas variables podría mejorar la distribución de los datos y la relación lineal con la variable objetivo. Es importante identificar y abordar los valores atípicos que podrían influir significativamente en los resultados del análisis, ya que estos pueden distorsionar las estimaciones y afectar la interpretación de los resultados.
Una vez examinado con detalle el modelo, evaluados los supuestos y generadas algunas recomendaciones para su mejora, podemos pasar a trabajar la predicción de los valores de la vivienda con las características solicitadas. Para ello se divide el dataset en dos conjuntos de datos, uno para el entrenamiento del modelo (train_data), que representa el 70% de los datos o 368 observaciones, y otro para probar su eficiencia, precisión y ajuste (test_data), que representa el 30% de los datos o 157 observaciones. Los conjuntos de datos se generan al azar para asegurar que el proceso no resulte viciado a una respuesta en particular.
#División de los datos
set.seed(123)
train_indices <- sample(1:nrow(base1), size = 0.7 * nrow(base1))
#Conjunto de entrenamiento con los índices generados 70% del dataset
train_data <- base1[train_indices, ]
#Conjunto de prueba con los índices generados 30% del dataset
test_data <- base1[-train_indices, ]
A continuación, se entrena el modelo nuevamente, con las variables validadas en el paso anterior y utilizando el conjunto de datos de entrenamiento.
regresion_multiple1_train <- lm(preciom ~ areaconst + banios + estrato + parqueaderos, data = train_data)
summary(regresion_multiple1_train)
##
## Call:
## lm(formula = preciom ~ areaconst + banios + estrato + parqueaderos,
## data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -835.14 -63.55 -18.95 42.32 946.71
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 12.83827 23.64315 0.543 0.587465
## areaconst 0.74546 0.05329 13.988 < 2e-16 ***
## banios 23.38737 6.92680 3.376 0.000815 ***
## estrato4 76.84568 21.46961 3.579 0.000392 ***
## estrato5 121.52767 20.53776 5.917 7.63e-09 ***
## estrato6 372.90534 50.20894 7.427 8.12e-13 ***
## parqueaderos 25.28932 7.17159 3.526 0.000476 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 148.8 on 360 degrees of freedom
## Multiple R-squared: 0.6675, Adjusted R-squared: 0.6619
## F-statistic: 120.4 on 6 and 360 DF, p-value: < 2.2e-16
El modelo entrenado con el primer conjunto de datos tiene un desempeño un poco más bajo que el inicial, donde se empleó el conjunto de datos completo. Mientras el valor de \(r^{2}\) para el primer modelo es de 0.698, el del modelo entrenado con el 70% de los datos tiene un valor de 0.667, esto implicaría una reducción del 3% en la capacidad del modelo de explicar la variación de los datos. Sin embargo, el verdadero valor de la división de los datos está en examinar cómo se comporta con el conjunto de datos de prueba, como se muestra a continuación.
predicciones <- predict(regresion_multiple1_train, newdata = test_data)
# Evaluar el rendimiento del modelo, por ejemplo, usando el RMSE
rmse <- sqrt(mean((test_data$preciom - predicciones)^2))
print(paste("Diferencia promedio entre los valores predichos y los reales (RMSE):", rmse))
## [1] "Diferencia promedio entre los valores predichos y los reales (RMSE): 114.974518386196"
print(paste("El promedio del valor de las propiedades de la base original es de:", mean(test_data$preciom)))
## [1] "El promedio del valor de las propiedades de la base original es de: 399.930379746835"
Para evaluar la precisión del modelo entrenado se calcula el Root Mean Square Error, que es la raíz cuadrada de la media de los errores del modelo al cuadrado. En otras palabras, la diferencia promedio que existe entre los valores predichos por el modelo y los errores reales. En este caso, la diferencia es de casi 115 millones de pesos, como se presenta arriba. Esta diferencia se considera significativa, teniendo en cuenta que esto implica que, en promedio, la diferencia de los valores predichos por el modelo tendrá una diferencia de 115 millones con los valores reales.
Ahora bien, si analizamos el rango de la variable preciom podemos darnos cuenta de que es significativamente amplio (entre 110 y 1600 millones) pues, como se ha mencionado antes, hay un número significativo de datos atípicos.
summary(test_data$preciom)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 110.0 246.2 350.0 399.9 497.0 1600.0
Esta nueva consideración puede ayudar con la interpretación de los resultados de las predicciones del modelo pues, aunque en promedio la diferencia es significativa, el RMSE es relativamente bajo con relación al límite superior del rango. Lo anterior significa que la diferencia entre las predicciones será mayor para las viviendas con un costo elevado y, probablemente, sea menor para las viviendas con costos más cercanos al promedio. En tanto el valor del RMSE (114.9) equivale al 28% del promedio real de la variable respuesta (407.6), podemos estimar que el modelo tiene un margen de error de alrededor del 28%. Este análisis puede visualizarse mejor en el siguiente gráfico.
ggplot(data = test_data, aes(x = preciom, y = predicciones)) +
geom_point(color = 'blue', alpha = 0.6) +
geom_abline(slope = 1, intercept = 0, color = 'red', linetype = 'dashed') +
labs(title = 'Valores Reales vs. Predicciones',
x = 'Valor Real de Precio',
y = 'Valor Predicho de Precio') +
theme_minimal()
La línea roja representa los valores predichos por el modelo, mientras los puntos azules son las observaciones reales dentro del conjunto de datos de prueba. Aquí es posible observar que aunque el modelo hace un buen trabajo describiendo el comportamiento de las viviendas con valores menores a 400 millones, la realidad es que con los datos superiores tiene dificultades significativas, alejándose los valores reales de los predichos.
Predicción de las propiedades con las características solicitadas La primera de ellas debe tener un área construida de 200 metros cuadrados, 1 parqueadero, 2 baños, 4 habitaciones y estar en los estratos 4 o 5.
prediccion_estrato_4 = predict(regresion_multiple1_train,list(areaconst = 200,parqueaderos = 1, banios = 2,
habitaciones = 4, estrato = "4"))
prediccion_estrato_4
## 1
## 310.8401
La vivienda con las características presentadas y en estrato 4 tendría un valor aproximado de $310’840.100 Ahora, la predicción de una vivienda con las mismas características en estrato 5:
prediccion_estrato_5 <- predict(regresion_multiple1_train,list(areaconst = 200,parqueaderos = 1, banios = 2,
habitaciones = 4, estrato = "5"))
prediccion_estrato_5
## 1
## 355.5221
La vivienda con las características presentadas y en estrato 5 tendría un valor aproximado de $355’522.100
Finalmente, se utilizará el modelo entrenado (regresión_multiple_train) para encontrar las 5 mejores viviendas que respondan a la solicitud de la empresa Bayer. Para ello se genera una nueva base con las viviendas que cumplan con las características planteadas:
viviendas_filtradas_base1 <- base1 %>%
filter(areaconst >= 200, parqueaderos >= 1, banios >= 4, habitaciones >= 4, estrato_num >= 2, estrato_num <= 3)
dim(viviendas_filtradas_base1)
## [1] 148 12
46 de las 525 viviendas en labase cumplen con las características de la solicitud. A continuación, se utiliza este nuevo conjunto para seleccionar las 5 propiedades que tengan el precio más cercano a las predicciones realizadas por el modelo, restando al valor de cada propiedad el valor predicho por el modelo en la sección anterior (promediando los valores de los estratos 4 y 5):
viviendas_seleccionadas_base1 <- viviendas_filtradas_base1 %>%
mutate(diferencia = abs((prediccion_estrato_5 + prediccion_estrato_4)/2 - preciom)) %>%
arrange(diferencia) %>%
head(5)
viviendas_seleccionadas_base1
## # A tibble: 5 × 13
## id estrato preciom areaconst parqueaderos banios habitaciones tipo barrio
## <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
## 1 4267 5 335 202 1 4 4 casa el bos…
## 2 1849 5 330 246 2 4 4 casa prados…
## 3 852 5 340 208 2 6 6 casa el bos…
## 4 3453 5 340 240 2 5 5 casa la cam…
## 5 3101 5 340 355 2 5 5 casa san vi…
## # ℹ 4 more variables: longitud <dbl>, latitud <dbl>, estrato_num <dbl>,
## # diferencia <dbl>
#select(id, areaconst, parqueaderos, banios, habitaciones, estrato, preciom, predicted_price)
Se observan las 5 opciones de vivienda que se acercan más al valor predicho. A primera vista podemos encontrar que todas superan el valor de los 333 millones, que es el promedio de las viviendas estrato 4 y 5, lo que puede explicarse por el hecho de que sólo una de las viviendas presentadas tiene un solo parqueadero y ninguna tiene menos de 2 baños por lo que, según el modelo, se elevaría un poco el precio. Sin embargo, todas las viviendas presentadas están por debajo de los 350 millones de pesos, que es el valor del prestamo preaprobado para la familia. Se presenta un mapa con la ubicación de cada una de las propiedades para facilitar la selección.
color <- colorFactor(palette = c( "blue"), domain = viviendas_seleccionadas_base1$tipo)
mapa3 <- leaflet(viviendas_seleccionadas_base1) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~color(tipo), radius = 4)
mapa3
Como se dijo antes, cualquiera de las 5 viviendas presentadas cumple con los requerimientos mínimos presentados por la empresa para la vivienda de esta familia, además de encontrarse todas en el estrato 5. Sin embargo, la vivienda con id 1849 tiene el menor de todos los costos, dispone de dos parqueaderos, 4 baños y las 4 habitaciones deseadas, tiene la particularidad de estar ubicada en el barrio Prados del norte, cerca de vías principales de la zona norte de la ciudad. Por otro lado, está la vivienda con id 4267, que tiene el segundo valor más bajo del conjunto, superando la anterior sólo por 5 millones de pesos, esta cuenta con un sólo parqueadero, pero también cuenta con 4 baños y 4 habitaciones, esta vivienda se encuentra en el barrio El Bosque que tiene la característica de ser más campestre que Prados del norte, pero más alejado de las vías principales.
En conclusión, el modelo generado tiene una capacidad de respuesta aceptable, a pesar de no cumplir a cabalidad todos los supuestos, lo que lo hace más inexacto con los valores extremos. Para el caso solicitado, una vivienda entre los 300 y 350 millones de pesos funcionó bastante bien, generando recomendaciones viables, que se acomodan a la solicitud del cliente y son asequibles para comprarse con el crédito de vivienda que tienen aprobado. Aun así, es importante ser cuidadosos con otras predicciones que se hagan utilizando este modelo, particularmente aquellas que impliquen viviendas con costos muy elevados.
Al igual que con los casos de las propiedades en la zona norte, se realiza una depuración de los apartamentos en la zona sur. El área en este caso estará contemplada entre la latitud que coincide con el Estadio Pascual Guerrero como el punto más al norte del cuadrante, la longitud que coincide con el Coliseo del pueblo como el punto más al oeste y la longitud que se alinea con la carrera 50 en el barrio Valle de Lili, pues esto ayudaría a incluir la mayoría de este barrio que está en crecimiento y tiene propiedades valiosas para el análisis. El cuadrante del sur se define por las coordenadas:
Latitud más al norte: 3.428619 Longitud del oeste: -76.551728 Longitud del Oriente: -76.514218
base2 <- data_clean %>%
filter(tipo == "apartamento", zona == "zona sur")
base2 <- data_clean %>%
select(-zona) %>%
filter(tipo == "apartamento", latitud <= 3.428619, longitud >= -76.551728 & longitud <= -76.514218)
color2 <- colorFactor(palette = c("violet"), domain = base2$tipo)
mapa3 <- leaflet(base2) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~color2(tipo), radius = 4)
mapa3
Similar a lo sucedido con la base1, la reclasificación de las propiedades del sur generó una disminución de casos para el segundo subset, en esta oportunidad se pasó de 2787 instancias a 2501, para una disminución de 286 propiedades, quedando con un dataset mucho más grande que el anterior. Aunque se trata de una perdida más grande qeu en el caso del norte, esta depuración es necesaria para garantizar la correcta identificación de la propiedad solicitada por la empresa Bayer. Como se puede apreciar en el mapa de arriba, todos los apartamentos dentro del subset pertenecen a la zona sur.
Con las bases depuradas y organizadas, podemos corroborar el contenido de la base2 subset con el que se trabaja en esta sección del informe:
tabla2 <- kable(head(base2))
tabla2
| id | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|
| 1724 | 5 | 240 | 87 | 1 | 3 | 3 | apartamento | acopi | -76.51700 | 3.36971 |
| 2326 | 4 | 220 | 52 | 2 | 2 | 2 | apartamento | acopi | -76.51974 | 3.42627 |
| 4386 | 5 | 310 | 137 | 2 | 3 | 3 | apartamento | acopi | -76.53105 | 3.38296 |
| 5424 | 4 | 320 | 108 | 2 | 3 | 3 | apartamento | acopi | -76.53638 | 3.40770 |
| 6271 | 5 | 385 | 103 | 2 | 2 | 2 | apartamento | acopi | -76.54173 | 3.42400 |
| 6857 | 3 | 100 | 49 | 1 | 1 | 1 | apartamento | acopi | -76.54531 | 3.37775 |
dim(base2)
## [1] 2501 11
summary(base2)
## id estrato preciom areaconst parqueaderos
## Min. :1250 3:181 Min. : 70.0 Min. : 40.00 Min. : 1.000
## 1st Qu.:2490 4:943 1st Qu.: 175.0 1st Qu.: 65.00 1st Qu.: 1.000
## Median :4044 5:929 Median : 250.0 Median : 85.00 Median : 1.000
## Mean :4219 6:448 Mean : 303.3 Mean : 98.21 Mean : 1.354
## 3rd Qu.:5826 3rd Qu.: 340.0 3rd Qu.:110.00 3rd Qu.: 2.000
## Max. :7740 Max. :1750.0 Max. :932.00 Max. :10.000
## banios habitaciones tipo barrio
## Min. :1.000 Min. :0.000 Length:2501 Length:2501
## 1st Qu.:2.000 1st Qu.:2.000 Class :character Class :character
## Median :2.000 Median :2.000 Mode :character Mode :character
## Mean :2.501 Mean :2.501
## 3rd Qu.:3.000 3rd Qu.:3.000
## Max. :8.000 Max. :8.000
## longitud latitud
## Min. :-76.55 Min. :3.334
## 1st Qu.:-76.54 1st Qu.:3.369
## Median :-76.53 Median :3.379
## Mean :-76.53 Mean :3.382
## 3rd Qu.:-76.52 3rd Qu.:3.397
## Max. :-76.51 Max. :3.428
Una vez se cuenta con la base depurada y la reasignación de las propiedades en el mapa, podemos pasar a realizar un análisis exploratorio de los datos, con especial énfasis en conocer mejor las correlaciones que existen entre las variables del dataset.
Antes de observar las relaciones, exploremos el comportamiento de la variable Precio en un histograma:
base2 %>%
ggplot(aes(preciom)) +
geom_histogram(binwidth = 90,fill = "#95EBDF") +
theme_bw()+
scale_x_continuous(breaks = seq(0, 1800, by = 300)) +
labs(x = "Valor de las propiedades en millones",
y = "Conteo propiedades",
title = "Distribución del valor de las propiedades")
El histograma presenta una distribución un poco más concentrada de los valores, en comparación con la base1, con un claro sesgo a la izquierda y algunos valores atípicos por encima de los 1200 millones.
Ahora, para empezar con el análisis de las relacines entre las variables, tenemos el área construida y el precio de la vivienda, visualizado mediante un gráfico de dispersión.
plot_ly(base2, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers') %>%
layout(title = "Precio vs Área Construida",
xaxis = list(title = "Área Construida (m²)"),
yaxis = list(title = "Precio (millones)"))
Este gráfico permite observar una posible relación lineal entre las variables, caso similar al anterior, pues entre mayor es el área construida de la propiedad, mayor es el precio en millones de pesos, sin embargo, en esta oportunidad, el aumento en el valor de la vivienda con relación al área cosntruida parece ser mayor. El gráfico también nos permite observar algunos datos atípicos, por ejemplo, viviendas de más de 1500 millones de pesos, o algunas de más de 600 metros cuadrados pero con valores entre los 200 y 400 millones de pesos.
Una relación que puede resultar interesante es la distribución de los valores de las viviendas según el estrato. A continuación, un gráfico de Cajas y Bigotes para ilustrar esta relación.
plot_ly(base1, x = ~factor(estrato), y = ~preciom, type = 'box') %>%
layout(title = "Distribución del Precio por Estrato",
xaxis = list(title = "Estrato"),
yaxis = list(title = "Precio (millones)"))
Como es de esperarse, las viviendas en el estrato 6 tienen costos significativamente más elevados que en los estratos 3, 4 y 5, además tienen mayor dispersión, representada por una caja más grande.
Para conocer mejor la distribución de las casas en el norte con respecto a los estratos, se realiza una gráfica de torta, que muestra la proporción de viviendas para cada estrato dentro del subset base2.
frecuencia_estrato <- as.data.frame(table(base2$estrato))
plot_ly(frecuencia_estrato,
labels = ~Var1,
values = ~Freq,
type = 'pie',
textinfo = 'label+percent',
insidetextorientation = 'radial',
marker = list(colors = c('#4CAF50', '#FF9800', '#2196F3', '#9C27B0')),
hoverinfo = 'text') %>%
layout(title = 'Distribución por Estrato')
La distribución de los valores es muy diferente a la de la base1. Puede verse en el gráfico que hay una cantidad muy similar de viviendas estrato 4 y estrato 5, 37.7 y 37.1 por ciento respectivamente. El siguiente estrato con mayor número de propiedades es el 6, con 21.9% mientras que el estrato con menor número de inmuebles es el estrato 3 con tan sólo 7.24%. Esta información nos hace pensar que las viviendas en el sur de la ciudad pueden tener un costo promedio mayor por cuenta de un mayor número de propiedades en estratos más altos.
Ahora bien, para tener una visualización más clara de las correlaciones entre las variables cuantitativas y su comportamiento comparado, se presenta la siguiente cuadrícula.
ggpairs(base2[,3:7], title="Correlaciones base1")
El conjunto de gráficos que presenta la cuadricula anterior resulta de gran relevancia pues reúne mucha información. En la diagonal, se presentan las densidades de cada variables, aquí podemos ver que todas tienden a acumular los datos a la izquierda, mientras que las variables baños y habitaciones tienen una forma irregular por cuenta de ser variables discretas, no continuas como el precio y el área construida. Debajo de la diagonal se encuentran los diagramas de dispersión, donde encontramos de nuevo la relación entre el precio y el área construida. Entre estos gráficos nos interesa observar de cerca la relación entre número de baños y número de habitaciones, pues describe nuevamente una relación lineal entre las dos variables, que para nuestro interés deberían ser independientes, evitando el problema de la colinealidad.
Lo anterior se corrobora con los coeficientes de correlación descritos sobre la diagonal, donde las variables habitación y baños alcanzan el 0.996, situación similar a la base1. Este valor es muy cercano a uno que quiere decir que ambas variables están muy correlacionadas.
En lo que se refiere a las otras variables explicativas encontramos relaciones que probablemente no describan un vínculo lineal entre las variables, pero son más elevadas que en el caso anterior. Por ejemplo, entre el número de parqueaderos y el área construida hay una correlación de 0.604, mientras que entre el número de baños y el área construida hay una correlación de 0.680. Ahora bien, el coeficiente de correlación que tienen las variables independientes con la variable respuesta, el precio de la vivienda, es favorable, incluso más que para la base1, el más alto nuevamente es entre el área construida y el precio en millones de pesos, con 0.763, lo que corrobora lo encontrado con el gráfico de dispersión, una relación cecana a la lineal. El número de baños y de habitaciones tienen coeficientes de 0.740 y 0.738 respectivamente, ambos valores muy cercanos, en tanto estas dos variables tienen una correlación muy alta entre ellas, es necesario seleccionar una de las dos para generar el modelo de regresión lineal múltiple con el objetivo de evitar la multicolinealidad de las variables, es decir, redundar la información que es entregada al modelo.
Para la siguiente sección, donde se estima el modelo, se realiza una nueva modificación de la base2 excluyendo la variable habitaciones, que tiene un valor menor en la correlación con el precio de las viviendas.
Teniendo en cuenta que la variable estrato no corresponde a una variable cuantitativa no se incluyó en el análisis anterior, que utiliza el método de Pearson para calcular las correlaciones. Sin embargo, dado que se contempla utilizar el estrato como variable explicativa en el modelo, se presenta una nueva matriz de correlaciones, esta vez utilizando el método de Spearman, que funciona para describir la correlación con variables cualitativas, ordinales, como es el caso del estrato, que tienen un orden propio de menor a mayor.
#Se genera una variable aparte que no altere el manejo del estrato más adelante
base2$estrato_num <- as.numeric(base2$estrato)
variables_numericas <- base2 %>%
select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato_num)
#Se calcula la correlación con el método de Spearman
matriz_correlacion_spearman <- cor(variables_numericas, method = "spearman")
print(matriz_correlacion_spearman)
## preciom areaconst parqueaderos banios habitaciones
## preciom 1.0000000 0.8707699 0.6696960 0.7187042 0.7157109
## areaconst 0.8707699 1.0000000 0.6480456 0.7614030 0.7604167
## parqueaderos 0.6696960 0.6480456 1.0000000 0.5779257 0.5785143
## banios 0.7187042 0.7614030 0.5779257 1.0000000 0.9956487
## habitaciones 0.7157109 0.7604167 0.5785143 0.9956487 1.0000000
## estrato_num 0.7599198 0.6469787 0.5394789 0.5784480 0.5754107
## estrato_num
## preciom 0.7599198
## areaconst 0.6469787
## parqueaderos 0.5394789
## banios 0.5784480
## habitaciones 0.5754107
## estrato_num 1.0000000
Para el caso del cálculo de la correlación usando el método de Spearman, se encuentra que el estrato no tiene una correlación significativa que pueda interferir con la estimación del modelo. El valor más alto lo adquiere en relación con el precio, 0.759, al igual como sucedió con el primer caso y como se presentó en el gráfico de cajas y bigotes más arriba. La relación más baja la tiene nuevamente con la variable parqueadero, 0.539, que también se explica al pensar que sin importar el estrato un apartamento debe contar con al menos un parqueadero según la imputación realizada al principio.
A continuación, la base final que servirá de insumo para la estimación del modelo para el segundo caso, donde se trabaja sólo con apartamentos en la zona sur de la ciudad:
head(base2)
## # A tibble: 6 × 12
## id estrato preciom areaconst parqueaderos banios habitaciones tipo barrio
## <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
## 1 1724 5 240 87 1 3 3 apart… acopi
## 2 2326 4 220 52 2 2 2 apart… acopi
## 3 4386 5 310 137 2 3 3 apart… acopi
## 4 5424 4 320 108 2 3 3 apart… acopi
## 5 6271 5 385 103 2 2 2 apart… acopi
## 6 6857 3 100 49 1 1 1 apart… acopi
## # ℹ 3 more variables: longitud <dbl>, latitud <dbl>, estrato_num <dbl>
Estimación del modelo
Se ejecuta la estimación del modelo para la predicción de la variable respuesta preciom usando las variables independientes seleccionadas en el análisis de datos, es decir: el área construida, el número de baños, el estrato donde se ubica la vivienda y el número de parqueaderos.
regresion_multiple2 <- lm(preciom ~ areaconst + banios + estrato + parqueaderos, data = base2)
summary(regresion_multiple1)
##
## Call:
## lm(formula = preciom ~ areaconst + banios + estrato + parqueaderos,
## data = base1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -838.45 -62.24 -16.61 41.28 953.32
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 16.43464 17.98740 0.914 0.361
## areaconst 0.75129 0.04523 16.609 < 2e-16 ***
## banios 20.74846 5.22537 3.971 8.18e-05 ***
## estrato4 77.42744 16.94199 4.570 6.10e-06 ***
## estrato5 113.16204 15.63129 7.239 1.64e-12 ***
## estrato6 439.69039 37.25013 11.804 < 2e-16 ***
## parqueaderos 27.16314 5.38438 5.045 6.29e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 138.6 on 518 degrees of freedom
## Multiple R-squared: 0.6985, Adjusted R-squared: 0.695
## F-statistic: 200 on 6 and 518 DF, p-value: < 2.2e-16
Análisis
El modelo de regresión lineal múltiple que se presenta arriba puede ser expresado mediante la siguiente ecuación:
preciom = -89.07315 + 1.26651 × areaconst + 40.66962 × banios + 32.80550 × estrato4 + 54.97333 × estrato5 + 201.11150 × estrato6 + 71.96298 × parqueaderos
Aunque la ecuación por sí sola no dice mucho, puede ayudar a comprender cómo se interpretan los coeficientes de estimación para cada variable. Recordemos que cada coeficiente explica la magnitud en que cambia la variable respuesta (precio) según el cambio en cada variable, cuando las demás se mantienen constantes. Puede ser más claro explicando el coeficiente del área construída:
areaconst (1.26651): Por cada unidad adicional en el área construida (un metro cuadrado adicional), se espera que el precio en millones aumente en 1.26651, cuando se mantienen constantes las demás variables.
Ahora bien, como se comentó en la sección anterior, la variable estrato se incluye en este modelo a través de lo que se conoce como “Variables dummy”, que son variables binarias que indican la pertenencia, o no a la categoría (por ejemplo una casa en estrato 4 tendría un 1 la columna correspondiente a estrato 4 y ceros en las columnas de estrato 3, 5 y 6). Esta clasificación se hace de manera automática en R, que para este caso toma el estrato 3 como la categoría de referencia, desde la que se compara el cambio de los valores de las viviendas.
Lo anterior puede ser más claro viendo en detalle el coeficiente del estrato 4:
estrato4 (32.80550): Si una propiedad está en el estrato 4 (comparado con el estrato 3, que es la categoría de referencia), se espera que el precio en millones aumente en 32.80550, manteniendo constantes las demás variables.
Una última anotación sobre la sección de coeficientes es que todos tienen un p-value muy pequeño, por debajo de 0.005, lo que significa que todos tienen un efecto estadísticamente significativo en el precio de las viviendas. En otras palabras, al menos en primera instancia, parece que todas las variables son valiosas para la estimación de valores de propiedades usando este modelo.
Frente a los otros indicadores retornados con respecto al modelo, se puede encontrar que:
Residuals: Los residuales, que presentan cómo las observaciones individuales se desvían de los valores predichos por el modelo, tienen una distribución más simétrica que para el caso anterior, lo que es buena señal. La mediana de los residuales es aún más cercana a 0 (-3.45). Los valores mínimos y máximos de los residuales reflejan una alta dispersión.
R-cuadrado (0.792): Indica que el 79.2% de la variabilidad del precio de los inmuebles se explica por las variables independientes incluidas en el modelo. Esto sugiere que el modelo tiene un buen ajuste, aunque todavía hay un 20.8% de la variabilidad que no es explicada por el modelo.
F-statistic (200): Un valor elevado en el estadístico F, en este caso 1583, indica que el modelo se ajusta mejor que un modelo nulo, que sólo cuenta en el intercepto de los datos. Adicionalmente, el p-valor muy bajo (< 2.2e-16) de la prueba F indica que el modelo es significativo, lo que implica que al menos una de las variables independientes tiene un efecto significativo en la variable dependiente, aunque, como veremos, todas las variables del modelo tienen un efecto considerable.
En últimas, el modelo de regresión lineal múltiple sugiere que todas las variables, asumidas como independientes, incluidas (área construida, número de baños, estrato, y número de parqueaderos) tienen un impacto significativo en el precio de las casas ubicadas en el norte de la ciudad. Además, el ajuste general del modelo es fuerte, explicando aproximadamente el 79% de la variabilidad en los precios. La variable estrato en el nivel más alto, estrato 6, tiene el mayor efecto en el aumento del precio, mientras que la variable parqueaderos tiene el segundo lugar en cuanto al impacto sobre la variable respuesta.
Ahora bien, con el objetivo de tener el mejor modelo con las variables disponibles, se realiza el proceso de Stepwise (en ambas direcciones), donde se examina el efecto que tiene cada variable independiente (predictoras), dentro de el modelo y evalúa el uso de aquellas que son más significativas. Esta validación se hace eliminando una a una las variables y observando el efecto que tiene en la capacidad predictiva del modelo.
modelo_all <- lm(preciom ~ areaconst + banios + estrato + parqueaderos, data = base2)
modelo_step <- step(modelo_all, direction = "both")
## Start: AIC=22581.36
## preciom ~ areaconst + banios + estrato + parqueaderos
##
## Df Sum of Sq RSS AIC
## <none> 20744275 22581
## - banios 1 1560715 22304990 22761
## - parqueaderos 1 2668066 23412341 22882
## - areaconst 1 5458989 26203264 23164
## - estrato 3 6050391 26794666 23215
# Resumen del modelo final
modelo_step
##
## Call:
## lm(formula = preciom ~ areaconst + banios + estrato + parqueaderos,
## data = base2)
##
## Coefficients:
## (Intercept) areaconst banios estrato4 estrato5
## -89.073 1.267 40.670 32.806 54.973
## estrato6 parqueaderos
## 201.112 71.963
El resultado del proceso Stepwise indica que todas las variables presentes en el modelo son relevantes, pues el Criterio de Información de Akaike (AIC en inglés), que evalúa la calidad del modelo (A mayor valor, peor es el modelo), empeora cada vez que se extrae una variable del mismo. Teniendo en cuenta lo anterior, este análisis también refleja que las variables estrato y área construida son las más significativas dentro del modelo, pues su extracción tiene el mayor impacto en el valor del AIC. Como era de esperarse, para los dos casos, norte y sur, las variables tienen un efecto similar en el comportamiento del modelo.
Con el objetivo de verificar la veracidad de los resultados del modelo se realiza la validación de los supuestos, lo que puede tener implicaciones sobre su interpretación. La primera herramienta para esta validación será graficar los residuales del modelo:
par(mfrow=c(2,2))
plot(regresion_multiple2)
Supuesto de Normalidad El supuesto de normalidad implica que los errores del modelo, es decir, la varianza que no es explicada por el modelo, están distribuidos de manera normal. Este supuesto puede validarse observando el gráfico Q-Q Residuals, en el caso que los residuales se distribuyesen de forma normal, los puntos seguirían la diagonal en el gráfico. Sin embargo, para este caso el gráfico parece expresar que no sucede de esta manera, los datos más en los extremos tienen un efecto de distorsión aun mayor que para el caso de la base1.
Una segunda forma de validar el supuesto de normalidad es mediante el uso del test de normalidad Shapiro-Wilk.
shapiro.test(regresion_multiple2$residuals)
##
## Shapiro-Wilk normality test
##
## data: regresion_multiple2$residuals
## W = 0.77085, p-value < 2.2e-16
El p-value extremadamente bajo, como este, indica que hay suficiente evidencia para rechazar la hipótesis nula de que los residuales siguen una distribución normal. En otras palabras, los resultados sugieren que los residuales no son normalmente distribuidos.
Supuesto de linealidad El supuesto de linealidad implica que existe una relación lineal entre las variables independientes (predictoras) y la variable dependiente, en este caso el precio de las viviendas. Podemos encontrar evidencias de este supuesto en el gráfico de dispersión Precio vs Área Construida, presentado en el punto B de esta sección, sin embargo, no es tan clara la relación lineal con el resto de las variables. Una forma de validar este supuesto, una vez se ha generado el modelo, es a través del gráfico Q-Q Resiguals que, al igual que con la normalidad de los residuales, si las observaciones se alinean con la diagonal predictora, podemos hablar de que se cumple el supuesto. Sin embargo, como sucede con la normalidad, este supuesto no se cumple del todo, particularmente con los valores más extremos.
Supuesto de Homocedasticidad (variación constante de los residuales) Al representar los residuos frente a los valores ajustados por el modelo, los primeros deberían distribuírse de forma aleatoria en torno a cero, manteniendo aproximadamente la misma variabilidad a lo largo del eje X. En este caso, en el gráfico Residuals vs Fitted, se observa un parón, una forma cónica con mayor concentración a la izquierda del gráfico, al igual que con el modelo anterior, lo que significa nuevamente que la variabilidad es dependiente del valor ajustado y por lo tanto no hay homocedasticidad.
Multicolinealidad En la etapa de análisis de los datos se exploró la correlación entre las variables, de este proceso se concluyó que era necesario eliminar la variable habitaciones del subset de datos por su alta correlación con la variable baños. Hasta ese punto, se espera que no haya una colinealidad significativa entre las variables. Sin embargo, existe la posibilidad de validar si hay otras formas en las que se introduzca multicolinealidad al modelo, usando el Factor de Inflación de Varianza (VIF), que indica cuánto se inflan las varianzas de los coeficientes de regresión debido a la colinealidad entre las variables predictoras.
vif(regresion_multiple2)
## GVIF Df GVIF^(1/(2*Df))
## areaconst 2.131279 1 1.459890
## banios 2.313767 1 1.521107
## estrato 1.759215 3 1.098719
## parqueaderos 1.894646 1 1.376461
La manera de interpretar el VIF es que los valores entre 1 y 5 indican una baja correlación entre las variables independientes, por lo que puede decirse que no hay multicolinealidad entre las variables empleadas en el modelo. Ahora bien, el resultado difiere frente al modelo calculado para las casas en el norte en tanto puede existir una correlación más cercana con las variables área construida y baños, sin embargo, al tener un valor VIF menor que 5 sigue siendo muy bajo para considerar que haya un problema de multicolinealidad
Sugerencias de mejora Una posibilidad para mejorar los supuestos del modelo es simplificarlo un poco, por ejemplo, eliminando la variable baño, que según los análisis anteriores puede ser la que menos aporta al modelo en general, similar al primer caso. Además, la transformación logarítmica de algunas variables podría mejorar la distribución de los datos y la relación lineal con la variable objetivo. Es importante identificar y abordar los valores atípicos que podrían influir significativamente en los resultados del análisis, ya que estos pueden distorsionar las estimaciones y afectar la interpretación de los resultados.
Una vez examinado con detalle el modelo, evaluados los supuestos y generadas algunas recomendaciones para su mejora, podemos pasar a trabajar la predicción de los valores de la vivienda con las características solicitadas. Para ello se divide el dataset en dos conjuntos de datos, igual a como se hizo en el primer caso. El primer conjunto es para el entrenamiento del modelo (train_data), que representa el 70% de los datos o 1751 observaciones, y otro para probar su eficiencia, precisión y ajuste (test_data), que representa el 30% de los datos o 750 observaciones. Los conjuntos de datos se generan al azar para asegurar que el proceso no resulte viciado a una respuesta en particular.
#División de los datos
set.seed(123)
train_indices <- sample(1:nrow(base2), size = 0.7 * nrow(base2))
#Conjunto de entrenamiento con los índices generados 70% del dataset
train_data <- base2[train_indices, ]
#Conjunto de prueba con los índices generados 30% del dataset
test_data <- base2[-train_indices, ]
A continuación, se entrena el modelo nuevamente, con las variables validadas en el paso anterior y utilizando el conjunto de datos de entrenamiento.
regresion_multiple2_train <- lm(preciom ~ areaconst + banios + estrato + parqueaderos, data = train_data)
summary(regresion_multiple2_train)
##
## Call:
## lm(formula = preciom ~ areaconst + banios + estrato + parqueaderos,
## data = train_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -901.95 -37.75 -3.29 35.26 855.20
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -92.39005 10.02210 -9.219 < 2e-16 ***
## areaconst 1.10300 0.05528 19.952 < 2e-16 ***
## banios 43.28596 3.58003 12.091 < 2e-16 ***
## estrato4 36.26353 9.01056 4.025 5.95e-05 ***
## estrato5 55.53882 9.28756 5.980 2.70e-09 ***
## estrato6 204.32669 11.45949 17.830 < 2e-16 ***
## parqueaderos 79.95178 5.16387 15.483 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 93.5 on 1743 degrees of freedom
## Multiple R-squared: 0.7855, Adjusted R-squared: 0.7848
## F-statistic: 1064 on 6 and 1743 DF, p-value: < 2.2e-16
El modelo entrenado con el primer conjunto de datos (train) tiene un desempeño muy similar al inicial, donde se empleó el conjunto de datos completo. Mientras el valor de \(r^{2}\) para el primer modelo es de 0.792, el del modelo entrenado con el 70% de los datos tiene un valor de 0.7855, esto implicaría una reducción del 0.6% en la capacidad del modelo de explicar la variación de los datos. Como en el caso anterior, veremos que el verdadero valor de la división de los datos está en examinar cómo se comporta con el conjunto de datos de prueba, como se muestra a continuación.
predicciones <- predict(regresion_multiple2_train, newdata = test_data)
# Evaluar el rendimiento del modelo, por ejemplo, usando el RMSE
rmse <- sqrt(mean((test_data$preciom - predicciones)^2))
print(paste("Diferencia promedio entre los valores predichos y los reales (RMSE):", rmse))
## [1] "Diferencia promedio entre los valores predichos y los reales (RMSE): 86.4734563908053"
print(paste("El promedio del valor de las propiedades de la base original es de:", mean(test_data$preciom)))
## [1] "El promedio del valor de las propiedades de la base original es de: 300.786950732357"
Para evaluar la precisión del modelo entrenado se calcula nuevamente el Root Mean Square Error, que es la raíz cuadrada de la media de los errores del modelo al cuadrado. En otras palabras, la diferencia promedio que existe entre los valores predichos por el modelo y los errores reales. En este caso, la diferencia es de 86 millones de pesos, como se presenta arriba. Esta diferencia se considera menos significativa que para el caso de la base1, aunque todavía podría causar problemas pues implica que, en promedio, el modelo estimaría erróneamente el valor de las viviendas por 86 millones de pesos.
Ahora bien, si analizamos el rango de la variable preciom podemos darnos cuenta de que es significativamente amplio (entre 90 y 1750 millones) pues, como se ha mencionado antes, hay un número significativo de datos atípicos.
summary(test_data$preciom)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 90.0 175.0 250.0 300.8 335.0 1750.0
Esta nueva consideración puede ayudar con la interpretación de los resultados de las predicciones del modelo pues, aunque en promedio la diferencia es considerable, el RMSE es relativamente bajo con relación al límite superior del rango. Lo anterior significa que la diferencia entre las predicciones será mayor para las viviendas con un costo elevado y, probablemente, sea menor para las viviendas con costos más cercanos al promedio. En tanto el valor del RMSE (86.74) equivale a casi el 28.8% del promedio real de la variable respuesta (300.8), podemos estimar que el modelo tiene un margen de error de alrededor del 28%. Este análisis puede visualizarse mejor en el siguiente gráfico.
ggplot(data = test_data, aes(x = preciom, y = predicciones)) +
geom_point(color = 'blue', alpha = 0.6) +
geom_abline(slope = 1, intercept = 0, color = 'red', linetype = 'dashed') +
labs(title = 'Valores Reales vs. Predicciones',
x = 'Valor Real de Precio',
y = 'Valor Predicho de Precio') +
theme_minimal()
Al igual que en el primer caso, la línea roja representa los valores predichos por el modelo, mientras los puntos azules son las observaciones reales dentro del conjunto de datos de prueba. Aquí es posible observar que aunque el modelo hace un buen trabajo describiendo el comportamiento de las viviendas con valores menores a 500 millones, la realidad es que con los datos superiores tiene dificultades significativas, alejándose los valores reales de los predichos. Para este caso las diferencias con los datos atípicos son más grandes que para el caso anterior, lo que explicaría el hecho de que, a pesar de mejores valores de ajuste y distribución de errores, el margen de error sea el mismo.
Predicción de las propiedades con las características solicitadas La segunda vivienda debe tener un área construida de 300 metros cuadrados, 3 parqueaderos, 3 baños, 5 habitaciones y estar en los estratos 5 o 6.
prediccion_estrato_5 = predict(regresion_multiple2_train,list(areaconst = 300,parqueaderos = 3,
banios = 3, habitaciones = 5,
estrato ="5"))
prediccion_estrato_5
## 1
## 663.7609
La vivienda con las características presentadas y en estrato 4 tendría un valor aproximado de $663’760.900 Ahora, la predicción de una vivienda con las mismas características en estrato 6:
prediccion_estrato_6 <- predict(regresion_multiple1_train,list(areaconst = 300, parqueaderos = 3,
banios = 3,
habitaciones = 5, estrato = "6"))
prediccion_estrato_6
## 1
## 755.4117
La vivienda con las características presentadas y en estrato 6 tendría un valor aproximado de $812’548.800
Finalmente, se utilizará el modelo entrenado (regresión_multiple_train) para encontrar las 5 mejores viviendas que respondan a la solicitud de la empresa Bayer. Para ello se genera una nueva base con las viviendas que cumplan con las características planteadas:
viviendas_filtradas_base2 <- base2 %>%
filter(areaconst >= 300, parqueaderos >= 3, banios >= 3, habitaciones >= 5, estrato_num >= 3, estrato_num <= 4)
dim(viviendas_filtradas_base2)
## [1] 13 12
13 de las 2501 viviendas en la base2 cumplen con las características de la solicitud. A continuación, se utiliza este nuevo conjunto para seleccionar las 5 propiedades que tengan el precio más cercano a las predicciones realizadas por el modelo, restando al valor de cada propiedad el valor predicho por el modelo en la sección anterior (promediando los valores de los estratos 5 y 6):
viviendas_seleccionadas_base2 <- viviendas_filtradas_base2 %>%
mutate(diferencia = abs((prediccion_estrato_6 + prediccion_estrato_5)/2 - preciom)) %>%
arrange(diferencia) %>%
head(5)
viviendas_seleccionadas_base2
## # A tibble: 5 × 13
## id estrato preciom areaconst parqueaderos banios habitaciones tipo barrio
## <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
## 1 7182 5 730 573 3 8 8 apart… guada…
## 2 7512 5 670 300 3 5 5 apart… semin…
## 3 5758 6 950 329 4 5 5 apart… ciuda…
## 4 6275 6 950 330 4 6 6 apart… ciuda…
## 5 4706 6 980 306 4 5 5 apart… ciuda…
## # ℹ 4 more variables: longitud <dbl>, latitud <dbl>, estrato_num <dbl>,
## # diferencia <dbl>
#select(id, areaconst, parqueaderos, banios, habitaciones, estrato, preciom, predicted_price)
Se observan las 5 opciones de vivienda que se acercan más al valor predicho. A primera vista podemos encontrar que sólo una de las viviendas está por debajo del promedio de las predicciones de valores para el estrato 5 y 6, 709 millones. Es el caso de la vivienda de id 7512, con un valor de 670 millones de pesos. Además de esta vivienda encontramos también la de id 7182 con un costo de 730 millones, esta última puede ser la opción más favorable, considerando que supera significativamente los requerimientos del cliente -con 8 baños, 8 habitaciones y 573 metros cuadrados construidos- y además tiene un valor menor a los 850 millones del crédito que tiene la familia aprobado. Las otras tres viviendas presentadas, aunque cumplen con las solicitudes realizadas, tienen un valor superior al préstamo para la compra de la vivienda, lo que podría explicarse por el hecho de que se encuentran en estrato 6, lo que aumentaría significativamente su valor según lo predicho por el modelo. Se presenta un mapa con la ubicación de cada una de las propiedades para facilitar la selección.
color <- colorFactor(palette = c( "blue"), domain = viviendas_seleccionadas_base2$tipo)
mapa4 <- leaflet(viviendas_seleccionadas_base2) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~color(tipo), radius = 4)
mapa4
De las 5 viviendas presentadas, sólo 2 de ellas están por debajo de los 850 millones que tiene disponible el cliente para la compra del apartamento en el sur. Las dos viviendas están en el estrato 5, en los barrios Guadalupe y Seminario que, aunque están en el lado sur de la ciudad, están cerca al centro, con fácil acceso a vías principales.
En conclusión, el segundo modelo generado tiene una capacidad de respuesta mejor que el anterior, a pesar de no cumplir a cabalidad todos los supuestos, nuevamente es inexacto con valores muy elevados, gracias a los valores extremos dentro del dataset. Para el caso solicitado, una vivienda por debajo de los 850 millones de pesos funcionó bien, generando recomendaciones viables pero no muy variadas, que sun así se acomodan a la solicitud del cliente. Un factor que pudo jugar en contra de la posibilidad de encontrar opciones más variadas es el requerimiento de que la vivienda estuviera en estratos 5 o 6, lo que eleva significativamente su valor. Aun así, al igual que en el caso anterior, es importante ser cuidadosos con otras predicciones que se hagan utilizando este modelo, particularmente aquellas que impliquen viviendas con costos muy elevados.
Los dos Modelos de Regresión Lineal Múltiple generados en este informe tuvieron un rendimiento aceptable a la hora de predecir el valor de las viviendas solicitadas por el cliente. Con el objetivo de mejorar el rendimiento del modelo se puede pensar en segmentar los públicos de venta, teniendo un conjunto de viviendas de lujo, por encima de los 1000 millones, y otro grupo de propiedades estándar. Esto disminuiría el margen de error de los modelos y permitiría hacer ventas de manera más eficiente a los clientes adecuados.
Finalmente, como se demostró a lo largo del informa, el manejo y entendimiento de los datos fue fundamental para superar algunos obstáculos, por ejemplo, aunque ningun modelo empleado cumplió adecuadamente con todos los supuestos de un modelo de regresión lineal, la exploración de los datos y el ajuste de los subsets de datos permitieron al menos evadir el problema de la multicolinealidad. Los procedimientos de manipulación de datos también fueron relevantes muestra de ellos es la reorganización de la variable zona para la realización del informe.
library(paqueteMODELOS)
library(tidyverse)
library(dplyr)
library(mice)
library(factoextra)
library(FactoMineR)
library(cluster)
library(janitor)
library(ggplot2)
library(leaflet)
library(GGally)
Mode <- function(x) {
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
data("vivienda")
#####Exploración general de los datos###
glimpse(vivienda)
str(vivienda)
summary(vivienda)
summarytools::freq(vivienda, cumul = F)
#Es necesario cambiar el tipo de algunas variables para hacer la exploración
vivienda$piso <- as.numeric(vivienda$piso)
vivienda$estrato <- factor(vivienda$estrato)
#Estandarizar valores de tipo character
vivienda$tipo <- tolower(vivienda$tipo)#Pasamos todas las observaciones a minúscula
vivienda$barrio <- tolower(vivienda$barrio)
vivienda$zona <- tolower(vivienda$zona)
#Se encuentran tres registros vacíos en todo el dataset.
#Hay viviendas sin habitaciones ni baños.
#Es necesario explorar más a fondo la variable piso y entender su relación en el
#Dataset
#Qué valores toma la variable?
unique(vivienda$piso)#NA, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12.
#Hay casas de más de 4 pisos?
casas_piso4 <- vivienda %>%
filter(tipo=="casa", piso > 4)
dim(casas_piso4)#hay 11 casas con más de 4 pisos, dos con 10
#Análisis de datos faltantes
md.pattern(vivienda) %>%
show() #Tenemos 1605 datos perdidos en parqueaderos y 2638 en piso.
#Hay tres observaciones con todos los datos faltantes.
#El uso de la variable piso puede ser problemático, pues no es claro si se
#trata del piso en el que se ubica la vivienda o el número de pisos que
#tienen las viviendas.Además, tiene un número elevado de datos faltantes
#y su naturaleza ambigua harí dificil la imputación.
#En ese sentido no se va a utilizar esta variable.
####Limpieza de datos###
#Exluímos la variables piso y borramos datos núlos en variable ID pues
#son registros vacíos
data_clean <- vivienda %>%
select(-piso) %>%
drop_na(id)
Imputación de datos de la variable Parqueadero
#La otra variable con datos faltantes es el parqueadero.
#Exploramos cuántas casas y apartamentos no tienen el dato "parqueaderos"
apto_sin_parqueo = data_clean %>%
select(tipo, parqueaderos) %>%
filter(tipo == "apartamento", is.na(parqueaderos))
dim(apto_sin_parqueo) # 869 apartamentos no tienen el dato "parqueaderos"
## [1] 0 2
casa_sin_parqueo = data_clean %>%
select(tipo, parqueaderos) %>%
filter(tipo == "casa", is.na(parqueaderos))
dim(casa_sin_parqueo) # 733 casas no tienen el dato "parqueaderos"
## [1] 0 2
#La estrategia de imputación será reemplazar por el dato más común de parqueadero
#dentro del subgrupo de cada tipo de vivienda.
casa_parqueo <- data_clean %>%
select(tipo, parqueaderos) %>%
filter(tipo == "casa")
apto_parqueo <- data_clean %>%
select(tipo, parqueaderos) %>%
filter(tipo == "apartamento")
Mode(casa_parqueo$parqueaderos) # Dato más común 2
## [1] 2
Mode(apto_parqueo$parqueaderos) # Dato más común 1
## [1] 1
data_clean <- data_clean %>%
mutate(parqueaderos = ifelse(is.na(parqueaderos) & tipo == "casa", 2,
ifelse(is.na(parqueaderos) & tipo == "apartamento", 1,
parqueaderos)))
#Verificamos que se haya hecho el reemplazo
md.pattern(data_clean) %>%
show()
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## id zona estrato preciom areaconst parqueaderos banios habitaciones tipo
## 8319 1 1 1 1 1 1 1 1 1
## 0 0 0 0 0 0 0 0 0
## barrio longitud latitud
## 8319 1 1 1 0
## 0 0 0 0
#Verificación del impacto de la imputación en los datos
tabla1 = table(vivienda$parqueaderos)
tabla2 = table(data_clean$parqueaderos)
prop.table(tabla1)*100
##
## 1 2 3 4 5 6
## 46.97037368 36.84680661 7.74155129 5.71683787 1.01235671 1.01235671
## 7 8 9 10
## 0.26797678 0.25308918 0.05955039 0.11910079
prop.table(tabla2)*100
##
## 1 2 3 4 5 6 7
## 48.3711985 38.5623272 6.2507513 4.6159394 0.8174059 0.8174059 0.2163722
## 8 9 10
## 0.2043515 0.0480827 0.0961654
par(mfrow=c(1,2))
boxplot(vivienda$parqueaderos ~ vivienda$tipo, main = "Distribución original")
boxplot(data_clean$parqueaderos ~ data_clean$tipo, main = "Distribución después de imputación")
#Es claro que debido a que los apartamentos eran el tipo de vivienda con más
#datos faltantes en la variables parqueaderos tuvo el mayor aumento. Sin embargo,
#se considera este método suficiente en tanto no tuvo mayor impacto en el resto
#de las variables y conserva (aproximadamente) la distribución de las proporciones
#del dataset original.
##Imputación Habitaciones y Baños con valores en 0##
#Según la exploración de los datos hay 45 propiedades donde el valor de baños es 0
#y 66 propiedades donde el valor de habitaciones es 0. A continuación un vector
#con los datos que reúnen en total 76 casos
viviendas_sin_hb <- data_clean %>%
filter(habitaciones == 0 | banios == 0)
dim(viviendas_sin_hb)
#Se empleará la misma estrategia de imputación que se usó para el número de
#parqueaderos, asumiendo que el número de habitaciones o baños más frecuente
#dentro de cada tipo de vivienda es la mejor pista que se tiene de cómo puede comportarse
#esta variable.
#Imputación habitaciones
casa_habitaciones <- data_clean %>%
select(tipo, habitaciones) %>%
filter(tipo == "casa")
apto_habitaciones <- data_clean %>%
select(tipo, habitaciones) %>%
filter(tipo == "apartamento")
Mode(casa_habitaciones$habitaciones) # Dato más común 4
Mode(apto_habitaciones$habitaciones) # Dato más común 3
data_clean <- data_clean %>%
mutate(habitaciones = ifelse(habitaciones == 0 & tipo == "casa", 4,
ifelse(habitaciones == 0 & tipo == "apartamento", 3,
banios)))
#Verificamos que se haya realizado el cambio
unique(data_clean$habitaciones)
#Imputación Baños
casa_banios <- data_clean %>%
select(tipo, banios) %>%
filter(tipo == "casa")
apto_banios <- data_clean %>%
select(tipo, banios) %>%
filter(tipo == "apartamento")
Mode(casa_banios$banios) # Dato más común 4
Mode(apto_banios$banios) # Dato más común 2
data_clean <- data_clean %>%
mutate(banios = ifelse(banios == 0 & tipo == "casa", 4,
ifelse(banios == 0 & tipo == "apartamento", 2,
banios)))
#Verificamos que se haya realizado el cambio
unique(data_clean$banios)