#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
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.
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