#MODELO DE REGRESIÒN CON DATOS DE VENTAS DE VIVIENDA EN CALI

#Cargar librerías necesarias
library(tidyverse)
library(caret)
library(GGally)
library(readxl)
library(ggplot2)
#Cargar los datos
Datos_Vivienda <- read_excel("D:/Datos_Vivienda.xlsx")
# Revisar los primeros registros y estructura de los datos
head(Datos_Vivienda)
str(Datos_Vivienda)
summary(Datos_Vivienda)
## # A tibble: 6 × 12
##   Zona       piso  Estrato precio_millon Area_contruida parqueaderos Banos
##   <chr>      <chr>   <dbl>         <dbl>          <dbl> <chr>        <dbl>
## 1 Zona Sur   2           6           880            237 2                5
## 2 Zona Oeste 2           4          1200            800 3                6
## 3 Zona Sur   3           5           250             86 NA               2
## 4 Zona Sur   NA          6          1280            346 4                6
## 5 Zona Sur   2           6          1300            600 4                7
## 6 Zona Sur   3           6           513            160 2                4
## # ℹ 5 more variables: Habitaciones <dbl>, Tipo <chr>, Barrio <chr>,
## #   cordenada_longitud <dbl>, Cordenada_latitud <dbl>
## tibble [8,322 × 12] (S3: tbl_df/tbl/data.frame)
##  $ Zona              : chr [1:8322] "Zona Sur" "Zona Oeste" "Zona Sur" "Zona Sur" ...
##  $ piso              : chr [1:8322] "2" "2" "3" "NA" ...
##  $ Estrato           : num [1:8322] 6 4 5 6 6 6 6 5 4 6 ...
##  $ precio_millon     : num [1:8322] 880 1200 250 1280 1300 513 870 310 240 690 ...
##  $ Area_contruida    : num [1:8322] 237 800 86 346 600 160 490 82.5 80 150 ...
##  $ parqueaderos      : chr [1:8322] "2" "3" "NA" "4" ...
##  $ Banos             : num [1:8322] 5 6 2 6 7 4 6 2 2 5 ...
##  $ Habitaciones      : num [1:8322] 4 7 3 5 5 4 5 3 3 4 ...
##  $ Tipo              : chr [1:8322] "Casa" "Casa" "Apartamento" "Apartamento" ...
##  $ Barrio            : chr [1:8322] "pance" "miraflores" "multicentro" "ciudad jardín" ...
##  $ cordenada_longitud: num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ Cordenada_latitud : num [1:8322] 3.43 3.43 3.43 3.43 3.43 ...
##      Zona               piso              Estrato      precio_millon   
##  Length:8322        Length:8322        Min.   :3.000   Min.   :  58.0  
##  Class :character   Class :character   1st Qu.:4.000   1st Qu.: 220.0  
##  Mode  :character   Mode  :character   Median :5.000   Median : 330.0  
##                                        Mean   :4.634   Mean   : 433.9  
##                                        3rd Qu.:5.000   3rd Qu.: 540.0  
##                                        Max.   :6.000   Max.   :1999.0  
##                                        NA's   :3       NA's   :2       
##  Area_contruida   parqueaderos           Banos         Habitaciones   
##  Min.   :  30.0   Length:8322        Min.   : 0.000   Min.   : 0.000  
##  1st Qu.:  80.0   Class :character   1st Qu.: 2.000   1st Qu.: 3.000  
##  Median : 123.0   Mode  :character   Median : 3.000   Median : 3.000  
##  Mean   : 174.9                      Mean   : 3.111   Mean   : 3.605  
##  3rd Qu.: 229.0                      3rd Qu.: 4.000   3rd Qu.: 4.000  
##  Max.   :1745.0                      Max.   :10.000   Max.   :10.000  
##  NA's   :3                           NA's   :3        NA's   :3       
##      Tipo              Barrio          cordenada_longitud Cordenada_latitud
##  Length:8322        Length:8322        Min.   :-76.59     Min.   :3.333    
##  Class :character   Class :character   1st Qu.:-76.54     1st Qu.:3.381    
##  Mode  :character   Mode  :character   Median :-76.53     Median :3.416    
##                                        Mean   :-76.53     Mean   :3.418    
##                                        3rd Qu.:-76.52     3rd Qu.:3.452    
##                                        Max.   :-76.46     Max.   :3.498    
##                                        NA's   :3          NA's   :3
#Tratamos datos faltantes o NA
is.na(Datos_Vivienda)
colSums(is.na(Datos_Vivienda))
datos <- na.omit(Datos_Vivienda)
#Visualización espacial de la información
require(leaflet)
library(htmltools)

#Mapa 1
leaflet() %>% addCircleMarkers(lng= datos$cordenada_longitud, lat= datos$Cordenada_latitud, radius=1.0, color= "purple", label= datos$id)%>% addTiles()
## Warning: Unknown or uninitialised column: `id`.
# Convertir columnas categóricas a factor. Este paso es necesario para correr un modelo lineal como el de regresión. Asi se entiende que esas variables son dummy.
datos <- datos %>%
  mutate(
    Zona = as.factor(Zona),
    Tipo = as.factor(Tipo),
    Barrio = as.factor(Barrio)
  )
# Gráficos de distribución
ggplot(datos, aes(x = precio_millon)) +
  geom_histogram(bins = 30, fill = "skyblue", color = "black") +
  labs(title = "Distribución del Precio de Viviendas (Millones)", x = "Precio (Millones)", y = "Frecuencia")

ggplot(datos, aes(x = Area_contruida)) +
  geom_histogram(bins = 30, fill = "lightgreen", color = "black") +
  labs(title = "Distribución del Área Construida", x = "Área Construida (m²)", y = "Frecuencia")

# Gráfico de correlación
numeric_vars <- datos %>%
  select(precio_millon, Area_contruida, parqueaderos, Banos, Habitaciones) %>%
  na.omit()
ggpairs(numeric_vars, title = "Matriz de Correlación entre Variables Numéricas")

#Otra forma de graficar relaciones entre variables cuantitativas
require(ggplot2)
require(plotly)

g1=ggplot(data = datos,aes(y=precio_millon, x=Area_contruida)) + geom_point() + geom_smooth()
ggplotly(g1)
#Aquí se segmenta las viviendas con área construida menor a 300mts2
pos2=which(datos$Area_contruida<300)
datos2=datos[pos2,]

g2=ggplot(data = datos2,aes(y=precio_millon, x=Area_contruida)) + geom_point() + geom_smooth()
ggplotly(g2)

##Modelo lineal simple y múltiple El modelo_simle toma el precio_millon como variable dependiente y una variable explicativa, como Area_contruida. Se estima el modelo de regresión simple y se visualiza con un gráfico de dispersión y la línea de regresión. La interpretación se puede hacer observando el valor de los coeficientes

# Modelo de regresión lineal simple
modelo_simple <- lm(precio_millon ~ Area_contruida, data = datos)
summary(modelo_simple)
## 
## Call:
## lm(formula = precio_millon ~ Area_contruida, data = datos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2659.88  -120.78   -47.55    67.27  1330.10 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    157.47636    4.13640   38.07   <2e-16 ***
## Area_contruida   1.58018    0.01831   86.30   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 238.7 on 8317 degrees of freedom
## Multiple R-squared:  0.4725, Adjusted R-squared:  0.4724 
## F-statistic:  7448 on 1 and 8317 DF,  p-value: < 2.2e-16
# Interpretación gráfica
ggplot(datos, aes(x = Area_contruida, y = precio_millon)) +
  geom_point(color = "blue") +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  labs(title = "Regresión Lineal Simple: Precio vs. Área Construida",
       x = "Área Construida (m²)", y = "Precio (Millones)")

Aquí se incluyen más variables explicativas. En este paso, se estima el modelo de regresión múltiple y se revisan sus supuestos usando gráficos de diagnóstico.

En el modelo_multiple el intercepto debe analizarse con detenimiento para ver si tiene sentido interpretarlo. En este caso es el valor d euna vivienda ubicada en el centro, con àrea igual a cero, baño=0

INTERPRETACIÒN:

Área construida:Cada metro cuadrado adicional de área construida incrementa el precio en 1.16 millones de unidades monetarias. Es decir, a mayor área, mayor precio de la propiedad.

Zona norte: Si la propiedad está en la zona norte, el precio aumentará en $75 millones en comparación con la zona centro, que es la base.

Zona oeste: Las propiedades en la zona oeste tienen un precio $313 millones más alto que las de la zona centro, lo que indica que esta zona tiene un impacto muy positivo en el precio.

Zona oriente: Las propiedades en la zona oriente tienen un precio $58 millones más bajo que las de la zona centro, lo que sugiere que esta zona es menos costosa.

Baños: Cada baño adicional incrementa el precio de la propiedad en $103.27 millones, lo que sugiere que tener más baños es un factor importante que aumenta el valor de la propiedad.

# Modelo de regresión lineal múltiple
modelo_multiple <- lm(precio_millon ~ Area_contruida + Zona + Banos, data = datos)
summary(modelo_multiple)
## 
## Call:
## lm(formula = precio_millon ~ Area_contruida + Zona + Banos, data = datos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1630.16   -89.76   -22.67    61.22  1206.41 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      -113.02845   18.55097  -6.093 1.16e-09 ***
## Area_contruida      1.05441    0.02032  51.891  < 2e-16 ***
## ZonaZona Norte     75.28142   18.59458   4.049 5.20e-05 ***
## ZonaZona Oeste    313.69122   18.97010  16.536  < 2e-16 ***
## ZonaZona Oriente  -72.26882   20.95469  -3.449 0.000566 ***
## ZonaZona Sur      112.50242   18.27609   6.156 7.82e-10 ***
## Banos              76.83829    2.05700  37.354  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 200.6 on 8312 degrees of freedom
## Multiple R-squared:  0.6278, Adjusted R-squared:  0.6276 
## F-statistic:  2337 on 6 and 8312 DF,  p-value: < 2.2e-16

##Validaciòn supuestos

  1. El gráfico de los residuos frente a los valores ajustados (residuos vs. valores ajustados), verifica la homocedasticidad (varianza constante de los errores) y la linealidad del modelo.

Interpretación: Si los puntos están dispersos de manera aleatoria alrededor de la línea horizontal (que debe estar cerca de cero), se sugiere que los residuos tienen una varianza constante (homocedasticidad) y el modelo está capturando correctamente la relación lineal entre las variables. Si hay un patrón (como una forma curva o fan-shaped), indica problemas de heterocedasticidad o que la relación entre las variables no es estrictamente lineal.

  1. El Gráfico de Q-Q (Quantile-Quantile) de los residuos, evalúa si los residuos siguen una distribución normal.

Interpretación: Si los puntos en el gráfico de Q-Q siguen aproximadamente una línea recta, significa que los residuos se distribuyen de manera normal, lo cual es un supuesto importante para la regresión lineal. Si los puntos se desvían significativamente de la línea recta (especialmente en los extremos), sugiere que los residuos no siguen una distribución normal, lo cual puede afectar la validez de los intervalos de confianza y las pruebas de hipótesis.

En caso que no se validen los supuestos, se debe probar una transformaciòn de datos. Si despues de transformar los datos continua el problem aen los supuestos, en ese caso se concluye que el modelo de regressiòn lineal no seria òptimo para modelar esos datos.

#Evaluación de supuestos
par(mfrow = c(2, 2))  # Configurar para ver gráficos de diagnóstico
plot(modelo_multiple)

par(mfrow = c(1, 1))  # Volver al gráfico normal
# Selecciòn de variables step by step
modelo_multiple_step=step(modelo_multiple)
summary(modelo_multiple_step)
## Start:  AIC=88208.47
## precio_millon ~ Area_contruida + Zona + Banos
## 
##                  Df Sum of Sq       RSS   AIC
## <none>                        334406670 88208
## - Banos           1  56137710 390544380 89497
## - Zona            4  62190513 396597183 89619
## - Area_contruida  1 108332718 442739388 90541
## 
## Call:
## lm(formula = precio_millon ~ Area_contruida + Zona + Banos, data = datos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1630.16   -89.76   -22.67    61.22  1206.41 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      -113.02845   18.55097  -6.093 1.16e-09 ***
## Area_contruida      1.05441    0.02032  51.891  < 2e-16 ***
## ZonaZona Norte     75.28142   18.59458   4.049 5.20e-05 ***
## ZonaZona Oeste    313.69122   18.97010  16.536  < 2e-16 ***
## ZonaZona Oriente  -72.26882   20.95469  -3.449 0.000566 ***
## ZonaZona Sur      112.50242   18.27609   6.156 7.82e-10 ***
## Banos              76.83829    2.05700  37.354  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 200.6 on 8312 degrees of freedom
## Multiple R-squared:  0.6278, Adjusted R-squared:  0.6276 
## F-statistic:  2337 on 6 and 8312 DF,  p-value: < 2.2e-16

##Transformación Logarítmica Para mejorar la linealidad, aplicamos una transformación logarítmica.

Cuando realizas una transformación logarítmica en la variable dependiente (en este caso, el precio en millones), el modelo de regresión interpreta los coeficientes de manera diferente en comparación con un modelo sin esta transformación.

La variable dependiente ahora está en el logaritmo del precio (log(precio_millon)), lo que afecta la forma en que interpretamos los coeficientes. Si se desea interpretar en la escala original de los datos, debe aplicarse euler al valor de los coeficientes estimados.

# Transformación logarítmica en la variable dependiente
modelo_log_dep <- lm(log(precio_millon) ~ Area_contruida + Zona + Banos, data = datos)
summary(modelo_log_dep)
## 
## Call:
## lm(formula = log(precio_millon) ~ Area_contruida + Zona + Banos, 
##     data = datos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.56596 -0.26728  0.00639  0.25084  1.89095 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)       4.691e+00  3.545e-02 132.329  < 2e-16 ***
## Area_contruida    1.765e-03  3.883e-05  45.462  < 2e-16 ***
## ZonaZona Norte    8.963e-02  3.554e-02   2.522   0.0117 *  
## ZonaZona Oeste    5.825e-01  3.625e-02  16.068  < 2e-16 ***
## ZonaZona Oriente -2.854e-01  4.005e-02  -7.126 1.12e-12 ***
## ZonaZona Sur      1.832e-01  3.493e-02   5.245 1.60e-07 ***
## Banos             2.068e-01  3.931e-03  52.616  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3833 on 8312 degrees of freedom
## Multiple R-squared:  0.6729, Adjusted R-squared:  0.6726 
## F-statistic:  2850 on 6 and 8312 DF,  p-value: < 2.2e-16

NOTA: Para interpretar correctamente los coeficientes en un modelo log-lin (logaritmo en la variable dependiente y variables no transformadas en los predictores), debemos aplicar la transformación exponencial inversa (también conocida como la “anti-transformación exponencial”) a los coeficientes. Esto nos dará la interpretación en términos de cambios porcentuales exactos:

Interpretación:

Àrea construida:Un incremento de una unidad (1 m² adicional) en el àrea construida de la vivienda aumenta el precio en aproximadamente 0,18%, anteniendo las demàs variables constantes.

Zona: Un cambio a la Zona Norte aumenta el precio en 9,37% comparado con la zona centro…etc

Baños:Un baño adicional incrementa el precio en 22,9%, manteniendo las demàs variables constantes.

# Calcular la interpretación en términos porcentuales aplicando la exponencial
exp_coef <- exp(coef(modelo_log_dep)) - 1  # Resta 1 para expresar como porcentaje

# Crear un dataframe para facilitar la interpretación
interpretacion_coef <- data.frame(
  Coeficiente = names(coef(modelo_log_dep)),
  Estimacion = coef(modelo_log_dep),
  Cambio_Porcentual = round(exp_coef * 100, 2)
)

# Mostrar la interpretación en términos de cambio porcentual
interpretacion_coef
##                       Coeficiente   Estimacion Cambio_Porcentual
## (Intercept)           (Intercept)  4.691435376          10800.95
## Area_contruida     Area_contruida  0.001765408              0.18
## ZonaZona Norte     ZonaZona Norte  0.089633991              9.38
## ZonaZona Oeste     ZonaZona Oeste  0.582518156             79.05
## ZonaZona Oriente ZonaZona Oriente -0.285379921            -24.83
## ZonaZona Sur         ZonaZona Sur  0.183207672             20.11
## Banos                       Banos  0.206842703             22.98
#Evaluación de supuestos en el modelo con logaritmo en la variable dependiente
par(mfrow = c(2, 2))  # Configurar para ver gráficos de diagnóstico
plot(modelo_log_dep )

par(mfrow = c(1, 1))  # Volver al gráfico normal

En un modelo log-log, los coeficientes se interpretan como elasticidades, es decir, el cambio porcentual en la variable dependiente cuando la variable independiente cambia en un 1%.

Interpretaciòn:

Área: Un aumento del 1% en Area_contruida se asocia con un aumento del 0.6% en el precio (precio_millon), manteniendo constantes las demás variables. En otras palabras, la elasticidad del precio respecto al área construida es 0.6.

Zona: Cambiar a una propiedad en la Zona Norte (comparado con la zona centro) se asocia con un aumento en el precio de aproximadamente 23.2%

Baño: Cada baño adicional se asocia con un aumento en el precio de aproximadamente 12.2%

# Transformación logarítmica en ambas dependiente e independientes
modelo_log_log <- lm(log(precio_millon) ~log (Area_contruida) + Zona + Banos, data = datos)
summary(modelo_log_log)
## 
## Call:
## lm(formula = log(precio_millon) ~ log(Area_contruida) + Zona + 
##     Banos, data = datos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.47376 -0.22078 -0.00002  0.21930  1.55993 
## 
## Coefficients:
##                      Estimate Std. Error t value Pr(>|t|)    
## (Intercept)          2.204715   0.046012  47.916  < 2e-16 ***
## log(Area_contruida)  0.602178   0.008219  73.268  < 2e-16 ***
## ZonaZona Norte       0.208852   0.031024   6.732 1.79e-11 ***
## ZonaZona Oeste       0.654455   0.031609  20.705  < 2e-16 ***
## ZonaZona Oriente    -0.244029   0.034884  -6.995 2.85e-12 ***
## ZonaZona Sur         0.316941   0.030522  10.384  < 2e-16 ***
## Banos                0.115405   0.003847  29.999  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3339 on 8312 degrees of freedom
## Multiple R-squared:  0.7518, Adjusted R-squared:  0.7516 
## F-statistic:  4197 on 6 and 8312 DF,  p-value: < 2.2e-16
#Evaluación de supuestos en el modelo con logaritmo en la variable dependiente y en una dependiente
par(mfrow = c(2, 2))  # Configurar para ver gráficos de diagnóstico
plot(modelo_log_log )

par(mfrow = c(1, 1))  # Volver al gráfico normal

##Validación Cruzada y Métricas de Rendimiento

Evaluamos el rendimiento del modelo con validación cruzada.

NOTA: set.seed(123): Fija la semilla para que los resultados sean reproducibles.

Luego, se dividen los datos en un 70% para entrenamiento (trainData) y un 30% para prueba (testData). Esta partición asegura que el modelo se entrena en una parte de los datos y luego se evalúa en un conjunto distinto, lo que simula su desempeño en datos nuevos.

# División en conjunto de entrenamiento y prueba
set.seed(123)
trainIndex <- createDataPartition(datos$precio_millon, p = .7, list = FALSE)
trainData <- datos[trainIndex, ]
testData <- datos[-trainIndex, ]

Aquí, el modelo múltiple inicial se entrena utilizando el conjunto de entrenamiento, incluyendo las variables seleccionadas como predictores del precio (precio_millon). Este paso ajusta el modelo en los datos de entrenamiento, obteniendo los coeficientes que minimizan el error cuadrático medio en estos datos.

A continuación se generan predicciones del precio en el conjunto de prueba (testData) usando el modelo entrenado. Como estas predicciones se realizan en datos que el modelo no ha visto antes, brindan una buena medida de su capacidad de generalización.

Interpretación:

El precio predicho se desvía, en promedio, alrededor de $133.77 millones.

#Validación cruzada modelo multiple inicial sin transformaciones

# Modelo con el conjunto de entrenamiento
modelo_multiple_VC <- lm(precio_millon ~ Area_contruida + Zona+ Banos , data = trainData)

# Predicciones en el conjunto de prueba
predicciones <- predict(modelo_multiple_VC, newdata = testData)

# Cálculo de MAE y RMSE
mae <- mean(abs(predicciones - testData$precio_millon))
rmse <- sqrt(mean((predicciones - testData$precio_millon)^2))

cat("MAE:", mae, "\nRMSE:", rmse)
## MAE: 133.7706 
## RMSE: 211.6556