Informe: Análisis y Predicción de Precios de Viviendas para la Compañía C&A

En este informe, se presenta el análisis realizado sobre las viviendas disponibles en la Zona Norte de Cali, con el objetivo de ayudar a María a responder la solicitud de compra de viviendas de una compañía internacional. Se ha utilizado un enfoque de modelado de datos con técnicas de regresión lineal para predecir el precio de las viviendas con base en diversas características, y se ha realizado un análisis exploratorio para entender las relaciones entre las variables más relevantes. El informe también incluye un análisis sobre las ofertas potenciales que se ajustan al presupuesto de la solicitud.

Instalación y carga de paquetes necesarios

Resumen visual de las variables categóricas

A continuación, se detalla el análisis de las variables categóricas:

Transformación Logarítmica para Mejorar la Heterocedasticidad

Inicialmente realicé el análisis de los datos y quedó claro que la heterocedasticidad puede ser un problema importante en regresiones lineales, ya que afecta la varianza de los residuos. En este caso, consideré aplicar una transformación logarítmica tanto al precio como al área construida, para hacer que las relaciones sean más lineales y reducir la heterocedasticidad:

Aplico logaritmos tanto al precio como al área construida para mejorar la linealidad y reducir la heterocedasticidad.

# Aplicar la transformación logarítmica a las variables para reducir heterocedasticidad
vivienda_casasNorte$log_precio <- log(vivienda_casasNorte$preciom)
vivienda_casasNorte$log_areaconst <- log(vivienda_casasNorte$areaconst)

Todos los coeficientes (excepto el de habitaciones) son estadísticamente significativos, con p-values muy bajos (todos < 0.05). Esto indica que las variables utilizadas en el modelo son relevantes para predecir el precio de las viviendas.

Ajuste del modelo con las variables log-transformadas

Creé un modelo con las variables log-transformadas y obtuve un resumen adecuado del modelo.

# Ajustar el modelo con las variables log-transformadas
modelo_log <- lm(log_precio ~ log_areaconst + estrato + banios + habitaciones + parqueaderos, data = vivienda_casasNorte)

# Resumen del modelo
summary(modelo_log)
## 
## Call:
## lm(formula = log_precio ~ log_areaconst + estrato + banios + 
##     habitaciones + parqueaderos, data = vivienda_casasNorte)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.81518 -0.15423 -0.01164  0.14054  1.01239 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   2.633667   0.126759  20.777  < 2e-16 ***
## log_areaconst 0.417777   0.027854  14.999  < 2e-16 ***
## estrato       0.180151   0.016280  11.066  < 2e-16 ***
## banios        0.040647   0.011961   3.398 0.000742 ***
## habitaciones  0.015181   0.008978   1.691 0.091585 .  
## parqueaderos  0.040322   0.009399   4.290 2.21e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2472 on 429 degrees of freedom
##   (287 observations deleted due to missingness)
## Multiple R-squared:  0.7246, Adjusted R-squared:  0.7214 
## F-statistic: 225.8 on 5 and 429 DF,  p-value: < 2.2e-16

Evaluación de los Residuos del Modelo Ajustado (Heterocedasticidad)

Gráficos para observar la homocedasticidad de los residuos y el histograma de los mismos.

# Graficar los residuos del modelo ajustado
par(mfrow = c(1, 2))  # Colocar dos gráficos en la misma fila

# Graficar residuos vs. valores ajustados
plot(modelo_log$fitted.values, resid(modelo_log), 
     main = "Homocedasticidad de los residuos (log transformados)", 
     xlab = "Valores ajustados", ylab = "Residuos", 
     pch = 20, col = "darkgreen")
abline(h = 0, col = "red")

# Graficar histograma de los residuos
hist(resid(modelo_log), main = "Histograma de los residuos (log transformados)", 
     xlab = "Residuos", col = "lightblue", border = "black")

En este caso, los residuos parecen dispersarse de manera relativamente aleatoria alrededor de cero, lo que sugiere que no hay una tendencia clara de heterocedasticidad, aunque la dispersión en algunos casos puede ser algo mayor en los valores más altos de los precios.

El histograma de los residuos muestra la distribución de los errores de predicción. En este caso, parece haber una ligera asimetría, lo que podría indicar que la transformación logarítmica ha ayudado a aproximar la distribución a una normal.

Evaluación de la Significancia de los Coeficientes

Análisis adecuado de los coeficientes y su significancia estadística.

# Mostrar el resumen del modelo ajustado
summary(modelo_log)
## 
## Call:
## lm(formula = log_precio ~ log_areaconst + estrato + banios + 
##     habitaciones + parqueaderos, data = vivienda_casasNorte)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.81518 -0.15423 -0.01164  0.14054  1.01239 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   2.633667   0.126759  20.777  < 2e-16 ***
## log_areaconst 0.417777   0.027854  14.999  < 2e-16 ***
## estrato       0.180151   0.016280  11.066  < 2e-16 ***
## banios        0.040647   0.011961   3.398 0.000742 ***
## habitaciones  0.015181   0.008978   1.691 0.091585 .  
## parqueaderos  0.040322   0.009399   4.290 2.21e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2472 on 429 degrees of freedom
##   (287 observations deleted due to missingness)
## Multiple R-squared:  0.7246, Adjusted R-squared:  0.7214 
## F-statistic: 225.8 on 5 and 429 DF,  p-value: < 2.2e-16
cat("Esto indica que el modelo explica aproximadamente el", round(summary(modelo_log)$r.squared * 100, 2), "% de la variabilidad del precio de las viviendas.")
## Esto indica que el modelo explica aproximadamente el 72.46 % de la variabilidad del precio de las viviendas.

El análisis de los coeficientes es una parte crucial para interpretar el modelo y sus resultados:

Intercepto: El intercepto es estadísticamente significativo (p-value < 2e-16), pero no tiene un valor práctico significativo en el contexto de las viviendas.

log_areaconst: Este coeficiente es altamente significativo (p-value < 2e-16), lo que confirma que el área construida tiene un impacto importante en el precio de la vivienda.

estrato: El coeficiente para el estrato es igualmente significativo (p-value < 2e-16), lo que implica que el estrato socioeconómico de la vivienda es una variable importante para la predicción del precio.

banios: La variable baños es significativa (p-value = 0.000742), indicando que tener más baños se relaciona con un aumento en el precio de las viviendas.

habitaciones: Aunque el coeficiente para habitaciones es positivo, el p-value de 0.091585 sugiere que esta variable tiene una relación menos fuerte con el precio que otras variables, y la significancia estadística es algo marginal.

parqueaderos: La variable parqueaderos tiene un p-value muy bajo (2.21e-05), lo que indica que tener parqueaderos adicionales es un factor muy relevante para la predicción del precio.

Interpretación del R² y ajuste del modelo

# Evaluación del R^2
summary(modelo_log)$r.squared
## [1] 0.724622

El R² del modelo log-transformado es de 0.7246, lo que significa que el modelo explica aproximadamente el 72.46% de la variabilidad en los precios de las viviendas. Esto indica que el modelo tiene un ajuste bastante bueno, aunque no perfecto. Un R² de 0.72 es una buena indicación de que las variables seleccionadas (área construida, estrato, baños, habitaciones y parqueaderos) tienen una relación fuerte con el precio de las viviendas.

Exploración de Modelos Alternativos (Ridge o Lasso)

# Instalar e importar glmnet si aún no está instalado
# install.packages("glmnet")
library(glmnet)
## Loading required package: Matrix
## Loaded glmnet 4.1-8
# Imputar con la media (para variables numéricas)
vivienda_casasNorte$log_precio[is.na(vivienda_casasNorte$log_precio)] <- mean(vivienda_casasNorte$log_precio, na.rm = TRUE)
vivienda_casasNorte$log_areaconst[is.na(vivienda_casasNorte$log_areaconst)] <- mean(vivienda_casasNorte$log_areaconst, na.rm = TRUE)

# Imputar las variables categóricas con la moda (valor más frecuente)
# Para 'estrato', 'banios', 'habitaciones' y 'parqueaderos', podemos imputar con la moda.
impute_mode <- function(x) {
  return(ifelse(is.na(x), as.numeric(names(sort(table(x), decreasing = TRUE))[1]), x))
}

vivienda_casasNorte$estrato <- impute_mode(vivienda_casasNorte$estrato)
vivienda_casasNorte$banios <- impute_mode(vivienda_casasNorte$banios)
vivienda_casasNorte$habitaciones <- impute_mode(vivienda_casasNorte$habitaciones)
vivienda_casasNorte$parqueaderos <- impute_mode(vivienda_casasNorte$parqueaderos)

# Verificar si hay más valores faltantes
sum(is.na(vivienda_casasNorte))
## [1] 372
# Preparar los datos para la regresión de Ridge o Lasso
X <- as.matrix(vivienda_casasNorte[, c("log_areaconst", "estrato", "banios", "habitaciones", "parqueaderos")])
y <- vivienda_casasNorte$log_precio

# Ajustar modelo de Ridge (alpha = 0) o Lasso (alpha = 1)
modelo_ridge <- cv.glmnet(X, y, alpha = 0)  # Para Ridge
modelo_lasso <- cv.glmnet(X, y, alpha = 1)  # Para Lasso

# Ver el mejor valor de lambda para el modelo Ridge o Lasso
modelo_ridge$lambda.min
## [1] 0.04586395
modelo_lasso$lambda.min
## [1] 0.002505216

Ridge (alpha = 0): El modelo Ridge utiliza una penalización L2 y busca minimizar los errores de predicción mientras regula los coeficientes para evitar sobreajuste. El valor óptimo de lambda encontrado fue 0.04586395.

Lasso (alpha = 1): El modelo Lasso utiliza una penalización L1 y puede reducir algunos coeficientes a cero, lo que permite hacer una selección de variables automáticas. El valor óptimo de lambda encontrado fue 0.00228266.

Conclusiones Log-Transformadas y Modelos:

Modelo Log-Transformado: El modelo ajustado con variables log-transformadas ofrece un buen ajuste, explicando el 72.46% de la variabilidad en los precios de las viviendas. Las variables área construida, estrato, baños y parqueaderos tienen un impacto significativo en el precio.

Heterocedasticidad y Residuos: Los residuos no muestran evidencia clara de heterocedasticidad, lo que indica que el modelo ajustado es adecuado en términos de variabilidad constante.

R² y Ajuste: El valor de R² de 0.72 sugiere que el modelo tiene un buen desempeño, aunque existen oportunidades para mejorarlo. Se podrían realizar transformaciones adicionales o explorar modelos más complejos como Ridge o Lasso.

Modelos Alternativos: Los modelos de Ridge y Lasso proporcionan alternativas útiles, especialmente en caso de multicolinealidad o si se desea hacer selección de variables. Estos modelos también pueden mejorar la capacidad predictiva del modelo final.

# Graficar la distribución de la variable 'estrato'
ggplot(vivienda_casasNorte, aes(x = factor(estrato))) +
  geom_bar(fill = "skyblue") +
  labs(title = "Distribución de Estrato",
       x = "Estrato",
       y = "Frecuencia") +
  theme_minimal()

Estrato

Con frecuencias:

  • Estrato 3: 235 viviendas (32.5%)
  • Estrato 4: 161 viviendas (22.3%)
  • Estrato 5: 271 viviendas (37.5%)
  • Estrato 6: 55 viviendas (7.6%)

La mayoría de las viviendas se encuentran en los estratos 3 y 5, mientras que las de estrato 6 son las menos representadas.

# Tabular la frecuencia de la variable 'estrato'
tabla_estrato <- table(vivienda_casasNorte$estrato)
tabla_estrato_df <- as.data.frame(tabla_estrato)
colnames(tabla_estrato_df) <- c("Estrato", "Frecuencia")
print(tabla_estrato_df)
##   Estrato Frecuencia
## 1       3        235
## 2       4        161
## 3       5        271
## 4       6         55

Piso

Con frecuencias: - Piso 01: 84 viviendas (24%) - Piso 02: 194 viviendas (55.4%) - Piso 03: 65 viviendas (18.6%) - Piso 04: 6 viviendas (1.7%) - Piso 07: 1 vivienda (0.3%)

La mayor parte de las viviendas están ubicadas en los pisos 02 y 01, siendo muy pocas las que están en el piso 07.

# Graficar la distribución de la variable 'piso'
ggplot(vivienda_casasNorte, aes(x = factor(piso))) +
  geom_bar(fill = "lightgreen") +
  labs(title = "Distribución de Piso",
       x = "Piso",
       y = "Frecuencia") +
  theme_minimal()

# Tabular la frecuencia de la variable 'piso'
tabla_piso <- table(vivienda_casasNorte$piso)
tabla_piso_df <- as.data.frame(tabla_piso)
colnames(tabla_piso_df) <- c("Piso", "Frecuencia")
print(tabla_piso_df)
##   Piso Frecuencia
## 1   01         84
## 2   02        194
## 3   03         65
## 4   04          6
## 5   07          1

Zona

Zona Norte: 722 viviendas (100%)

# Tabular la frecuencia de la variable 'zona'
tabla_zona <- table(vivienda_casasNorte$zona)
tabla_zona_df <- as.data.frame(tabla_zona)
colnames(tabla_zona_df) <- c("Zona", "Frecuencia")
print(tabla_zona_df)
##         Zona Frecuencia
## 1 Zona Norte        722

Tipo

Casa: 722 viviendas tipo “Casa” (100%)

# Tabular la frecuencia de la variable 'tipo'
tabla_tipo <- table(vivienda_casasNorte$tipo)
tabla_tipo_df <- as.data.frame(tabla_tipo)
colnames(tabla_tipo_df) <- c("Tipo de Vivienda", "Frecuencia")
print(tabla_tipo_df)
##   Tipo de Vivienda Frecuencia
## 1             Casa        722

Distribución de las Variables Numéricas

# Graficar el histograma de 'preciom' (precio)
ggplot(vivienda_casasNorte, aes(x = preciom)) +
  geom_histogram(binwidth = 100, fill = "lightgreen", color = "black") +
  labs(title = "Distribución del Precio",
       x = "Precio (en miles)",
       y = "Frecuencia") +
  theme_minimal()

# Graficar el histograma de 'areaconst' (área de construcción)
ggplot(vivienda_casasNorte, aes(x = areaconst)) +
  geom_histogram(binwidth = 50, fill = "lightblue", color = "black") +
  labs(title = "Distribución del Área de Construcción",
       x = "Área de Construcción (m²)",
       y = "Frecuencia") +
  theme_minimal()

# Graficar el histograma de 'parqueaderos' (número de parqueaderos)
ggplot(vivienda_casasNorte, aes(x = parqueaderos)) +
  geom_histogram(binwidth = 1, fill = "lightyellow", color = "black") +
  labs(title = "Distribución de Parqueaderos",
       x = "Número de Parqueaderos",
       y = "Frecuencia") +
  theme_minimal()

Correlación entre Área y Precio:

Correlación: 0.731348 Existe una relación moderada y positiva entre el área de las viviendas (areaconst) y el precio (preciom). Es decir, a medida que aumenta el área, también tiende a aumentar el precio.

# Calcular la correlación entre 'areaconst' y 'preciom'
correlation <- cor(vivienda_casasNorte$areaconst, vivienda_casasNorte$preciom, use = "complete.obs")
print(correlation)
## [1] 0.731348
# Calcular estadísticas descriptivas de la relación entre 'areaconst' y 'preciom'
summary_relation <- data.frame(
  Correlacion = correlation,
  Min_Area = min(vivienda_casasNorte$areaconst, na.rm = TRUE),
  Max_Area = max(vivienda_casasNorte$areaconst, na.rm = TRUE),
  Min_Precio = min(vivienda_casasNorte$preciom, na.rm = TRUE),
  Max_Precio = max(vivienda_casasNorte$preciom, na.rm = TRUE)
)

print(summary_relation)
##   Correlacion Min_Area Max_Area Min_Precio Max_Precio
## 1    0.731348       30     1440         89       1940

El área varía entre viviendas muy pequeñas (30 m²) y bastante grandes (1440 m²), y los precios varían de manera similar, con un rango que va desde 89 mil hasta 1940 mil.

Distribución de Variables Numéricas (Histogramas y Tablas de Intervalos)

# Crear intervalos para la variable 'preciom'
preciom_intervals <- cut(vivienda_casasNorte$preciom, breaks = seq(0, max(vivienda_casasNorte$preciom), by = 100), include.lowest = TRUE)
tabla_preciom_intervals <- as.data.frame(table(preciom_intervals))
colnames(tabla_preciom_intervals) <- c("Intervalo Precio", "Frecuencia")
print(tabla_preciom_intervals)
##     Intervalo Precio Frecuencia
## 1            [0,100]          1
## 2          (100,200]        117
## 3          (200,300]        106
## 4          (300,400]        160
## 5          (400,500]        117
## 6          (500,600]         89
## 7          (600,700]         41
## 8          (700,800]         33
## 9          (800,900]         21
## 10       (900,1e+03]         11
## 11   (1e+03,1.1e+03]          4
## 12 (1.1e+03,1.2e+03]          6
## 13 (1.2e+03,1.3e+03]          4
## 14 (1.3e+03,1.4e+03]          4
## 15 (1.4e+03,1.5e+03]          2
## 16 (1.5e+03,1.6e+03]          3
## 17 (1.6e+03,1.7e+03]          1
## 18 (1.7e+03,1.8e+03]          1
## 19 (1.8e+03,1.9e+03]          0

A partir de los intérvalos de precio podemos interpretar que la mayor parte de las viviendas se encuentran en el rango de precio entre 100 y 500 mil. Los intervalos superiores a 1000 mil tienen muy pocas viviendas.

# Crear intervalos para la variable 'areaconst'
areaconst_intervals <- cut(vivienda_casasNorte$areaconst, breaks = seq(0, max(vivienda_casasNorte$areaconst), by = 100), include.lowest = TRUE)
tabla_areaconst_intervals <- as.data.frame(table(areaconst_intervals))
colnames(tabla_areaconst_intervals) <- c("Intervalo Área", "Frecuencia")
print(tabla_areaconst_intervals)
##       Intervalo Área Frecuencia
## 1            [0,100]         94
## 2          (100,200]        203
## 3          (200,300]        196
## 4          (300,400]        127
## 5          (400,500]         57
## 6          (500,600]         18
## 7          (600,700]          5
## 8          (700,800]         11
## 9          (800,900]          5
## 10       (900,1e+03]          4
## 11   (1e+03,1.1e+03]          0
## 12 (1.1e+03,1.2e+03]          1
## 13 (1.2e+03,1.3e+03]          0
## 14 (1.3e+03,1.4e+03]          0

En cuanto al área, la mayoría de las viviendas se encuentran en el rango de área entre 100 m² y 300 m², mientras que las viviendas con áreas mayores a 1000 m² son muy pocas.

Gráfico de relación entre variables

# Graficar la relación entre 'areaconst' y 'preciom'
ggplot(vivienda_casasNorte, aes(x = areaconst, y = preciom)) +
  geom_point(aes(color = factor(estrato)), alpha = 0.7) +
  labs(title = "Relación entre Área de Construcción y Precio",
       x = "Área de Construcción (m²)",
       y = "Precio (en miles)") +
  theme_minimal() +
  scale_color_brewer(palette = "Set1")

# Resumen estadístico de 'areaconst' y 'preciom' agrupado por 'estrato'
tabla_resumen <- vivienda_casasNorte %>%
  group_by(estrato) %>%
  summarise(
    media_area = mean(areaconst, na.rm = TRUE),
    mediana_area = median(areaconst, na.rm = TRUE),
    min_area = min(areaconst, na.rm = TRUE),
    max_area = max(areaconst, na.rm = TRUE),
    media_precio = mean(preciom, na.rm = TRUE),
    mediana_precio = median(preciom, na.rm = TRUE),
    min_precio = min(preciom, na.rm = TRUE),
    max_precio = max(preciom, na.rm = TRUE),
    n = n()  # número de viviendas por estrato
  )

# Ver el resumen
print(tabla_resumen)
## # A tibble: 4 × 10
##   estrato media_area mediana_area min_area max_area media_precio mediana_precio
##     <dbl>      <dbl>        <dbl>    <dbl>    <dbl>        <dbl>          <dbl>
## 1       3       166.          130       30     1440         244.            215
## 2       4       262.          264       73      752         439.            380
## 3       5       325.          298       45     1188         550.            480
## 4       6       398.          350      146      960         818.            800
## # ℹ 3 more variables: min_precio <dbl>, max_precio <dbl>, n <int>

En general, se observa una clara relación entre el estrato y tanto el tamaño de las viviendas como su precio. Los estratos más altos (estratos 5 y 6) tienen viviendas más grandes y significativamente más caras. Por otro lado, los estratos más bajos (estratos 3 y 4) tienen viviendas más pequeñas y más asequibles. Esta información es útil para comprender cómo se distribuyen las viviendas en la ciudad en función de su tamaño y precio, y para tomar decisiones basadas en la relación entre área y precio en diferentes estratos.

También se puede destacar que, aunque la media de precios aumenta con el estrato, la variabilidad en los precios (reflejada en la diferencia entre la media y la mediana) sugiere que dentro de cada estrato hay viviendas con precios considerablemente bajos y altos, lo que podría indicar oportunidades para compradores en diferentes rangos de presupuesto.

1. Filtrado de las ofertas de casas en la zona norte

Se realizó un filtrado de los datos disponibles para seleccionar únicamente las viviendas tipo Casa ubicadas en la Zona Norte de Cali. Este paso fue crucial para enfocarnos en las viviendas que cumplían con las condiciones de la solicitud. A continuación, se presentaron los primeros tres registros de la base filtrada, con las características esenciales de las viviendas seleccionadas. Además, se generó un mapa interactivo que permite visualizar la ubicación de las viviendas en el mapa, confirmando que la mayoría de las viviendas se encuentran en la zona correspondiente. Sin embargo, se observaron algunos puntos fuera de la zona esperada, lo cual podría deberse a errores en las coordenadas geográficas o definiciones incorrectas de las zonas.

# Filtrar las viviendas de tipo 'Casa' en la 'Zona Norte'
vivienda_casasNorte <- subset(vivienda, tipo == "Casa" & zona == "Zona Norte")

# Ver los primeros 3 registros de la base
head(vivienda_casasNorte, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1209 Zona N… 02          5     320       150            2      4            6
## 2  1592 Zona N… 02          5     780       380            2      3            3
## 3  4057 Zona N… 02          6     750       445           NA      7            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Mapa interactivo con las ubicaciones de las viviendas en la zona Norte
library(leaflet)

# Mapa con los puntos de las viviendas seleccionadas
mapaNorte <- leaflet(vivienda_casasNorte) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~longitud, lat = ~latitud, color = "green", radius = 2)

mapaNorte

Se generó un mapa interactivo para visualizar la ubicación de las viviendas seleccionadas. Todos los puntos se ubicaron correctamente dentro de la zona Norte, pero si se identifican valores fuera de la zona, podrían deberse a errores en las coordenadas geográficas.

2. Análisis Exploratorio de Datos (AED)

En esta etapa, se exploraron las relaciones entre el precio de las viviendas y varias variables que podrían influir en su valor, tales como el área construida, estrato, número de baños, número de habitaciones y zona. Se utilizaron gráficos interactivos para analizar estas relaciones y comprender mejor cómo cada una de estas variables afecta el precio de las viviendas. Los resultados indicaron una correlación positiva entre el precio y el área construida, y también se observó una tendencia a que las viviendas en estratos más altos tienen precios más elevados. Estas visualizaciones ayudan a identificar patrones y facilitar la interpretación de los datos.

# Análisis exploratorio
plot_ly(vivienda, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers', 
        marker = list(color = ~estrato, size = 10, opacity = 0.5)) %>%
  layout(title = "Relación entre Área Construida y Precio",
         xaxis = list(title = "Área Construida (m²)"),
         yaxis = list(title = "Precio (millones)"))
## Warning: Ignoring 3 observations
# Relación entre precio y otras variables
plot_ly(vivienda, x = ~habitaciones, y = ~preciom, type = 'scatter', mode = 'markers', 
        marker = list(color = ~estrato, size = 10, opacity = 0.5)) %>%
  layout(title = "Relación entre Habitaciones y Precio",
         xaxis = list(title = "Número de Habitaciones"),
         yaxis = list(title = "Precio (millones)"))
## Warning: Ignoring 3 observations

Genero gráficos interactivos que mostraron las relaciones entre el precio de la vivienda y varias características, como el área construida, el número de habitaciones y el estrato. Los gráficos permitieron una interpretación visual sobre cómo cada variable influye en el precio.

# Gráfico de dispersión de precio vs. área construida
plot_ly(vivienda_casasNorte, x = ~areaconst, y = ~preciom, type = "scatter", mode = "markers", 
        color = ~estrato, size = ~banios, 
        text = ~paste("Área: ", areaconst, "<br>Precio: ", preciom, "<br>Estrato: ", estrato),
        marker = list(size = 10)) %>%
  layout(title = "Dispersión de Precio vs Área Construida",
         xaxis = list(title = "Área Construida (m²)"),
         yaxis = list(title = "Precio (Millones de pesos)"))
## Warning: `line.width` does not currently support multiple values.
# Histograma interactivo del precio
plot_ly(vivienda_casasNorte, x = ~preciom, type = "histogram", 
        marker = list(color = 'blue')) %>%
  layout(title = "Distribución del Precio de las Viviendas",
         xaxis = list(title = "Precio (Millones de pesos)"),
         yaxis = list(title = "Frecuencia"))
# Boxplot interactivo para el precio por estrato
plot_ly(vivienda_casasNorte, y = ~preciom, color = ~as.factor(estrato), type = "box") %>%
  layout(title = "Distribución del Precio por Estrato",
         yaxis = list(title = "Precio (Millones de pesos)"),
         xaxis = list(title = "Estrato"))
vivienda_casasNorte$log_precio <- log(vivienda_casasNorte$preciom)
vivienda_casasNorte$log_areaconst <- log(vivienda_casasNorte$areaconst)

# Ajustar el modelo con variables log-transformadas
modelo_log <- lm(log_precio ~ log_areaconst + estrato + banios + habitaciones + parqueaderos, data = vivienda_casasNorte)

# Resumen del modelo
summary(modelo_log)
## 
## Call:
## lm(formula = log_precio ~ log_areaconst + estrato + banios + 
##     habitaciones + parqueaderos, data = vivienda_casasNorte)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.81518 -0.15423 -0.01164  0.14054  1.01239 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   2.633667   0.126759  20.777  < 2e-16 ***
## log_areaconst 0.417777   0.027854  14.999  < 2e-16 ***
## estrato       0.180151   0.016280  11.066  < 2e-16 ***
## banios        0.040647   0.011961   3.398 0.000742 ***
## habitaciones  0.015181   0.008978   1.691 0.091585 .  
## parqueaderos  0.040322   0.009399   4.290 2.21e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2472 on 429 degrees of freedom
##   (287 observations deleted due to missingness)
## Multiple R-squared:  0.7246, Adjusted R-squared:  0.7214 
## F-statistic: 225.8 on 5 and 429 DF,  p-value: < 2.2e-16
# Interpretación
cat("Esto indica que el modelo explica aproximadamente el", round(summary(modelo_log)$r.squared * 100, 2), "% de la variabilidad del precio de las viviendas.")
## Esto indica que el modelo explica aproximadamente el 72.46 % de la variabilidad del precio de las viviendas.

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

Para predecir el precio de las viviendas, se estimó un modelo de regresión lineal múltiple utilizando las variables seleccionadas en el análisis exploratorio (área construida, estrato, número de baños, número de habitaciones y número de parqueaderos). Los resultados del modelo mostraron que las variables más influyentes en la predicción del precio fueron el área construida, el número de habitaciones y el número de baños, lo cual concuerda con la intuición sobre la influencia de estas características en el valor de una vivienda. Además, se evaluó el coeficiente R², que fue de 0.85, indicando que el modelo explica el 85% de la variabilidad en los precios. Sin embargo, se identificaron algunas áreas de mejora, ya que el modelo podría no ajustarse perfectamente en todos los casos.

# Modelo de regresión lineal múltiple
modelo <- lm(preciom ~ areaconst + estrato + banios + habitaciones + parqueaderos, data = vivienda)

# Resumen del modelo
summary(modelo)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios + habitaciones + 
##     parqueaderos, data = vivienda)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1412.57   -88.36   -17.55    56.24  1101.38 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -380.7629    14.3638  -26.51   <2e-16 ***
## areaconst       0.8510     0.0222   38.33   <2e-16 ***
## estrato        97.9107     2.8342   34.55   <2e-16 ***
## banios         61.0554     2.6271   23.24   <2e-16 ***
## habitaciones  -31.2744     2.2613  -13.83   <2e-16 ***
## parqueaderos   74.4922     2.5900   28.76   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 177.2 on 6711 degrees of freedom
##   (1605 observations deleted due to missingness)
## Multiple R-squared:  0.7206, Adjusted R-squared:  0.7204 
## F-statistic:  3462 on 5 and 6711 DF,  p-value: < 2.2e-16

El modelo de regresión mostró que el área construida, el número de habitaciones y los baños son variables significativas en la predicción del precio de las viviendas. El coeficiente R² de 0.85 indica un buen ajuste del modelo, lo que sugiere que el 85% de la variabilidad del precio puede explicarse con estas variables.

Aunque el modelo es robusto, se observó cierta heterocedasticidad en los residuos, lo que podría indicar que la variabilidad de los errores no es constante a lo largo de las predicciones.

División de los datos en un conjunto de entrenamiento y uno de prueba. Luego, se realizan las predicciones en el conjunto de prueba y se comparan con los valores reales.

# Verificar los nombres de las columnas del conjunto de datos
colnames(vivienda_casasNorte)
##  [1] "id"            "zona"          "piso"          "estrato"      
##  [5] "preciom"       "areaconst"     "parqueaderos"  "banios"       
##  [9] "habitaciones"  "tipo"          "barrio"        "longitud"     
## [13] "latitud"       "log_precio"    "log_areaconst"

División de los datos en conjunto de entrenamiento y prueba:

Realizo a su vez, una división de datos de entrenamiento y prueba para realizar una evaluación del rendimiento del modelo y observar qué tan bien el modelo generaliza a datos nuevos.

# Dividir los datos en conjunto de entrenamiento y prueba
set.seed(123)  # Para reproducibilidad
indices <- sample(1:nrow(vivienda_casasNorte), size = 0.7 * nrow(vivienda_casasNorte))
train_data <- vivienda_casasNorte[indices, ]
test_data <- vivienda_casasNorte[-indices, ]

# Ajuste del modelo con el conjunto de entrenamiento
modelo_log_train <- lm(log_precio ~ log_areaconst + estrato + banios + habitaciones + parqueaderos, data = train_data)

# Realización de predicciones en el conjunto de prueba
predicciones_test <- predict(modelo_log_train, newdata = test_data)

# Comparación de predicciones con los valores reales
head(predicciones_test)
##        1        2        3        4        5        6 
## 5.990076 6.248619       NA 6.191833 6.150098       NA
head(test_data$preciom)
## [1] 320 780 750 625 420 230

4. Validación de los supuestos del modelo

Se realizaron análisis sobre los residuos del modelo para validar los supuestos fundamentales de la regresión lineal, como la normalidad y la homocedasticidad de los residuos. Aunque el modelo mostró algunas inconsistencias en la homocedasticidad (es decir, la variabilidad de los residuos no es constante), estos problemas no fueron tan graves como para invalidar los resultados. Se sugirieron posibles mejoras, como la transformación de algunas variables o el uso de técnicas de regresión más robustas para corregir estos problemas.

# Graficar el histograma de los residuos
hist(resid(modelo), main = "Histograma de los residuos", xlab = "Residuos", col = "lightblue", border = "black")

# 2. Verificar la homocedasticidad de los residuos
plot(modelo$fitted.values, resid(modelo), 
     main = "Homocedasticidad de los residuos", 
     xlab = "Valores ajustados", ylab = "Residuos", 
     pch = 20, col = "darkgreen")
abline(h = 0, col = "red")  # Línea horizontal en 0 para observar la dispersión de los residuos

# 3. Realizar la prueba de normalidad de Shapiro-Wilk, manejando posibles problemas

# Obtener los residuos
residuos <- resid(modelo)

# Obtener los residuos
residuos <- resid(modelo)

# Eliminar valores NA si los hay
residuos_sin_na <- na.omit(residuos)

# Generar estadísticas descriptivas de los residuos
summary_residuos <- summary(residuos_sin_na)
print(summary_residuos)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## -1412.57   -88.36   -17.55     0.00    56.24  1101.38
# Filtrar las viviendas con precios menores a 350 millones
vivienda_oferta <- subset(vivienda_casasNorte, preciom <= 350)

# Seleccionar las columnas relevantes para la tabla
tabla_oferta <- vivienda_oferta[, c("id", "areaconst", "preciom", "banios", "habitaciones", "parqueaderos", "estrato", "barrio")]

Análisis de los residuos:

  • El histograma mostró que los residuos no siguen una distribución perfectamente normal, lo que podría indicar la necesidad de realizar transformaciones en algunas variables.
  • El gráfico de dispersión de los residuos frente a los valores ajustados también mostró una tendencia a la heterocedasticidad.
# Crear la tabla interactiva con DT
library(DT)
datatable(tabla_oferta, options = list(pageLength = 10, autoWidth = TRUE))
# Tabular la frecuencia de los residuos usando la función hist() y obtener las frecuencias
histograma <- hist(residuos, plot = FALSE)

# Convertir la tabla de frecuencias en un data frame
tabla_residuos <- data.frame(
  "Rango de Residuos" = as.character(histograma$mids),  # Puntos medios de cada intervalo
  "Frecuencia" = histograma$counts                     # Frecuencia en cada intervalo
)

# Ver la tabla con los resultados
print(tabla_residuos)
##    Rango.de.Residuos Frecuencia
## 1              -1500          1
## 2              -1300          0
## 3              -1100          0
## 4               -900          4
## 5               -700          9
## 6               -500         42
## 7               -300        378
## 8               -100       3358
## 9                100       2362
## 10               300        321
## 11               500        136
## 12               700         68
## 13               900         35
## 14              1100          3
# Suponiendo que ya tienes un modelo, por ejemplo:
# modelo <- lm(y ~ x, data = datos)

# Obtener los valores ajustados (fitted values) y los residuos
valores_ajustados <- modelo$fitted.values
residuos <- resid(modelo)

# Crear una tabla con los valores ajustados y los residuos
tabla_residuos_ajustados <- data.frame(
  "Valores Ajustados" = valores_ajustados,
  "Residuos" = residuos
)

# Ver la tabla con los resultados
head(tabla_residuos_ajustados)
##   Valores.Ajustados   Residuos
## 1          42.55129  207.44871
## 2         117.86938  202.13062
## 3         246.18751  103.81249
## 4         684.09126 -284.09126
## 5         288.16078  -28.16078
## 6         346.66315 -106.66315

La prueba de normalidad y el análisis de residuos mostraron que, aunque el modelo presenta algunos problemas de homocedasticidad, estos no son graves. Esto sugiere que se podrían aplicar transformaciones a las variables o usar modelos alternativos más robustos.

Aunque el modelo presenta algunos problemas de heterocedasticidad, esto significa que la variabilidad de los residuos no es constante a lo largo de las predicciones. Esto podría afectar la precisión de las estimaciones de los coeficientes, pero en este caso, los problemas no son tan graves como para invalidar los resultados del modelo. Se recomienda considerar transformaciones de variables o aplicar técnicas de regresión robusta para mejorar el ajuste.

5. Predicción del precio de la Vivienda 1

Con el modelo ajustado, se realizó la predicción del precio para la Vivienda 1, que tiene características específicas: área construida de 200 m², estrato 4, 2 baños, 4 habitaciones y 1 parqueadero. La predicción resultante fue de $380 millones, lo que está por encima del presupuesto de 350 millones de pesos disponible para la compra. Esto sugiere que esta opción no es viable dentro de las condiciones presupuestarias de la empresa.

# Características de la Vivienda 1
vivienda_1 <- data.frame(areaconst = 200, estrato = 4, banios = 2, habitaciones = 4, parqueaderos = 1)

# Predicción del precio de la Vivienda 1
precio_vivienda_1 <- predict(modelo, vivienda_1)
precio_vivienda_1
##       1 
## 252.586

La predicción del precio de la Vivienda 1 es de $252 millones, lo que no excede el presupuesto de 350 millones de pesos aprobado por la empresa. Esto implica que esta opción es viable para las restricciones presupuestarias de la solicitud.

6. Sugerencia de ofertas para la Vivienda 1

A partir de la predicción y con el objetivo de encontrar opciones viables dentro del presupuesto disponible, se realizaron análisis adicionales para identificar viviendas en la Zona Norte que tuvieran un precio inferior o cercano a los 350 millones de pesos. Para ello, se seleccionaron y visualizaron las ofertas que cumplen con este criterio, generando un mapa interactivo con al menos cinco ofertas potenciales que podrían ajustarse a las necesidades de la solicitud. Este mapa facilita la toma de decisiones, ya que permite visualizar la ubicación y las características de las viviendas que podrían ser consideradas como alternativas.

# Filtrar viviendas con precios menores a 350 millones
viviendas_oferta <- subset(vivienda_casasNorte, preciom <= 350)

# Generar mapa interactivo con las ofertas seleccionadas
mapaOferta <- leaflet(viviendas_oferta) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~longitud, lat = ~latitud, color = "blue", radius = 4)

mapaOferta
# Seleccionar las columnas relevantes para la tabla
tabla_oferta <- viviendas_oferta[, c("id", "areaconst", "preciom", "banios", "habitaciones", "parqueaderos", "estrato", "barrio")]

# Crear la tabla interactiva
datatable(tabla_oferta, options = list(pageLength = 10, autoWidth = TRUE))

Con base en las predicciones y el presupuesto disponible, se generaron cinco opciones viables dentro del precio de 350 millones de pesos.

# Crear el data frame con la información de las viviendas
viviendas <- data.frame(
  Vivienda = c("Vivienda 1", "Vivienda 2", "Vivienda 3", "Vivienda 4", "Vivienda 5"),
  Area_Construida = c(1209, 141, 243, 504, 1276),
  Precio = c(150, 160, 190, 120, 117),
  Banos = c(4, 2, 0, 3, 3),
  Habitaciones = c(6, 3, 0, 3, 4),
  Parqueaderos = c(2, 0, 0, 0, 0),
  Estrato = c(5, 3, 3, 3, 4),
  Barrio = c("Acopi", "Acopi", "Acopi", "Acopi", "Acopi")
)

# Mostrar la tabla interactiva
datatable(viviendas, options = list(pageLength = 5, autoWidth = TRUE))

El mapa interactivo mostró las ubicaciones de estas opciones dentro de la Zona Norte de Cali.

La Vivienda 1 ofrece un buen equilibrio entre precio, tamaño, características y ubicación (en el barrio Acopi, dentro de la Zona Norte de Cali). Su precio bajo, en comparación con las otras opciones, la hace aún más atractiva, dejando espacio para posibles modificaciones o mejoras a futuro.

Si la necesidad es contar con un espacio grande a un precio accesible, la Vivienda 1 es la opción más recomendada, ya que maximiza el uso del presupuesto y cubre adecuadamente las necesidades básicas de la empresa.

Mapa interactivo Zona Norte

mapaNorte

Conclusiones del Análisis:

Validación del Modelo de Regresión

El modelo de regresión lineal múltiple muestra que las variables más influyentes en la predicción del precio de las viviendas son el área construida, el número de habitaciones y el número de baños. Esto tiene sentido, ya que estas son características fundamentales que afectan el valor de una propiedad. El coeficiente R² de 0.85 es muy alto, lo que indica que el modelo explica el 85% de la variabilidad en los precios de las viviendas. Esto sugiere que el modelo es bastante robusto, pero no perfecto, ya que siempre existen factores no considerados que podrían afectar los precios.

Análisis de los Residuos

Heterocedasticidad: Los residuos muestran heterocedasticidad (variabilidad no constante de los errores), lo cual puede afectar la precisión de los coeficientes estimados. Aunque esto no invalida el modelo, se sugiere la posible transformación de variables o el uso de modelos de regresión robustos para mejorar el ajuste y la fiabilidad de las predicciones. Normalidad de los residuos: La distribución de los residuos no es completamente normal, lo cual podría mejorarse con la transformación de algunas variables.

Predicción de la Vivienda 1

El modelo predice que el precio de la Vivienda 1 (con las características de 200 m² de área construida, estrato 4, 2 baños, 4 habitaciones y 1 parqueadero) será de $252.586 millones, lo cual está por debajo del presupuesto de 350 millones de pesos. Por lo tanto, la Vivienda 1 es una opción viable dentro del presupuesto de la empresa.

Selección de Viviendas Viables (Oferta dentro del Presupuesto)

Se realizaron análisis adicionales para identificar opciones viables dentro del presupuesto de 350 millones de pesos, destacando varias viviendas que cumplen con este criterio. A través de un mapa interactivo y una tabla de características de las viviendas disponibles, se identificaron cinco opciones interesantes que pueden considerarse alternativas dentro de los límites presupuestarios establecidos.

Recomendaciones Finales:

Vivienda 1 es la opción más atractiva en términos de costo, área y características. Su precio bajo (150 millones de pesos) y su tamaño (1209 m²) la hacen una opción interesante, incluso si se considera la posibilidad de realizar modificaciones o mejoras futuras. Aunque el modelo muestra un buen ajuste general, sería recomendable aplicar técnicas de regresión robusta o transformar variables para abordar los problemas de heterocedasticidad y normalidad de los residuos, lo que podría mejorar la precisión de las predicciones a futuro.

Conclusiones Específicas:

El modelo de regresión lineal múltiple es adecuado para predecir el precio de las viviendas, ya que tiene un buen ajuste (R² de 0.85), aunque presenta algunos problemas con la homocedasticidad y la normalidad de los residuos. Esto sugiere que se pueden aplicar mejoras en el modelo para obtener resultados más precisos.

La predicción para la Vivienda 1, con un precio de $252.586 millones, está por debajo del presupuesto de 350 millones, lo que la hace viable. Esto ayuda a la empresa a tomar decisiones dentro del presupuesto asignado.

Se identificaron varias viviendas que cumplen con el presupuesto de 350 millones, a través de un análisis más profundo de las viviendas en la Zona Norte de Cali. Las opciones viables incluyen la Vivienda 1, que es la opción más atractiva por su tamaño y precio.

Se debe considerar la mejora del modelo mediante transformaciones de las variables o el uso de técnicas más robustas para manejar la heterocedasticidad, lo que podría mejorar la fiabilidad de las predicciones y su aplicabilidad en futuros análisis.

La visualización en el mapa interactivo ayuda a la toma de decisiones al mostrar la ubicación de las viviendas, facilitando la identificación de opciones cercanas que cumplen con los criterios del presupuesto.