María es agente de bienes raíces en Cali hace 10 años, 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:
| Caracteristicas | Vivienda1 | Vivienda2 |
|---|---|---|
| Tipo | Casa | Apartamento |
| area construida | 200 | 300 |
| parqueaderos | 1 | 3 |
| banos | 2 | 3 |
| habitaciones | 4 | 5 |
| estrato | 4 o 5 | 5 o 6 |
| zona | Norte | Sur |
| credito preaprobado | 350 millones | 850 millones |
La base de datos original contiene 8322 registros, con el objetivo de realizar el análisis de la vivienda 1 se aplica un filtro a esta base de datos seleccionando solo las viviendas que en tipo tengan el valor “Casa” y en zona tengan “Zona Norte”, quedando una base de datos con 722 registros , y a continuación se presentan los tres (03) primeros:
library(paqueteMODELOS)
library(dplyr)
library(knitr)
data("vivienda")
viviendas1 <- vivienda %>%
filter(tipo == "Casa", zona == "Zona Norte")
kable(head(viviendas1, 3))
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1209 | Zona Norte | 02 | 5 | 320 | 150 | 2 | 4 | 6 | Casa | acopi | -76.51341 | 3.47968 |
| 1592 | Zona Norte | 02 | 5 | 780 | 380 | 2 | 3 | 3 | Casa | acopi | -76.51674 | 3.48721 |
| 4057 | Zona Norte | 02 | 6 | 750 | 445 | NA | 7 | 6 | Casa | acopi | -76.52950 | 3.38527 |
dim(viviendas1)
## [1] 722 13
Luego de aplicado el filtro se presentan unas tablas que comprueban la consulta, es decir, que la nueva base solo contenga viviendas que el tipo sea “Casa” y estén ubicadas en la “Zona norte”, donde se puede visualizar que solo se presenta la información que tiene estas características y una frecuencia de 722:
library(kableExtra)
tabla <- as.data.frame(table(viviendas1$tipo))
names(tabla) <- c("Tipo de vivienda", "Frecuencia")
tabla
## Tipo de vivienda Frecuencia
## 1 Casa 722
tabla1 <- as.data.frame(table(viviendas1$zona))
names(tabla1) <- c("Zona", "Frecuencia")
tabla1
## Zona Frecuencia
## 1 Zona Norte 722
A continuación, se presenta el mapa interactivo de la ciudad de Santiago de Cali (Colombia) con los puntos de la base de datos tipo casa y ubicadas en la zona norte:
library(leaflet)
leaflet(viviendas1) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 4,
color = "#7B02A8",
popup = ~tipo
)
En el anterior, se puede visualizar que hay una gran concentración de puntos en la parte superior del mapa, siendo esta la zona norte de la ciudad (latitudes más altas). Cabe destacar que, hay puntos que se ubican en la parte inferior del mapa, que no corresponderían a la zona norte del análisis, si no más a la zona sur. Lo que indicaría que hay errores en la clasificación de la zona de algunas casas, puesto que a pesar de que la latitud los ubica en la parte inferior, fueron registrados en zona como Zona Norte, también puede deberse a que la zona es una clasificación administrativa pero no siempre coincide con la zona de coordenadas reales.
Teniendo en cuenta que la solicitud del cliente indica que una de las condiciones es que la casa este ubicada en zona norte y como se evidencio anteriormente, no todas las zonas clasificadas como zona norte lo son realmente, se opta por realizar un análisis de conglomerados (clústeres) para dividir los puntos geográficos en zonas basadas en la concentración real de los datos y hacer el análisis posterior solo con los puntos que por conglomerado correspondan a las zonas con latitud más alta.
Al aplicar este análisis de conglomerados obtenemos dos clústeres, zona 1 y zona 2, cuya latitud promedio es 3.47 y 3.39 respectivamente, lo que indicaría que la zona 1 es la que contiene las casas ubicadas al norte de la ciudad, sobre las cuales se realizarían el análisis, quedando con 606 registros.
set.seed(123) # Para reproducibilidad
# Solo latitud y longitud en matriz
coords <- viviendas1 %>% select(longitud, latitud)
# Aplicar k-means para 2 clusters
km <- kmeans(coords, centers = 2)
# Agregar cluster a la base como zona_real
viviendas1$zona_real <- factor(km$cluster, labels = c("Zona 1", "Zona 2"))
aggregate(latitud ~ zona_real, data = viviendas1, FUN = mean)
## zona_real latitud
## 1 Zona 1 3.472208
## 2 Zona 2 3.397372
table(viviendas1$zona_real)
##
## Zona 1 Zona 2
## 606 116
Al realizar nuevamente el mapa interactivo de la ciudad Santiago Cali luego de la división por conglomerados y tomando la zona 1 se puede visualizar que los puntos se agrupan solo en la parte superior del mapa, representando una mejor aproximación a las casas ubicadas en la zona norte que la original:
zona1 <- viviendas1 %>%
filter(zona_real == "Zona 1")
leaflet(zona1) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 4,
color = "#7B02A8",
popup = ~tipo
)
Continuando con el análisis, se revisan los datos faltantes en la base de datos resultante (zona 1), donde se evidencia que el 46% de la columna piso son datos faltantes, por lo cual, se toma la decisión de eliminar está columna. De igual manera, se procede a eliminar “id” puesto que es un indicador y no brinda información significativa en el análisis:
colSums(is.na(zona1))
## id zona piso estrato preciom areaconst
## 0 0 279 0 0 0
## parqueaderos banios habitaciones tipo barrio longitud
## 209 0 0 0 0 0
## latitud zona_real
## 0 0
zona1r <- zona1[, !(names(zona1) %in% c("piso", "id"))]
names(zona1r)
## [1] "zona" "estrato" "preciom" "areaconst" "parqueaderos"
## [6] "banios" "habitaciones" "tipo" "barrio" "longitud"
## [11] "latitud" "zona_real"
Por otro lado, la variable parqueaderos presenta 209 datos faltantes, se observa que sus valores registrados van de 1 a 10, sin incluir el valor 0. Esto indica que en la base de datos no se representa explícitamente las viviendas que no cuentan con parqueadero y es común encontrar viviendas con esta característica:
table(zona1r$parqueaderos, useNA = "always")
##
## 1 2 3 4 5 6 7 8 9 10 <NA>
## 149 145 42 35 11 7 5 1 1 1 209
Asimismo, se evidencia que las viviendas con NA en parqueaderos tienen un precio promedio mucho menor que aquellas que, si tienen un valor registrado en esta variable, lo que podría sugerir que ese NA no es aleatorio y se asocia a 0 parqueaderos. Por lo cual, se procede a reemplazar NA de parqueaderos con cero:
aggregate(preciom ~ is.na(parqueaderos), data = zona1r, mean)
## is.na(parqueaderos) preciom
## 1 FALSE 479.3678
## 2 TRUE 334.4545
# Se reemplazan los NA en parquederos con cero
zona1r$parqueaderos[is.na(zona1r$parqueaderos)] <-0
sum(is.na(zona1r$parqueaderos))
## [1] 0
En la revisión de los estadísticos descriptivos generales de las columnas numéricas de las variables solicitadas en el análisis (precio, área construida, parqueaderos, baños y habitaciones), se identifica que los valores de parqueaderos, baños y habitaciones oscilan entre 0 y 10; el precio presenta un mínimo de 89 y un máximo de 1940; y el área construida varía entre 30 y 1440:
zona1r %>%
select(preciom, areaconst, parqueaderos, banios, habitaciones) %>%
summary()
## preciom areaconst parqueaderos banios
## Min. : 89.0 Min. : 30.0 Min. : 0.000 Min. : 0.000
## 1st Qu.: 245.0 1st Qu.: 140.0 1st Qu.: 0.000 1st Qu.: 2.000
## Median : 380.0 Median : 240.0 Median : 1.000 Median : 3.000
## Mean : 429.4 Mean : 261.4 Mean : 1.426 Mean : 3.517
## 3rd Qu.: 540.0 3rd Qu.: 336.0 3rd Qu.: 2.000 3rd Qu.: 4.000
## Max. :1940.0 Max. :1440.0 Max. :10.000 Max. :10.000
## habitaciones
## Min. : 0.000
## 1st Qu.: 3.000
## Median : 4.000
## Mean : 4.584
## 3rd Qu.: 5.000
## Max. :10.000
Por otro lado, se calculó la matriz de correlaciones de Pearson entre las variables numéricas y su análisis gráfico, donde se identifica que todas las variables tienen una relación positiva con el precio de las viviendas, aunque con distinta intensidad. El área construida tiene una relación fuerte (0.74) con el precio, lo que indica que, a mayor superficie, el precio tiende a aumentar de forma consistente, aunque hay cierta variabilidad. Las variables parqueaderos (0.41), baños (0.55) y habitaciones (0.41) presentan correlaciones moderadas a bajas con el precio, reflejando que su relación es más débil y que los datos están más dispersos.
library(kableExtra)
correlacionviviendas1 <- cor(zona1r[, c("preciom", "areaconst", "parqueaderos", "banios", "habitaciones")], method = "pearson")
kable(correlacionviviendas1, caption = "Matriz de correlación de Pearson") %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
| preciom | areaconst | parqueaderos | banios | habitaciones | |
|---|---|---|---|---|---|
| preciom | 1.0000000 | 0.7388374 | 0.4121477 | 0.5524624 | 0.4055618 |
| areaconst | 0.7388374 | 1.0000000 | 0.3565642 | 0.4991671 | 0.4374937 |
| parqueaderos | 0.4121477 | 0.3565642 | 1.0000000 | 0.3766356 | 0.2586741 |
| banios | 0.5524624 | 0.4991671 | 0.3766356 | 1.0000000 | 0.6246336 |
| habitaciones | 0.4055618 | 0.4374937 | 0.2586741 | 0.6246336 | 1.0000000 |
library(GGally)
ggpairs(zona1r[, c("preciom", "areaconst", "parqueaderos", "banios", "habitaciones")], title="Matriz de dispersión y correlación de Pearson")
Posteriormente, se hizo el análisis del precio de las viviendas con la variable categórica estrato, mediante el precio promedio y el diagrama de cajas, donde se evidencia que hay una tendencia positiva entre el estrato y el precio promedio de las viviendas, lo que indica que los precios aumentan a medida que aumenta el estrato:
library(dplyr)
tabla_resumen <- zona1r %>%
group_by(estrato) %>%
summarise(
precio_prom = mean(preciom, na.rm = TRUE),
n = n()
)
tabla_resumen %>%
kable(
caption = "Precio promedio por estrato",
digits = 0, # número de decimales
col.names = c("Estrato", "Precio Promedio", "Cantidad de Viviendas")
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
| Estrato | Precio Promedio | Cantidad de Viviendas |
|---|---|---|
| 3 | 241 | 210 |
| 4 | 434 | 129 |
| 5 | 547 | 233 |
| 6 | 767 | 34 |
library(plotly)
plot_ly(
data = zona1r,
x = ~factor(estrato),
y = ~preciom,
type = "box",
jitter = 0.3,
marker = list(color = "#7B02A8")
) %>%
layout(
title = "Distribución del precio por estrato",
xaxis = list(title = "Estrato"),
yaxis = list(title = "Precio")
)
Asimismo, se realizó un ANOVA para revisar estadísticamente si existen diferencias significativas en los precios promedio de las viviendas entre los estratos, teniendo las siguientes hipótesis
H0: Las medias del precio son iguales en todos los estratos
H1: Al menos un estrato tiene media diferente
anova_model <- aov(preciom ~ factor(estrato), data = zona1r)
summary(anova_model)
## Df Sum Sq Mean Sq F value Pr(>F)
## factor(estrato) 3 14584322 4861441 109.4 <2e-16 ***
## Residuals 602 26759167 44450
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
El análisis ANOVA muestra que existen diferencias estadísticamente significativas en el precio de las viviendas entre los distintos estratos. Esto coincide con el gráfico de cajas y la tabla, donde se observa que los estratos más altos tienen precios promedio mayores.
Antes de la estimación del modelo de regresión lineal múltiple se hace un proceso de construccion de variables indicadoras (dummy) para la variable estrato, puesto que es categorica y no se puede asumir que hay un incremento lineal monotómico entre los estratos, donde el estrato 3 será la categoría base, es decir, cuando estrato 4, 5 y 6 tomen valor de cero simultaneamente, significa que la casa es estrato 3, a continuación se muestra el ejemplo de como quedaron los tres primeros registros con estas nuevas variables dummys:
library(fastDummies)
zona1r <- fastDummies::dummy_cols(zona1r,
select_columns = "estrato",
remove_first_dummy = TRUE) # opcional para evitar multicolinealidad
head(zona1r[, c("estrato_4", "estrato_5", "estrato_6")], 3) %>%
kable(
caption = "Variables Dummy para Estratos (primeras 3 filas)",
col.names = c("Estrato 4", "Estrato 5", "Estrato 6")
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
| Estrato 4 | Estrato 5 | Estrato 6 |
|---|---|---|
| 0 | 1 | 0 |
| 0 | 1 | 0 |
| 0 | 0 | 0 |
Se ajusta el modelo de regresión lineal mútliple para explicar el precio de la vivienda en función de la el área construida, los parqueaderos, los baños, las habitaciones y el estrato:
# Dividir el dataset ( 70% entrenamiento y 30% prueba)
indices <- sample(1:nrow(zona1r), size = 0.7 * nrow(zona1r))
train_data1 <- zona1r[indices, ]
test_data1 <- zona1r[-indices, ]
modelo1 <- lm(preciom ~ areaconst + parqueaderos + banios + habitaciones + estrato_4 + estrato_5 + estrato_6, data = train_data1)
summary(modelo1)
##
## Call:
## lm(formula = preciom ~ areaconst + parqueaderos + banios + habitaciones +
## estrato_4 + estrato_5 + estrato_6, data = train_data1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -851.79 -70.94 -17.13 32.42 1115.04
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 9.4935 22.4998 0.422 0.673287
## areaconst 0.6958 0.0566 12.294 < 2e-16 ***
## parqueaderos 13.0412 5.7466 2.269 0.023756 *
## banios 27.5658 7.4200 3.715 0.000231 ***
## habitaciones 8.6981 5.5421 1.569 0.117302
## estrato_4 73.2429 23.2990 3.144 0.001788 **
## estrato_5 128.0187 21.7180 5.895 7.77e-09 ***
## estrato_6 259.7367 41.3498 6.281 8.46e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 159 on 416 degrees of freedom
## Multiple R-squared: 0.6393, Adjusted R-squared: 0.6332
## F-statistic: 105.3 on 7 and 416 DF, p-value: < 2.2e-16
El intercepto en este modelo no tiene interpretación real, porque no es posible que todas las variables tengan valor de cero.
área construida (0.70): Por cada metro cuadrado adicional construido incrementa el precio en 0.70, manteniendo las demás variables constantes. Es un beta es estadísticamente significativo (p < 0.05).
parqueadero (13.04): Por cada parqueadero adicional en la vivienda aumenta su precio en 13.04, manteniendo todo lo demás constante. Es un beta es estadísticamente significativo (p < 0.05).
baño (27.56): Por cada baño adicional en la vivienda aumenta su precio en 27.56, manteniendo las demás variables constantes. Es un beta es estadísticamente significativo (p < 0.05).
Habitaciones (8.69): No es estadísticamente significativa (p = 0.11), es decir, no se puede afirmar que tiene efecto sobre el precio,manteniendo todo lo demás constante.
estrato 4 (73.24): Comparado con el estrato 3, la vivienda al pertenecer al estrato 4 aumenta el precio en 73.24 en promedio, manteniendo todo lo demás constante. Es un beta es estadísticamente significativo (p < 0.05).
estrato 5 (128): Comparado con el estrato de referencia (estrato 3) la vivienda al pertenecer al estrato 5 aumenta el precio en 128 en promedio, manteniendo las demás variables constantes. Es un beta es estadísticamente significativo (p < 0.05).
estrato 6 (259): Comparado con el estrato 3, la vivienda al pertenecer al estrato 6 aumenta el precio en 259 en promedio, manteniendo todo lo demás constante. Es un beta es estadísticamente significativo (p < 0.05).
Por otro lado, el R cuadrado ajustado nos indica que el modelo explica aproximadamente 63% de la variabilidad de los precios y es estadísticamente significativo (p-value: < 2.2e-16). En sintesis, el modelo de regresión lineal múltiple muestra que el precio de las viviendas aumenta significativamente con el aumento de la superficie construida, número de baños, parqueaderos y estrato socioeconómico, siendo resultados coherentes con la realidad, ya que mejores características en la vivienda tienden a aumentar su precio, dado que implican mayor diseño, materiales, trabajo y espacios adicionales, convirtiéndose así en propiedades de mayor valor o lujo.
Para mejorar el ajuste del modelo, se podrían considerar nuevas características de la vivienda, así como aspectos del sector, cercanía a servicios o amenidades adicionales. También sería útil agrupar la variable habitaciones en rangos, dado que no resultó significativa, para evaluar si su aporte mejora. Adicionalmente, se recomienda identificar y tratar valores atípicos (outliers) que influyan en los errores, probar transformaciones logarítmicas de las variables y, finalmente, crear un índice de barrio que capture la calidad del vecindario y su impacto en los precios.
par(mfrow=c(2,2))
plot(modelo1)
par(mfrow=c(2,2))
En el análisis gráfico se puede visualizar que los residuos presentan dispersión en valores grandes y puntos que se alejan de la línea, reflejando valores atípicos o influyentes. En el Normal Q-Q los puntos se alejan de la línea en los extremos superiores e inferiores, lo que indica que los residuos no siguen una distribución normal. En el Scale-Location hay una tendencia ascendente, lo que indica la presencia de heterocedasticidad, la dispersión de los residuos aumenta a medida que aumentan los valores predichos. En el Residuals vs Leverage se ve que los puntos 521, 136 y 588 tiene un residuo grande y es un punto influyente que puede estar afectando mucho el modelo.
Residual_modelo1 <- residuals(modelo1)
shapiro.test(Residual_modelo1)
##
## Shapiro-Wilk normality test
##
## data: Residual_modelo1
## W = 0.78229, p-value < 2.2e-16
En el resultado arrojado por el test de normalidad de Shapiro-Wilk se puede apreciar que el p-value es muy pequeño y menor que un nivel de significancia del 0.05, eso significa que hay fuerte evidencia para rechazar la hipótesis de normalidad de los errores.
library(lmtest)
bptest(modelo1)
##
## studentized Breusch-Pagan test
##
## data: modelo1
## BP = 86.833, df = 7, p-value = 5.524e-16
En el resultado arrojado por el test de Breusch-Pagan se puede apreciar que el p-value es pequeño y menor que un nivel de significancia del 0.05, por tanto se concluye la presencia de heterocedasticidad con una significancia del 5%.
# Test de Durbin-Watson
dwtest(modelo1)
##
## Durbin-Watson test
##
## data: modelo1
## DW = 1.9851, p-value = 0.4432
## alternative hypothesis: true autocorrelation is greater than 0
# Test de Breusch-Godfrey
bgtest(modelo1)
##
## Breusch-Godfrey test for serial correlation of order up to 1
##
## data: modelo1
## LM test = 0.021834, df = 1, p-value = 0.8825
Los p-value obtenidos en las test de Durbin-Watson y Breusch-Godfrey son muy pequeños, menores a 0.05, lo que indica que con un nivel de significancia del 5% se rechaza la hipótesis nula y los errores no son independientes, hay una autocorrelación positiva en los residuos del modelo.
library(car)
vif(modelo1)
## areaconst parqueaderos banios habitaciones estrato_4 estrato_5
## 1.638839 1.355203 2.178484 1.797343 1.459848 1.900809
## estrato_6
## 1.289356
Se evaluó la presencia de multicolinealidad mediante el Factor de Inflación de la Varianza (VIF). Los valores obtenidos estuvieron entre 1.36 y 2.12, valores menores al umbral de 5, por lo que, se deduce que no hay problemas de multicolinealidad entre las variables independientes del modelo.
En síntesis, la validación del modelo arrojo que, no hay
normalidad en los residuos, posible existencia de Valores atípicos o
influyentes, heterocedasticidad y no independencia de los errores, se
sugiere que, se apliquen transformaciones (logaritmo) a la variable
precio y las variables explicativas como por ejemplo logaritmo, realizar
tratamiento de valores atípicos (suavizarlos o eliminarlos) o
finalmente, elegir otro tipo de modelo.
predicciones1 <- predict(modelo1, newdata = test_data1)
resultados1 <- data.frame(Real = test_data1$preciom,
Predicho = predicciones1)
head(resultados1, 5)
## Real Predicho
## 1 320 430.4229
## 2 780 536.8064
## 3 230 202.0543
## 4 500 373.2039
## 5 395 397.3818
Al comparar los precios reales con los estimados por el modelo, se observa que algunas predicciones se acercan bastante al valor real (por ejemplo, fila 5: 395 vs 397), mientras que otras muestran diferencias mayores (fila 2: 780 vs 537). Esto indica que el modelo captura la tendencia general de los precios, pero tiende a subestimar las viviendas muy caras y sobreestimar las más económicas, por lo que puede ser útil ajustar o complementar el modelo para mejorar la precisión en los extremos.
Se realiza la predicción del precio de una vivienda tipo casa ubicada en la zona norte, con las siguientes características: área construida de 200, 1 parqueadero, 2 baños y 4 habitaciones. Para un estrato 4, el precio estimado es de 324.15, mientras que para un estrato 5, el precio estimado aumenta a 379.65.
#Predicción para estrato 4
predict(modelo1,
newdata = data.frame(
areaconst = 200,
parqueaderos= 1,
banios= 2,
habitaciones=4,
estrato_4=1,
estrato_5=0,
estrato_6=0))
## 1
## 324.8702
#Predicción para estrato 5
predict(modelo1,
newdata = data.frame(
areaconst = 200,
parqueaderos= 1,
banios= 2,
habitaciones=4,
estrato_4=0,
estrato_5=1,
estrato_6=0))
## 1
## 379.646
zona1r$precio_pred <- predict(modelo1, newdata = zona1r)
viviendas1_disponibles <- subset(
zona1r,
preciom <= 350 &
areaconst >= 200 &
habitaciones >= 4 &
banios >= 2 &
parqueaderos >= 1 &
estrato_4 ==1
)
ofertas_potenciales <- head(viviendas1_disponibles[order(-viviendas1_disponibles$preciom, -viviendas1_disponibles$areaconst ), ], 5)
ofertas_potenciales[, c("areaconst","habitaciones","banios","parqueaderos","estrato","preciom","precio_pred")] %>%
kable(
caption = "Ofertas potenciales de vivienda dentro del presupuesto",
col.names = c("Área construida", "Habitaciones", "Baños", "Parqueaderos", "Estrato", "Precio real", "Precio estimado"),
digits = 2
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
| Área construida | Habitaciones | Baños | Parqueaderos | Estrato | Precio real | Precio estimado |
|---|---|---|---|---|---|---|
| 350.0 | 5 | 4 | 1 | 4 | 350 | 493.08 |
| 280.0 | 4 | 3 | 2 | 4 | 350 | 421.14 |
| 295.0 | 4 | 2 | 2 | 4 | 340 | 404.02 |
| 264.5 | 4 | 4 | 2 | 4 | 340 | 437.92 |
| 275.0 | 5 | 3 | 2 | 4 | 330 | 426.36 |
Con base en las características solicitadas para la vivienda y considerando el crédito pre-aprobado máximo de 350 millones de pesos, se identificaron cinco viviendas potenciales que cumplen con los requisitos mínimos de área construida, número de habitaciones, baños, parqueaderos y estrato.
Las viviendas seleccionadas corresponden a aquellas que, dentro del presupuesto disponible, ofrecen las mejores características en términos de área construida y distribución, buscando maximizar el valor de la vivienda que el cliente puede adquirir con el crédito disponible:
• Oferta 1: vivienda de 350 m², con 5 habitaciones, 4 baños y 1 parqueadero, en estrato 4. Tiene un precio real de 350 millones.
• Oferta 2: vivienda de 280 m², con 4 habitaciones, 3 baños y 2 parqueaderos, también en estrato 4. Su precio real es de 350 millones.
• Oferta 3: vivienda de 295 m², con 4 habitaciones, 2 baños y 2 parqueaderos, con un precio real de 340 millones.
• Oferta 4: vivienda de 264.5 m², con 4 habitaciones, 4 baños y 2 parqueaderos, cuyo precio real es de 340 millones.
• Oferta 5: vivienda de 275 m², con 5 habitaciones, 3 baños y 2 parqueaderos, con precio real de 330 millones.
Es importante señalar que, las opciones seleccionadas presentan precios reales dentro del presupuesto, pero el modelo estima valores superiores, lo que sugiere que podrían representar oportunidades de compra atractivas en el mercado
A continuación, se presenta su ubicación geográfica:
library(leaflet)
icono_casa <-awesomeIcons(
icon = "map-marker",
iconColor = "white",
markerColor = "purple",
library = "fa"
)
leaflet(ofertas_potenciales) %>%
addTiles() %>%
addAwesomeMarkers(
lng = ~longitud,
lat = ~latitud,
icon = icono_casa,
popup = ~paste(
"<b>Precio:</b>", preciom,
"<br><b>Área:</b>", areaconst,
"<br><b>Habitaciones:</b>", habitaciones,
"<br><b>Baños:</b>", banios
)
)
La base de datos original contiene 8322 registros, con el objetivo de realizar el análisis de la vivienda 2 se aplica un filtro a esta base de datos seleccionando solo las viviendas que en tipo tengan el valor “Apartamento” y en zona tengan “Zona Sur”, quedando una base de datos con 2787 registros , y a continuación se presentan los tres (03) primeros:
viviendas2 <- vivienda %>%
filter(tipo == "Apartamento", zona == "Zona Sur")
kable(head(viviendas2, 3))
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 5098 | Zona Sur | 05 | 4 | 290 | 96 | 1 | 2 | 3 | Apartamento | acopi | -76.53464 | 3.44987 |
| 698 | Zona Sur | 02 | 3 | 78 | 40 | 1 | 1 | 2 | Apartamento | aguablanca | -76.50100 | 3.40000 |
| 8199 | Zona Sur | NA | 6 | 875 | 194 | 2 | 5 | 3 | Apartamento | aguacatal | -76.55700 | 3.45900 |
dim(viviendas2)
## [1] 2787 13
Luego de aplicado el filtro se presentan unas tablas que comprueban la consulta, es decir, que la nueva base solo contenga viviendas que el tipo sea “Apartamento” y estén ubicadas en la “Zona Sur”, donde se puede visualizar que solo se presenta la información que tiene estas características y una frecuencia de 2787:
library(kableExtra)
tabla2 <- as.data.frame(table(viviendas2$tipo))
names(tabla2) <- c("Tipo de vivienda", "Frecuencia")
tabla2
## Tipo de vivienda Frecuencia
## 1 Apartamento 2787
tabla3 <- as.data.frame(table(viviendas2$zona))
names(tabla3) <- c("Zona", "Frecuencia")
tabla3
## Zona Frecuencia
## 1 Zona Sur 2787
A continuación, se presenta el mapa interactivo de la ciudad de Santiago de Cali (Colombia) con los puntos de la base de datos tipo Apartamentos y ubicados en la Zona Sur:
library(leaflet)
leaflet(viviendas2) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 4,
color = "#7B02A8",
popup = ~tipo
)
En el anterior, se puede visualizar que hay una gran concentración de puntos en la parte inferior del mapa, siendo esta la zona sur de la ciudad (latitudes más bajas). Cabe destacar que, hay puntos distribuidos por todo el mapa de la ciudad y hay muchos puntos que se ubican en la parte superior del mapa, que no corresponderían a la zona sur del análisis, si no más a la zona norte. Lo que indicaría que hay errores en la clasificación de la zona de algunos apartamentos (algo similar a lo que sucedia con las casas de la zona norte), puesto que a pesar de que la latitud los ubica en la parte superior, fueron registrados en zona como Zona Sur, también puede deberse a que la zona es una clasificación administrativa pero no siempre coincide con la zona de coordenadas reales.
Teniendo en cuenta que la solicitud del cliente indica que una de las condiciones es que el apartamento este ubicado en zona sur y como se evidencio anteriormente, no todas las zonas clasificadas como zona sur lo son realmente, se opta por realizar un análisis de conglomerados (clústeres) para dividir los puntos geográficos en zonas basadas en la concentración real de los datos y hacer el análisis posterior solo con los puntos que por conglomerado correspondan a las zonas con latitud más baja.
Al aplicar este análisis de conglomerados obtenemos dos clústeres, zona 1 y zona 2, cuya latitud promedio es 3.42 y 3.37 respectivamente, lo que indicaría que la zona 2 es la que contiene los apartamentos ubicados más al sur de la ciudad, sobre las cuales se realizarían el análisis, quedando con 1845 registros.
set.seed(123) # Para reproducibilidad
# Solo latitud y longitud en matriz
coords <- viviendas2 %>% select(longitud, latitud)
# Aplicar k-means para 2 clusters
km <- kmeans(coords, centers = 2)
# Agregar cluster a la base como zona_real
viviendas2$zona_real <- factor(km$cluster, labels = c("Zona 2", "Zona 1"))
aggregate(latitud ~ zona_real, data = viviendas2, FUN = mean)
## zona_real latitud
## 1 Zona 2 3.372778
## 2 Zona 1 3.422378
table(viviendas2$zona_real)
##
## Zona 2 Zona 1
## 1845 942
Al realizar nuevamente el mapa interactivo de la ciudad Santiago Cali luego de la división por conglomerados y tomando la zona 2 se puede visualizar que los puntos se agrupan solo en la parte inferior del mapa, representando una mejor aproximación a los apartamentos ubicadas en la zona sur que la original:
zona2 <- viviendas2 %>%
filter(zona_real == "Zona 2")
leaflet(zona2) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 4,
color = "#7B02A8",
popup = ~tipo
)
Continuando con el análisis, se revisan los datos faltantes en la base de datos resultante (zona 2), donde se evidencia que el 23% de la columna piso son datos faltantes, por lo cual, se toma la decisión de eliminar está columna, puesto que no es una caracteristica solicitada por el cliente. De igual manera, se procede a eliminar “id” puesto que es un indicador y no brinda información significativa en el análisis:
colSums(is.na(zona2))
## id zona piso estrato preciom areaconst
## 0 0 417 0 0 0
## parqueaderos banios habitaciones tipo barrio longitud
## 239 0 0 0 0 0
## latitud zona_real
## 0 0
zona2r <- zona2[, !(names(zona2) %in% c("piso", "id"))]
names(zona2r)
## [1] "zona" "estrato" "preciom" "areaconst" "parqueaderos"
## [6] "banios" "habitaciones" "tipo" "barrio" "longitud"
## [11] "latitud" "zona_real"
Por otro lado, la variable parqueaderos presenta 239 datos faltantes, aligual que en el caso de casas, se observa que sus valores registrados van de 1 a 10, sin incluir el valor 0. Esto indica que en la base de datos no se representa explícitamente las viviendas que no cuentan con parqueadero y es común encontrar viviendas con esta característica:
table(zona2r$parqueaderos, useNA = "always")
##
## 1 2 3 4 10 <NA>
## 1003 514 60 28 1 239
Asimismo, se evidencia que los apartamentos con NA en parqueaderos tienen un precio promedio mucho menor que aquellos que, si tienen un valor registrado en esta variable, lo que podría sugerir que ese NA no es aleatorio y se asocia a 0 parqueaderos. Por lo cual, se procede a reemplazar NA de parqueaderos con cero:
aggregate(preciom ~ is.na(parqueaderos), data = zona2r, mean)
## is.na(parqueaderos) preciom
## 1 FALSE 339.4707
## 2 TRUE 178.6318
# Se reemplazan los NA en parquederos con cero
zona2r$parqueaderos[is.na(zona2r$parqueaderos)] <-0
sum(is.na(zona2r$parqueaderos))
## [1] 0
En la revisión de los estadísticos descriptivos generales de las columnas numéricas de las variables solicitadas en el análisis (precio, área construida, parqueaderos, baños y habitaciones), se identifica que los valores de parqueadero oscila entre 0 y 1, baños y habitaciones fluctuan entre 0 y 7, 0 y 6 respectivamente ; el precio por apartamento presenta un mínimo de 78 y un máximo de 1750; y el área construida varía entre 30 y 1440:
zona2r %>%
select(preciom, areaconst, parqueaderos, banios, habitaciones) %>%
summary()
## preciom areaconst parqueaderos banios
## Min. : 78.0 Min. : 40.00 Min. : 0.000 Min. :0.00
## 1st Qu.: 190.0 1st Qu.: 65.00 1st Qu.: 1.000 1st Qu.:2.00
## Median : 260.0 Median : 85.00 Median : 1.000 Median :2.00
## Mean : 318.6 Mean : 98.35 Mean : 1.264 Mean :2.56
## 3rd Qu.: 350.0 3rd Qu.:110.00 3rd Qu.: 2.000 3rd Qu.:3.00
## Max. :1750.0 Max. :932.00 Max. :10.000 Max. :7.00
## habitaciones
## Min. :0.000
## 1st Qu.:3.000
## Median :3.000
## Mean :2.943
## 3rd Qu.:3.000
## Max. :6.000
Por otro lado, se calculó la matriz de correlaciones de Pearson entre las variables numéricas y su análisis gráfico, donde se identifica que todas las variables tienen una relación positiva con el precio de los apartamentos, aunque con distinta intensidad. El área construida, baños y parqueaderos tiene una relación fuerte, 0.79, 0.75 y 0.71 respectivamente, lo que indica que mayor superficie, más baños y más parqueaderos, el precio tiende a aumentar de forma consistente, aunque hay cierta variabilidad. La variable habitaciones (0.35) presenta una correlación baja con el precio, reflejando que su relación es más débil y que los datos están más dispersos.
library(kableExtra)
correlacionviviendas2 <- cor(zona2r[, c("preciom", "areaconst", "parqueaderos", "banios", "habitaciones")], method = "pearson")
kable(correlacionviviendas2, caption = "Matriz de correlación de Pearson") %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
| preciom | areaconst | parqueaderos | banios | habitaciones | |
|---|---|---|---|---|---|
| preciom | 1.0000000 | 0.7983390 | 0.7137791 | 0.7510829 | 0.3560771 |
| areaconst | 0.7983390 | 1.0000000 | 0.6233564 | 0.6818235 | 0.4198300 |
| parqueaderos | 0.7137791 | 0.6233564 | 1.0000000 | 0.5924295 | 0.3216734 |
| banios | 0.7510829 | 0.6818235 | 0.5924295 | 1.0000000 | 0.5174674 |
| habitaciones | 0.3560771 | 0.4198300 | 0.3216734 | 0.5174674 | 1.0000000 |
library(GGally)
ggpairs(zona2r[, c("preciom", "areaconst", "parqueaderos", "banios", "habitaciones")], title="Matriz de dispersión y correlación de Pearson")
Posteriormente, se hizo el análisis del precio de los apartamentos con la variable categórica estrato, mediante el precio promedio y el diagrama de cajas, donde se evidencia que hay una tendencia positiva entre el estrato y el precio promedio de los apartamentos, lo que indica que los precios aumentan a medida que aumenta el estrato:
library(dplyr)
tabla_resumen <- zona2r %>%
group_by(estrato) %>%
summarise(
precio_prom = mean(preciom, na.rm = TRUE),
n = n()
)
tabla_resumen %>%
kable(
caption = "Precio promedio por estrato",
digits = 0, # número de decimales
col.names = c("Estrato", "Precio Promedio", "Cantidad de apartamentos")
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
| Estrato | Precio Promedio | Cantidad de apartamentos |
|---|---|---|
| 3 | 140 | 82 |
| 4 | 200 | 651 |
| 5 | 295 | 713 |
| 6 | 592 | 399 |
library(plotly)
plot_ly(
data = zona2r,
x = ~factor(estrato),
y = ~preciom,
type = "box",
jitter = 0.3,
marker = list(color = "#7B02A8")
) %>%
layout(
title = "Distribución del precio por estrato",
xaxis = list(title = "Estrato"),
yaxis = list(title = "Precio")
)
Asimismo, se realizó un ANOVA para revisar estadísticamente si existen diferencias significativas en los precios promedio de los apartamentos entre los estratos, teniendo las siguientes hipótesis
H0: Las medias del precio son iguales en todos los estratos
H1: Al menos un estrato tiene media diferente
anova_model <- aov(preciom ~ factor(estrato), data = zona2r)
summary(anova_model)
## Df Sum Sq Mean Sq F value Pr(>F)
## factor(estrato) 3 41982302 13994101 695.1 <2e-16 ***
## Residuals 1841 37064321 20133
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
El análisis ANOVA muestra que existen diferencias estadísticamente significativas en el precio de los apartamentos entre los distintos estratos. Esto coincide con el gráfico de cajas y la tabla, donde se observa que los estratos más altos tienen precios promedio mayores.
Antes de la estimación del modelo de regresión lineal múltiple se hace un proceso de construccion de variables indicadoras (dummy) para la variable estrato, puesto que es categorica y no se puede asumir que hay un incremento lineal monotómico entre los estratos, donde el estrato 3 será la categoría base, es decir, cuando estrato 4, 5 y 6 tomen valor de cero simultaneamente, significa que la casa es estrato 3, a continuación se muestra el ejemplo de como quedaron los tres primeros registros con estas nuevas variables dummys:
library(fastDummies)
zona2r <- fastDummies::dummy_cols(zona2r,
select_columns = "estrato",
remove_first_dummy = TRUE) # opcional para evitar multicolinealidad
head(zona2r[, c("estrato_4", "estrato_5", "estrato_6")], 3) %>%
kable(
caption = "Variables Dummy para Estratos (primeras 3 filas)",
col.names = c("Estrato 4", "Estrato 5", "Estrato 6")
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
| Estrato 4 | Estrato 5 | Estrato 6 |
|---|---|---|
| 1 | 0 | 0 |
| 0 | 0 | 0 |
| 1 | 0 | 0 |
Se ajusta el modelo de regresión lineal mútliple para explicar el precio de la vivienda en función de la el área construida, los parqueaderos, los baños, las habitaciones y el estrato:
indices2 <- sample(1:nrow(zona2r), size = 0.7 * nrow(zona2r))
train_data2 <- zona2r[indices2, ]
test_data2 <- zona2r[-indices2, ]
modelo2 <- lm(preciom ~ areaconst + parqueaderos + banios + habitaciones + estrato_4 + estrato_5 + estrato_6, data =train_data2)
summary(modelo2)
##
## Call:
## lm(formula = preciom ~ areaconst + parqueaderos + banios + habitaciones +
## estrato_4 + estrato_5 + estrato_6, data = train_data2)
##
## Residuals:
## Min 1Q Median 3Q Max
## -711.02 -32.57 1.04 31.18 764.10
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -27.93200 15.68484 -1.781 0.075177 .
## areaconst 2.03169 0.07492 27.119 < 2e-16 ***
## parqueaderos 40.04457 4.38709 9.128 < 2e-16 ***
## banios 37.35100 4.23309 8.824 < 2e-16 ***
## habitaciones -20.74933 4.73433 -4.383 1.27e-05 ***
## estrato_4 29.59628 11.66575 2.537 0.011298 *
## estrato_5 44.19214 11.91001 3.711 0.000216 ***
## estrato_6 167.35753 14.04798 11.913 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 83 on 1283 degrees of freedom
## Multiple R-squared: 0.8319, Adjusted R-squared: 0.831
## F-statistic: 906.9 on 7 and 1283 DF, p-value: < 2.2e-16
El intercepto en este modelo no tiene interpretación real, porque no es posible que todas las variables tengan valor de cero.
área construida (2.03): Por cada metro cuadrado adicional construido incrementa el precio en 2.03 en los apartamentos, manteniendo las demás variables constantes. Es un beta estadísticamente significativo (p < 0.05).
parqueadero (40.04): Por cada parqueadero adicional en el apartamento aumenta su precio en 40.04, manteniendo todo lo demás constante. Es un beta estadísticamente significativo (p < 0.05).
baño ( 37.35): Por cada baño adicional en el apartamento aumenta su precio en 37.35, manteniendo las demás variables constantes. Es un beta es estadísticamente significativo (p < 0.05).
Habitaciones (-20.75): Por cada habitación adicional en el apartamento disminuye su precio en 20.75, manteniendo las demás variables constantes. Es un beta es estadísticamente significativo (p < 0.05).
Estrato 4 (29.60): Comparado con el estrato 3, el apartamento al pertenecer al estrato 4 aumenta el precio en 29.60 en promedio, manteniendo todo lo demás constante. Es un beta es estadísticamente significativo (p < 0.05).
estrato 5 (44.19): Comparado con el estrato de referencia (estrato 3) el apartamento al pertenecer al estrato 5 aumenta el precio en 44.19 en promedio, manteniendo las demás variables constantes. Es un beta es estadísticamente significativo (p < 0.05).
estrato 6 (167.37): Comparado con el estrato 3, el apartamento al pertenecer al estrato 6 aumenta el precio en 167.37 en promedio, manteniendo todo lo demás constante. Es un beta es estadísticamente significativo (p < 0.05).
Por otro lado, el R cuadrado ajustado nos indica que el modelo explica aproximadamente 83% de la variabilidad de los precios de los apartamentos y es estadísticamente significativo (p-value: < 2.2e-16). En síntesis, el modelo de regresión lineal múltiple muestra que el precio de los apartamentos aumenta significativamente con el aumento de la superficie construida, número de baños, parqueaderos y estrato socioeconómico, siendo resultados coherentes con la realidad, ya que mejores características en la vivienda tienden a aumentar su precio, dado que implican mayor diseño, materiales, trabajo y espacios adicionales, convirtiéndose así en propiedades de mayor valor o lujo.
Las habitaciones presenta una relación negativa, es decir, más habitaciones significan menores precios, aunque intuitivamente no es lógico, se puede deber a que, más habitaciones en un mismo espacio significa habitaciones más pequeñas y prefieren menos habitaciones, pero más amplias.
El modelo tiene muy buen nivel de ajuste y sus betas son significativos, explorar si hay otras variables que se pueda incluir que mejoren su poder explicativo, vamos a revisar si se cumplen los supuestos del modelo:
par(mfrow=c(2,2))
plot(modelo2)
par(mfrow=c(2,2))
En el análisis gráfico se puede visualizar que los residuos presentan dispersión en valores grandes y puntos que se alejan de la línea, reflejando valores atípicos o influyentes. En el Normal Q-Q los puntos se alejan de la línea en los extremos superiores e inferiores, lo que indica que los residuos no siguen una distribución normal. En el Scale-Location hay una tendencia ascendente, lo que indica la presencia de heterocedasticidad, la dispersión de los residuos aumenta a medida que aumentan los valores predichos. En el Residuals vs Leverage se ve que los puntos 1524, 598 y 304 tiene un residuo grande y es un punto influyente que puede estar afectando mucho el modelo.
Residual_modelo2 <- residuals(modelo2)
shapiro.test(Residual_modelo2)
##
## Shapiro-Wilk normality test
##
## data: Residual_modelo2
## W = 0.78017, p-value < 2.2e-16
En el resultado arrojado por el test de normalidad de Shapiro-Wilk se puede apreciar que el p-value es muy pequeño y menor que un nivel de significancia del 0.05, eso significa que hay fuerte evidencia para rechazar la hipótesis de normalidad de los errores.
library(lmtest)
bptest(modelo2)
##
## studentized Breusch-Pagan test
##
## data: modelo2
## BP = 387.3, df = 7, p-value < 2.2e-16
En el resultado arrojado por el test de Breusch-Pagan se puede apreciar que el p-value es pequeño y menor que un nivel de significancia del 0.05, por tanto se concluye la presencia de heterocedasticidad con una significancia del 5%.
# Test de Durbin-Watson
dwtest(modelo2)
Durbin-Watson test
data: modelo2 DW = 2.0104, p-value = 0.5743 alternative hypothesis: true autocorrelation is greater than 0
# Test de Breusch-Godfrey
bgtest(modelo2)
Breusch-Godfrey test for serial correlation of order up to 1
data: modelo2 LM test = 0.038176, df = 1, p-value = 0.8451
Los p-value obtenidos en las test de Durbin-Watson y Breusch-Godfrey son muy pequeños, menores a 0.05, lo que indica que con un nivel de significancia del 5% se rechaza la hipótesis nula y los errores no son independientes, hay una autocorrelación positiva en los residuos del modelo.
library(car)
vif(modelo2)
## areaconst parqueaderos banios habitaciones estrato_4 estrato_5
## 2.597086 2.157472 2.870739 1.508443 5.905212 6.331508
## estrato_6
## 5.914481
Se evaluó la presencia de multicolinealidad mediante el Factor de Inflación de la Varianza (VIF). Los valores obtenidos oscilaron entre 1.44 y 6.35. La mayoría de las variables presentan valores inferiores a 5, lo que indica que no existe un problema fuerte de multicolinealidad entre las variables explicativas. Sin embargo, las variables asociadas a los estratos (estrato 4, 5 y 6) presentan valores ligeramente superiores a este umbral, lo cual puede deberse a la relación existente entre las variables dummy que representan las categorías del estrato. Aun así, estos valores se mantienen por debajo de 10, por lo que no se considera un problema grave para la estimación del modelo
En síntesis, la validación del modelo arrojo que, no hay
normalidad en los residuos, posible existencia de Valores atípicos o
influyentes, heterocedasticidad y no independencia de los errores, se
sugiere que, se apliquen transformaciones (logaritmo) a la variable
precio y las variables explicativas como por ejemplo logaritmo, realizar
tratamiento de valores atípicos (suavizarlos o eliminarlos) o
finalmente, elegir otro tipo de modelo.
predicciones2 <- predict(modelo2, newdata = test_data2)
resultados2 <- data.frame(Real = test_data2$preciom,
Predicho = predicciones2)
head(resultados2, 5)
## Real Predicho
## 1 220 184.77999
## 2 165 136.01950
## 3 125 79.23066
## 4 600 627.19367
## 5 680 622.51948
Al comparar los precios reales con los estimados por el modelo se evidencia que logra aproximarse bastante a los precios reales de las viviendas, aunque tiende a subestimar algunas propiedades de menor valor y sobrestimar algunas de mayor valor. Esto indica que, aunque el modelo capta la tendencia general de los precios, existen desviaciones puntuales que podrían mejorar ajustando variables o revisando valores atípicos.
Se realiza la predicción del precio de una vivienda tipo casa
ubicada en la zona norte, con las siguientes características: área
construida de 300, 3 parqueadero, 3 baños y 5 habitaciones. Para un
estrato 5, el precio estimado es de 687, mientras que para un estrato 6,
el precio estimado aumenta a 815.
#Predicción para estrato 5
predict(modelo2,
newdata = data.frame(
areaconst = 300,
parqueaderos= 3,
banios= 3,
habitaciones=5,
estrato_4=0,
estrato_5=1,
estrato_6=0))
## 1
## 754.2063
#Predicción para estrato 6
predict(modelo2,
newdata = data.frame(
areaconst = 300,
parqueaderos= 3,
banios= 3,
habitaciones=5,
estrato_4=0,
estrato_5=0,
estrato_6=1))
## 1
## 877.3717
zona2r$precio_pred <- predict(modelo2, newdata = zona2r)
viviendas2_disponibles <- subset(
zona2r,
preciom <= 850 &
areaconst >= 300 &
habitaciones >= 4 &
banios >= 3 &
parqueaderos >= 2 &
estrato_5 ==1
)
# Convertir a data.frame para evitar problemas
ofertas_potenciales1 <- head(viviendas2_disponibles[order(-viviendas2_disponibles$preciom, -viviendas2_disponibles$areaconst ), ], 5)
ofertas_potenciales1[, c("areaconst","habitaciones","banios","parqueaderos","estrato","preciom","precio_pred")] %>%
kable(
caption = "Ofertas potenciales de vivienda dentro del presupuesto reduciendo número de habitaciones y parqueadero",
col.names = c("Area construida", "Habitaciones", "Banos", "Parqueaderos", "Estrato", "Precio real", "Precio estimado"),
digits = 2
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE,
position = "center"
)
| Area construida | Habitaciones | Banos | Parqueaderos | Estrato | Precio real | Precio estimado |
|---|---|---|---|---|---|---|
| 486 | 4 | 4 | 2 | 5 | 690 | 1150.16 |
| 600 | 5 | 4 | 2 | 5 | 650 | 1361.02 |
Con base en las características solicitadas para la vivienda y considerando el crédito pre-aprobado máximo de 850 millones de pesos,no se encontró ningun apartamento en la zona sur que con ese presupuesto cumpliera con todas las características, por lo cual, se proponen dos alternativas derivadas de reducir el número de habitaciones y parqueaderos, que estaría dentro del rango estimado:
• Oferta 1: vivienda de 486 m², con 4 habitaciones, 4 baños y 2 parqueadero, en estrato 5. Tiene un precio real de 690 millones.
• Oferta 2: vivienda de 600 m², con 5 habitaciones, 4 baños y 2 parqueaderos, también en estrato 5. Su precio real es de 650 millones.
Es importante señalar que, las opciones seleccionadas presentan características muy cercanas a las solicitadas y estan dentro del rango de precio, tambien se propone si desean aumentar el valor del credito pre aprobado les permitira acceder a todas las características deseadas.
A continuación, se presenta su ubicación geográfica:
library(leaflet)
icono_casa <-awesomeIcons(
icon = "map-marker",
iconColor = "white",
markerColor = "purple",
library = "fa"
)
leaflet(ofertas_potenciales1) %>%
addTiles() %>%
addAwesomeMarkers(
lng = ~longitud,
lat = ~latitud,
icon = icono_casa,
popup = ~paste(
"<b>Precio:</b>", preciom,
"<br><b>Área:</b>", areaconst,
"<br><b>Habitaciones:</b>", habitaciones,
"<br><b>Baños:</b>", banios
)
)
La estimación del precio de viviendas, tanto casas como
apartamentos, es un fenómeno complejo que depende de múltiples factores
y características específicas de cada inmueble. La utilización de
modelos de regresión lineal para estas estimaciones presenta desafíos
importantes, dado que los datos suelen tener propiedades que dificultan
el cumplimiento de los supuestos del modelo.
En ambos modelos, el precio de la vivienda aumenta con el área construida, número de baños, parqueaderos y estrato socioeconómico, reflejando que propiedades más amplias y mejor ubicadas valen más. En los apartamentos, se observó que más habitaciones reducen ligeramente el precio, probablemente por la reducción de tamaño por habitación.
El modelo para apartamentos mostró un R ajustado superior (83%) indicado mejor capacidad de predicción que el modelo para casas (explico el 63%), además de que hay mayor homogeneidad apartamentos zona sur y mayor heterogeneidad casa zona norte. Para las casas, el estrato socioeconómico demostró tener un efecto más marcado sobre el valor.
En el análisis se identificó que ninguno de los modelos construidos cumple completamente con los supuestos de normalidad, homocedasticidad e independencia de los residuos. Además, la presencia de valores atípicos o influyentes impactan significativamente la estimación, lo que implica que las predicciones pueden ser precisas para la mayoría de las viviendas, pero pueden subestimar propiedades muy caras o sobrestimar las más económicas.
Los modelos ayudan a recomendar las mejores opciones de compra dentro de su presupuesto. Por ejemplo, para un crédito de 350 millones, se pueden priorizar casas con mayor área construida o distribución óptima de habitaciones y baños. En los requisititos de los apartamentos, el presupuesto no alcanza para todas las características deseadas, por lo que se propusieron ajustes en habitaciones o parqueaderos, o aumento en el crédito para acceder a la vivienda ideal
Para los siguientes modelos se recomienda: • Explorar transformaciones logarítmicas a las variables. • Investigar la inclusión de variables adicionales. • Realizar una segmentación o agrupamiento de variables (por ejemplo, habitaciones en rangos) cuando algunas variables individuales no sean significativas. • Aplicar métodos robustos para manejar la heterocedasticidad. • Realizar un análisis más exhaustivo de valores atípicos y puntos influyentes que podrían distorsionar la estimación.