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:


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


Ayude a María a responder la solicitud, mediante técnicas 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).

Informe ejecutivo

Resumen

La compañía C&A, en aras de dar la mejor solución a nuestros clientes, quiere determinar las mejores opciones de vivienda que se ajuste al presupuesto y gustos de los solicitantes. Es por esto por lo que, para dar solución a la solicitud, se puso en marcha la iniciativa junto al área de analítica de datos, para la creación de un modelo que pudiera pronosticar adecuadamente el precio de una vivienda por medio de las características suministradas por la empresa internacional. Para esto, se uso un algoritmo de regresión lineal múltiple, el cual está construido mediante las variables área construida, estrato, número de cuartos, número de parqueaderos y número de baños, garantizando la mejor ubicación para los dos empleados de la empresa y sus familias.

Para hacerlo aún mas personalizado, se crearon dos modelos para cada una de las 2 solicitudes, uno teniendo en cuenta casas de la zona norte y otro para los apartamentos de la zona sur. Esto garantizó que el algoritmo solo se entrenara con los patrones y características de cada una de esas zonas.


Hallazgos

Interpretación del modelo

El primer modelo está enfocado en la primera solicitud. El impacto de cada variable sobre el precio de la vivienda es el siguiente:


\[ precio_m = 33.96564 + 0.83083 \times areaconst + 84.28927 \times estrato4 + 137.92112 \times estrato5 + 327.80065 \times estrato6 + 27.10245 \times banios + \varepsilon \]

  • Por cada cambio de 1 metro cuadrado en el área construida, el precio aumenta en promedio 0.83 millones
  • Por cada cambio en estrato 4, el precio aumenta en promedio en 84, en estrato 5 a 137 y en estrato 6 a 327 millones
  • Por cada cambio de 1 baño adicional, el precio aumenta en promedio 27.1 millones

Además, el R2, el cual es una métrica para medir el rendimiento del modelo, es de 0.66, lo que indica que aproximadamente el 66% de la variabilidad del precio de un inmueble es explicada por las variables explicativas del modelo, lo cual es un rendimiento bastante aceptable.


El segundo modelo esta enfocado en la segunda solicitud. El impacto de cada variable sobre el precio es la siguiente:


\[ precio_m = -42.3541 + 2.6247 \times areaconst + 5.4340 \times estrato4 + 8.4178 \times estrato5 + 121.4733 \times estrato6 - 28.3972 \times habitaciones + 48.4498 \times parqueaderos + 28.7492 \times banios + \varepsilon \]

  • Por cada cambio de 1 metro cuadrado en el área construida, el precio aumenta en promedio 2.62 millones
  • Por cada cambio en estrato 6, el precio aumenta en promedio en 121 millones
  • Por cada cambio de 1 baño adicional, el precio aumenta en promedio 28.7 millones
  • Por cada cambio en 1 habitación, el precio disminuye en promedio en 28.4 millones
  • Por cada cambio en 1 parqueadero, el precio aumenta en 48.4 millones

Adicionalmente, se tiene un rendimiento bastante bueno, con un R2 de 0.86, es decir, que las variables incluidas explican aproximadamente el 86% de la variabilidad del precio, lo cual es bastante bueno.


La predicción de la solicitud

Tras construirse el modelo, se procede a realizar una predicción para cada una de las solicitudes, para determinar si las características sugeridas se adaptan al limite del presupuesto aprobado para cada empleado.


Para la primera solicitud se tiene la siguiente predicción:

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

Debido a que 2 de las variables no fueron estadísticamente significativas en este modelo, no se incluirán en la predicción.

Predicción para estrato 4: 338 millones

Predicción para estrato 5: 392 millones


Por lo tanto, la mejor opción para la familia 1 es una casa de estrato 4 con un área construida de 200 metros cuadrados, 1 parqueadero, 2 baños y 4 habitaciones puesto que es acorde al presupuesto aprobado de 350 millones.


Para la segunda solicitud se tiene la siguiente predicción:

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

Predicción para estrato 4: 843 millones

Predicción para estrato 5: 956 millones


Esto significa que la mejor opción para la familia 2 es un apartamento de estrato 5 con un área construida de 300 metros cuadrados, 3 parqueaderos, 3 baños y 4 habitaciones puesto que es acorde al presupuesto aprobado de 350 millones.

Recomendaciones

Adicionalmente, desde la empresa C&A, y gracias al modelo construido, se pueden realizar diversas predicciones que pueden generar nuevas opciones de apartamentos y casas que igualmente se ajustan al presupuesto establecido para los 2 empleados. Ademas, se muestra a continuación algunas ofertas atractivas para ubicar adecadamente a la familia 1 y 2. (para ver la ubicación geoespacial de estas ofertas, ver Anexo)


Solicitud 1:

Para la primera solicitud se tienen estas ofertas con las siguientes características, algunas de ellas con el mínimo o mejores características a las solicitadas:

Piso Estrato Precio Área Construida Parqueaderos Baños Habitaciones Barrio
2 4 330 240 1 4 4 Acopi
1 5 350 200 3 3 4 El Bosque
1 5 335 202 1 4 5 El Bosque
1 5 340 250 2 4 4 El Bosque
2 5 350 300 3 5 6 El Bosque


Solicitud 2:

Para la segunda solicitud se tienen estas ofertas con las siguientes características. Igualmente algunas de ellas con el mínimo o mejores características a las solicitadas:

Piso Estrato Precio Área Construida Parqueaderos Baños Habitaciones Barrio
2 5 730 573 3 8 5 Guadalupe
2 5 670 300 3 5 6 Seminario

Sin embargo, para la segunda solicitud solo se tienen 2 ofertas del total de la base de datos. A pesar de esto, basandonos en el modelo predictivo que se construyó, se predicen 4 nuevas sugerencias que pueden ser en algun punto potenciales ofertas y que se ajustan igualmente al presupuesto. Para esto, se variaron ligeramente algunas características de lo solicitado para la familia 2, pero sin compremeter sustancialmente sus preferencias.

Oferta Tipo Área Construida Parqueaderos Baños Habitaciones Estrato Precio Estimado
1 Apartamento 300 3 2 4 5 842.7312
2 Apartamento 255 3 3 5 6 838.0274
3 Apartamento 320 2 3 5 5 847.1273
4 Apartamento 275 2 1 3 6 841.3676


Anexo 1: Plan de trabajo


Paso Descripción de la Tarea Metodología para Obtener los Datos
1 Filtro de la base de datos para incluir solo casas de la zona norte o zona sur Seleccionar registros donde el tipo de vivienda sea “Casa” y la zona sea “Norte” de la ciudad.
2 Análisis exploratorio de datos enfocado en la correlación Utilizar el paquete plotly en R para crear gráficos interactivos de dispersión entre las variables de interés.
3 Estimación de un modelo de regresión lineal múltiple Utilizar el paquete stats en R para ajustar un modelo de regresión lineal con las variables seleccionadas.
4 Validación de supuestos del modelo Utilizar herramientas de diagnóstico de regresión como gráficos de residuos, pruebas de normalidad y homocedasticidad.
5 Predicción del precio de la vivienda Utilizar el modelo de regresión lineal múltiple estimado para predecir el precio de la vivienda solicitada.
6 Selección de ofertas potenciales Utilizar el modelo de regresión para identificar viviendas que se ajusten al presupuesto de la empresa.
7 Repetir pasos del 1 al 6 para la segunda solicitud Realizar nuevamente los pasos anteriores para la segunda solicitud, teniendo en cuenta el nuevo presupuesto.


Anexo 2: resultados de la modelación, validación y comparación de modelos


Preprocesamiento de datos:


Importación de la base de datos

library(naniar)
library(ggplot2)


datos <- read.csv(file = "vivienda.csv",
                  header = TRUE,
                  sep = ";")

head(datos)
##     id         zona piso estrato preciom areaconst parqueaderos banios
## 1 1147 Zona Oriente   NA       3     250        70            1      3
## 2 1169 Zona Oriente   NA       3     320       120            1      2
## 3 1350 Zona Oriente   NA       3     350       220            2      2
## 4 5992     Zona Sur    2       4     400       280            3      5
## 5 1212   Zona Norte    1       5     260        90            1      2
## 6 1724   Zona Norte    1       5     240        87            1      3
##   habitaciones        tipo      barrio  longitud latitud
## 1            6        Casa 20 de julio -76,51168 3,43382
## 2            3        Casa 20 de julio -76,51237 3,43369
## 3            4        Casa 20 de julio -76,51537 3,43566
## 4            3        Casa  3 de julio    -76,54   3,435
## 5            3 Apartamento       acopi  -76,5135 3,45891
## 6            3 Apartamento       acopi   -76,517 3,36971

Tratamiento de datos faltantes


Se observa que la variable “piso” y “parqueaderos” tienen un 31 y 19 por ciennto de datos faltantes respectivamente, por lo que es necesario realizar un tratamiento de datos faltantes en esas dos variables.

round(colSums(is.na(datos)) / nrow(datos) * 100, 2)
##           id         zona         piso      estrato      preciom    areaconst 
##         0.04         0.00        31.70         0.04         0.02         0.00 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##        19.29         0.04         0.04         0.00         0.00         0.00 
##      latitud 
##         0.00
vis_miss(datos)


El método seleccionado en este caso es el de imputación por la moda, esto debido a que son variables numéricas discretas y la moda se adapta mejor a ellos.

datos$areaconst <- gsub(",", ".", datos$areaconst)


imputar_moda <- function(x) {
  moda <- names(sort(table(x), decreasing = TRUE))[1]
  x_imputada <- ifelse(is.na(x), moda, x)
  return(x_imputada)
}

datos <- as.data.frame(lapply(datos, imputar_moda))


Resultado final de la base de datos sin datos faltantes

vis_miss(datos)

Se reemplaza las comas por puntos en las variables relacionadas con las coordenadas

datos$longitud <- gsub(",", ".", datos$longitud)
datos$latitud <- gsub(",", ".", datos$latitud)


Convertir variables a numéricas y categóricas


Se convierten las variables a sus respectivos tipos de datos. En este caso son 4 variables categóricas y 6 variables numéricas.

# Convertir a enteros las variables numéricas convertidas de texto
datos$piso <- as.integer(datos$piso)
datos$preciom <- as.integer(datos$preciom)
datos$areaconst <- as.numeric(datos$areaconst)
datos$parqueaderos <- as.integer(datos$parqueaderos)
datos$banios <- as.integer(datos$banios)
datos$habitaciones <- as.integer(datos$habitaciones)

datos$zona <- factor(datos$zona, levels = c("Zona Centro", "Zona Norte", "Zona Oeste", "Zona Oriente", "Zona Sur"))
datos$estrato <- as.factor(datos$estrato)
datos$tipo <- factor(datos$tipo, levels = c("Casa", "Apartamento"))
datos$barrio <- as.factor(datos$barrio)



# Eliminar filas con valores faltantes
datos <- na.omit(datos)


Tratamiento de datos atípicos


Se verifica si en las variables numéricas existe presencia de valores atípicos que puedan perjudicar el análisis o la ejecución del modelo. Para esto se hace uso del rango intercuartílico. Como se observa, ningún registro está por fuera de los rangos intercuartílicos, por lo que no hay presencia de outliers.

# Calcular el IQR para una columna 'x' en un data frame 'datos'
Q1 <- quantile(datos$x, 0.25)
Q3 <- quantile(datos$x, 0.75)
IQR <- Q3 - Q1

# Definir los límites para identificar outliers
lower <- Q1 - 1.5 * IQR
upper <- Q3 + 1.5 * IQR

# Identificar outliers
datos$x[datos$piso < lower | datos$piso > upper]
## NULL
datos$x[datos$preciom < lower | datos$preciom > upper]
## NULL
datos$x[datos$areaconst < lower | datos$areaconst > upper]
## NULL
datos$x[datos$parqueaderos < lower | datos$parqueaderos > upper]
## NULL
datos$x[datos$banios < lower | datos$banios > upper]
## NULL
datos$x[datos$habitaciones < lower | datos$habitaciones > upper]
## NULL


Primera solicitud


1. Filtros

Se filtra la base de datos para tener en cuenta solo casas en la zona norte.

# Filtrar las ofertas de casas en la zona norte de la ciudad
ofertas_norte <- subset(datos, tipo == "Casa" & zona == "Zona Norte")

# Mostrar los primeros 3 registros de las bases
head(ofertas_norte, 3)
##      id       zona piso estrato preciom areaconst parqueaderos banios
## 9  1209 Zona Norte    2       5     320       150            2      4
## 10 1592 Zona Norte    2       5     780       380            2      3
## 11 4057 Zona Norte    2       6     750       445            1      7
##    habitaciones tipo barrio  longitud latitud
## 9             6 Casa  acopi -76.51341 3.47968
## 10            3 Casa  acopi -76.51674 3.48721
## 11            6 Casa  acopi  -76.5295 3.38527
# Porcentaje de ofertas de casas en la zona norte
prop_ofertas_norte <- nrow(ofertas_norte) / nrow(datos)

print("Porcentaje de ofertas de casas en la zona norte:")
## [1] "Porcentaje de ofertas de casas en la zona norte:"
print(prop_ofertas_norte * 100)
## [1] 8.678928

2. Análisis exploratorio


Para variables numéricas con el precio:

library(plotly)

# 2. Gráfico de dispersión interactivo para cada variable
plot_area <- plot_ly(ofertas_norte, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers', marker = list(color = ~areaconst)) %>%
  layout(title = 'Precio de la Casa vs. Área Construida',
         xaxis = list(title = 'Área Construida'),
         yaxis = list(title = 'Precio de la Casa'))


# 3. Calcular la matriz de correlación
correlation_matrix <- cor(ofertas_norte[, c("preciom", "areaconst", "banios", "habitaciones")])


# 4. Visualizar la matriz de correlación como un mapa de calor interactivo
plot_correlation <- plot_ly(z = ~correlation_matrix, colorscale = 'Reds', type = 'heatmap')


# Mostrar los gráficos
plot_area
correlation_matrix
##                preciom areaconst    banios habitaciones
## preciom      1.0000000 0.7313480 0.5233357    0.3227096
## areaconst    0.7313480 1.0000000 0.4628152    0.3753323
## banios       0.5233357 0.4628152 1.0000000    0.5755314
## habitaciones 0.3227096 0.3753323 0.5755314    1.0000000
plot_correlation


Para variables categóricas con precio:

# Gráfico de barras para la relación entre el estrato y el precio de la casa
plot_estrato <- plot_ly(ofertas_norte, x = ~factor(estrato), y = ~preciom, type = 'bar', marker = list(color = ~preciom)) %>%
  layout(title = 'Precio de la Casa por Estrato',
         xaxis = list(title = 'Estrato'),
         yaxis = list(title = 'Precio de la Casa'))

# Mostrar los gráficos
subplot(plot_estrato)


3. Modelo

set.seed(123)

id_train_1 <- sample(1:nrow(ofertas_norte), round(0.7 * nrow(ofertas_norte)))

train_1 <- ofertas_norte[id_train_1, ]
test_1 <- ofertas_norte[-id_train_1, ]
modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = train_1)
summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = train_1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -653.27  -71.35  -14.28   47.17  947.14 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   33.36100   19.45140   1.715    0.087 .  
## areaconst      0.80541    0.05017  16.055  < 2e-16 ***
## estrato4      83.42305   18.98245   4.395 1.36e-05 ***
## estrato5     130.03241   18.33088   7.094 4.52e-12 ***
## estrato6     344.32935   28.91361  11.909  < 2e-16 ***
## habitaciones   0.25580    4.53959   0.056    0.955    
## parqueaderos   2.69060    5.82382   0.462    0.644    
## banios        28.45758    5.79086   4.914 1.21e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 145.9 on 497 degrees of freedom
## Multiple R-squared:  0.686,  Adjusted R-squared:  0.6816 
## F-statistic: 155.1 on 7 and 497 DF,  p-value: < 2.2e-16


Se vuelve a correr el modelo pero solo con las variables estadísticamente significativas

modelo1 <- lm(preciom ~ areaconst + estrato + banios, data = ofertas_norte)
summary(modelo1) 
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios, data = ofertas_norte)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -968.77  -73.13  -16.35   45.27 1069.02 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  33.96564   15.51078   2.190   0.0289 *  
## areaconst     0.83083    0.04177  19.889  < 2e-16 ***
## estrato4     84.28927   16.89775   4.988 7.66e-07 ***
## estrato5    137.92112   15.73297   8.766  < 2e-16 ***
## estrato6    327.80065   25.82630  12.693  < 2e-16 ***
## banios       27.10245    4.50506   6.016 2.85e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 156.8 on 716 degrees of freedom
## Multiple R-squared:  0.661,  Adjusted R-squared:  0.6587 
## F-statistic: 279.3 on 5 and 716 DF,  p-value: < 2.2e-16


4. Validación de supuestos

  • Homocedasticidad
library(lmtest)

bptest(modelo1)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo1
## BP = 132.54, df = 5, p-value < 2.2e-16


h0: No hay heterocedasticidad en los errores del modelo

ha: Existe heterocedasticidad en los errores del modelo

Debido a que el pvalor es muy pequeño, se niega la hipótesis nula, por lo que los existe heterocedasticidad.


  • Normalidad de los residuos
shapiro.test(resid(modelo1))
## 
##  Shapiro-Wilk normality test
## 
## data:  resid(modelo1)
## W = 0.83045, p-value < 2.2e-16


h0: Los residuos del modelo siguen una distribución normal.

ha: Los residuos del modelo no siguen una distribución normal.

Debido a que el pvalor es muy pequeño, se niega la hipótesis nula, por lo que los residuos del modelo no siguen una distribución normal.


  • Autocorrelación
dwtest(modelo1)
## 
##  Durbin-Watson test
## 
## data:  modelo1
## DW = 1.69, p-value = 1.163e-05
## alternative hypothesis: true autocorrelation is greater than 0


h0: No hay autocorrelación en los residuos del modelo.

ha: Existe autocorrelación en los residuos del modelo.

Debido a que el pvalor es muy pequeño, se niega la hipótesis nula, por lo que existe autocorrelación en los residuos.


  • Colinealidad
library(car)

vif(modelo1)
##               GVIF Df GVIF^(1/(2*Df))
## areaconst 1.430202  1        1.195910
## estrato   1.376739  3        1.054732
## banios    1.382317  1        1.175720


Según el factor de inflación de la varianza (VIF), cada variable del modelo posee valores menores a 10, lo que sugiere que no hay una colinealidad considerable entre las variables predictoras del modelo.


5. Predicción

# Para estrato 4
predict(modelo1, list(areaconst= 200,estrato= "4", banios=2))
##        1 
## 338.6254
# Para estrato 5
predict(modelo1, list(areaconst= 200,estrato= "5", banios=2))
##        1 
## 392.2572


6. Sugerencia de ofertas

El modelo construido arroja la siguiente predicción con las características que quiere el cliente.

# Oferta principal
predict(modelo1, list(areaconst= 200,estrato= "4", banios=2))
##        1 
## 338.6254


Teniendo en cuenta la base de datos, se busca 5 sugerencias de casas que cumplan con las sugerencias y presupuesto establecido para la familiar 1. Para esto, se ilustra visualiza mediante un mapa de la ciudad de Cali, la ubicación de las 5 propuestas sugeridas por la empresa.

ofertas_norte$estrato <- as.numeric(as.character(ofertas_norte$estrato))

ofertas_filtradas1 <- subset(ofertas_norte, 
                             areaconst >= 200 & 
                             estrato >= 4 & 
                             habitaciones >= 4 & 
                             parqueaderos >= 1 & 
                             banios >= 2 & 
                             preciom <= 350)

nrow(ofertas_filtradas1)
## [1] 39


Características de las 5 sugerencias.

head(ofertas_filtradas1, 5)
##        id       zona piso estrato preciom areaconst parqueaderos banios
## 155  7471 Zona Norte    2       4     330       240            1      4
## 2163 4210 Zona Norte    1       5     350       200            3      3
## 2165 4267 Zona Norte    1       5     335       202            1      4
## 2173 4800 Zona Norte    1       5     340       250            2      4
## 2183 4209 Zona Norte    2       5     350       300            3      5
##      habitaciones tipo    barrio  longitud latitud
## 155             4 Casa     acopi  -76.5498 3.39758
## 2163            4 Casa el bosque  -76.5301 3.48503
## 2165            5 Casa el bosque -76.53044 3.48399
## 2173            4 Casa el bosque   -76.533   3.465
## 2183            6 Casa el bosque  -76.5301 3.48577


Ubicación de las sugerencias.

library(leaflet)


sugerencias1 <- data.frame(
  ciudad = c("Ciudad A", "Ciudad B", "Ciudad C", "Ciudad D", "Ciudad E"),
  longitud = c(-76.5498, -76.5301, -76.53044, -76.533, -76.5301),
  latitud = c(3.39758, 3.48503, 3.48399, 3.465, 3.48577)
)

mapa <- leaflet(data = sugerencias1) %>%
  addTiles() %>%
  setView(lng = -76.5, lat = 3.4, zoom = 12) %>%  
  addMarkers(lng = ~longitud, lat = ~latitud, popup = ~ciudad)


mapa

Segunda solicitud


1. Filtros

ofertas_sur <- subset(datos, tipo == "Apartamento" & zona == "Zona Sur")

# Mostrar los primeros 3 registros de las bases
head(ofertas_sur, 3)
##       id     zona piso estrato preciom areaconst parqueaderos banios
## 24  5098 Zona Sur    5       4     290        96            1      2
## 164  698 Zona Sur    2       3      78        40            1      1
## 264 8199 Zona Sur    2       6     875       194            2      5
##     habitaciones        tipo     barrio  longitud latitud
## 24             3 Apartamento      acopi -76.53464 3.44987
## 164            2 Apartamento aguablanca   -76.501     3.4
## 264            3 Apartamento  aguacatal   -76.557   3.459
# Proporción de ofertas de casas en la zona sur
prop_ofertas_sur <- nrow(ofertas_sur) / nrow(datos)

print("Porcentaje de ofertas de casas en la zona sur:")
## [1] "Porcentaje de ofertas de casas en la zona sur:"
print(prop_ofertas_sur * 100)
## [1] 33.50162

2. Análisis exploratorio
Para variables numéricas con el precio:

library(plotly)

# 2. Gráfico de dispersión interactivo para cada variable
plot_area <- plot_ly(ofertas_sur, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers', marker = list(color = ~areaconst)) %>%
  layout(title = 'Precio de la Casa vs. Área Construida',
         xaxis = list(title = 'Área Construida'),
         yaxis = list(title = 'Precio de la Casa'))


# 3. Calcular la matriz de correlación
correlation_matrix <- cor(ofertas_sur[, c("preciom", "areaconst", "banios", "habitaciones")])


# 4. Visualizar la matriz de correlación como un mapa de calor interactivo
plot_correlation <- plot_ly(z = ~correlation_matrix, colorscale = 'Reds', type = 'heatmap')


# Mostrar los gráficos
plot_area
correlation_matrix
##                preciom areaconst    banios habitaciones
## preciom      1.0000000 0.7579955 0.7196705    0.3317538
## areaconst    0.7579955 1.0000000 0.6618179    0.4339608
## banios       0.7196705 0.6618179 1.0000000    0.5149227
## habitaciones 0.3317538 0.4339608 0.5149227    1.0000000
plot_correlation


Para variables categóricas con precio:

# Gráfico de barras para la relación entre el estrato y el precio de la casa
plot_estrato <- plot_ly(ofertas_norte, x = ~factor(estrato), y = ~preciom, type = 'bar', marker = list(color = ~preciom)) %>%
  layout(title = 'Precio de la Casa por Estrato',
         xaxis = list(title = 'Estrato'),
         yaxis = list(title = 'Precio de la Casa'))

# Mostrar los gráficos
subplot(plot_estrato)


3. Modelo

set.seed(345)

id_train_2 <- sample(1:nrow(ofertas_sur), round(0.7 * nrow(ofertas_sur)))

train_2 <- ofertas_sur[id_train_1, ]
test_2 <- ofertas_sur[-id_train_1, ]
modelo2 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = train_2)
summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = train_2)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -310.58  -32.47   -0.57   31.96  672.24 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -42.3541    22.7300  -1.863    0.063 .  
## areaconst      2.6247     0.1296  20.253  < 2e-16 ***
## estrato4       5.4340    14.8978   0.365    0.715    
## estrato5       8.4178    15.9587   0.527    0.598    
## estrato6     121.4733    18.0227   6.740 4.40e-11 ***
## habitaciones -28.3972     7.1131  -3.992 7.53e-05 ***
## parqueaderos  48.4498     9.5660   5.065 5.77e-07 ***
## banios        28.7492     6.8033   4.226 2.83e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 85.89 on 497 degrees of freedom
## Multiple R-squared:  0.8644, Adjusted R-squared:  0.8625 
## F-statistic: 452.5 on 7 and 497 DF,  p-value: < 2.2e-16


4. Validación de supuestos

  • Homocedasticidad
bptest(modelo1)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo1
## BP = 132.54, df = 5, p-value < 2.2e-16


h0: No hay heterocedasticidad en los errores del modelo

ha: Existe heterocedasticidad en los errores del modelo

Debido a que el pvalor es muy pequeño, se niega la hipótesis nula, por lo que los existe heterocedasticidad.


  • Normalidad de los residuos
shapiro.test(resid(modelo1))
## 
##  Shapiro-Wilk normality test
## 
## data:  resid(modelo1)
## W = 0.83045, p-value < 2.2e-16


h0: Los residuos del modelo siguen una distribución normal.

ha: Los residuos del modelo no siguen una distribución normal.

Debido a que el pvalor es muy pequeño, se niega la hipótesis nula, por lo que los residuos del modelo no siguen una distribución normal.


  • Autocorrelación
dwtest(modelo1)
## 
##  Durbin-Watson test
## 
## data:  modelo1
## DW = 1.69, p-value = 1.163e-05
## alternative hypothesis: true autocorrelation is greater than 0


h0: No hay autocorrelación en los residuos del modelo.

ha: Existe autocorrelación en los residuos del modelo.

Debido a que el pvalor es muy pequeño, se niega la hipótesis nula, por lo que existe autocorrelación en los residuos.


  • Colinealidad
vif(modelo1)
##               GVIF Df GVIF^(1/(2*Df))
## areaconst 1.430202  1        1.195910
## estrato   1.376739  3        1.054732
## banios    1.382317  1        1.175720


Según el factor de inflación de la varianza (VIF), cada variable del modelo posee valores menores a 10, lo que sugiere que no hay una colinealidad considerable entre las variables predictoras del modelo.


5. Predicción

# Para estrato 5
predict(modelo2, list(tipo = "Apartamento", areaconst=300, parqueaderos=3, banios=3, habitaciones=5, estrato="5"))
##        1 
## 843.0832
# Para estrato 6
predict(modelo2, list(tipo = "Apartamento", areaconst=300, parqueaderos=3, banios=3, habitaciones=5, estrato="6"))
##        1 
## 956.1387


6. Sugerencia de ofertas

El modelo construido arroja la siguiente predicción con las características que quiere el cliente.

# Oferta principal
predict(modelo2, list(tipo = "Apartamento", areaconst=300, parqueaderos=3, banios=3, habitaciones=5, estrato="5"))
##        1 
## 843.0832


Teniendo en cuenta la base de datos, se busca 5 sugerencias de casas que cumplan con las sugerencias y presupuesto establecido para la familiar 1. Para esto, se ilustra visualiza mediante un mapa de la ciudad de Cali, la ubicación de las 5 propuestas sugeridas por la empresa.

ofertas_sur$estrato <- as.numeric(as.character(ofertas_sur$estrato))

ofertas_filtradas2 <- subset(ofertas_sur, 
                             areaconst >= 300 & 
                             estrato >= 5 & 
                             habitaciones >= 5 & 
                             parqueaderos >= 3 & 
                             banios >= 3 & 
                             preciom <= 850)

nrow(ofertas_filtradas2)
## [1] 2


Características de las 5 sugerencias.

head(ofertas_filtradas2, 5)
##        id     zona piso estrato preciom areaconst parqueaderos banios
## 3251 7182 Zona Sur    2       5     730       573            3      8
## 6669 7512 Zona Sur    2       5     670       300            3      5
##      habitaciones        tipo    barrio longitud latitud
## 3251            5 Apartamento guadalupe  -76.548   3.408
## 6669            6 Apartamento seminario   -76.55   3.409


Ubicación de las sugerencias.

library(leaflet)


sugerencias2 <- data.frame(
  ciudad = c("Ciudad A", "Ciudad B"),
  longitud = c(-76.548, -76.55),
  latitud = c(3.408, 3.409)
)

mapa <- leaflet(data = sugerencias2) %>%
  addTiles() %>%
  setView(lng = -76.5, lat = 3.4, zoom = 12) %>%  
  addMarkers(lng = ~longitud, lat = ~latitud, popup = ~ciudad)


mapa


Debido a que solo existen 2 ofertas con estas características en la base de datos, a continuación se usa el modelo para determinar otras 4 posibles sugerencias que se pueden llegar a adaptar al presupuesto aprobado, cambiando ligeramente algunas características de las solicitudes.

# Ofertas opcionadas
predict(modelo2, list(tipo = "Apartamento", areaconst=300, parqueaderos=3, banios=2, habitaciones=4, estrato="5"))
##        1 
## 842.7312
predict(modelo2, list(tipo = "Apartamento", areaconst=255, parqueaderos=3, banios=3, habitaciones=5, estrato="6"))
##        1 
## 838.0274
predict(modelo2, list(tipo = "Apartamento", areaconst=320, parqueaderos=2, banios=3, habitaciones=5, estrato="5"))
##        1 
## 847.1273
predict(modelo2, list(tipo = "Apartamento", areaconst=275, parqueaderos=2, banios=1, habitaciones=3, estrato="6"))
##        1 
## 841.3676