Actividad 1 Modelos Estadísticos para la toma de decisiones
Evaluación de la oferta inmobiliaria urbana
Problema Una empresa inmobiliaria líder en una gran ciudad está buscando comprender en profundidad el mercado de viviendas urbanas para tomar decisiones estratégicas más informadas. La empresa posee una base de datos extensa que contiene información detallada sobre diversas propiedades residenciales disponibles en el mercado. Se requiere realizar un análisis holístico de estos datos para identificar patrones, relaciones y segmentaciones relevantes que permitan mejorar la toma de decisiones en cuanto a la compra, venta y valoración de propiedades.
El reto principal consisten en realizar un análisis integral y multidimensional de la base de datos para obtener una comprensión del mercado inmobiliario urbano. Se requiere aplicar diversas técnicas de análisis de datos, incluyendo:
Análisis de Componentes Principales: Reducir la dimensionalidad del conjunto de datos y visualizar la estructura de las variables en componentes principales para identificar características clave que influyen en la variación de precios y oferta del mercado.
Análisis de Conglomerados: Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas de las ofertas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.
Análisis de Correspondencia : Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.
Visualización de resultados: Presentar gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.
El informe final debe incluir análisis detallados de los resultados obtenidos, las conclusiones clave y las recomendaciones específicas para guiar las decisiones estratégicas de la empresa inmobiliaria. Se espera que este análisis de datos proporcione ventajas competitivas en el mercado, optimizando la inversión y maximizando los beneficios en un entorno altamente competitivo y en constante cambio.
Carga de datos
# Cargar librería y dataset
library(paqueteMODELOS)
## Cargando paquete requerido: boot
## Cargando paquete requerido: broom
## Cargando paquete requerido: GGally
## Warning: package 'GGally' was built under R version 4.4.3
## Cargando paquete requerido: ggplot2
## Warning: package 'ggplot2' was built under R version 4.4.3
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
## Cargando paquete requerido: gridExtra
## Warning: package 'gridExtra' was built under R version 4.4.3
## Cargando paquete requerido: knitr
## Cargando paquete requerido: summarytools
data("vivienda")
# Copia de trabajo con nuevo nombre
datos_inmuebles <- vivienda
# Estructura del dataset
str(datos_inmuebles)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<externalptr>
Exploración inicial
# Primeras filas
head(datos_inmuebles)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… <NA> 3 250 70 1 3 6
## 2 1169 Zona O… <NA> 3 320 120 1 2 3
## 3 1350 Zona O… <NA> 3 350 220 2 2 4
## 4 5992 Zona S… 02 4 400 280 3 5 3
## 5 1212 Zona N… 01 5 260 90 1 2 3
## 6 1724 Zona N… 01 5 240 87 1 3 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# Dimensiones (filas y columnas)
dim(datos_inmuebles)
## [1] 8322 13
# Resumen estadístico
summary(datos_inmuebles)
## id zona piso estrato
## Min. : 1 Length:8322 Length:8322 Min. :3.000
## 1st Qu.:2080 Class :character Class :character 1st Qu.:4.000
## Median :4160 Mode :character Mode :character Median :5.000
## Mean :4160 Mean :4.634
## 3rd Qu.:6240 3rd Qu.:5.000
## Max. :8319 Max. :6.000
## NA's :3 NA's :3
## preciom areaconst parqueaderos banios
## Min. : 58.0 Min. : 30.0 Min. : 1.000 Min. : 0.000
## 1st Qu.: 220.0 1st Qu.: 80.0 1st Qu.: 1.000 1st Qu.: 2.000
## Median : 330.0 Median : 123.0 Median : 2.000 Median : 3.000
## Mean : 433.9 Mean : 174.9 Mean : 1.835 Mean : 3.111
## 3rd Qu.: 540.0 3rd Qu.: 229.0 3rd Qu.: 2.000 3rd Qu.: 4.000
## Max. :1999.0 Max. :1745.0 Max. :10.000 Max. :10.000
## NA's :2 NA's :3 NA's :1605 NA's :3
## habitaciones tipo barrio longitud
## Min. : 0.000 Length:8322 Length:8322 Min. :-76.59
## 1st Qu.: 3.000 Class :character Class :character 1st Qu.:-76.54
## Median : 3.000 Mode :character Mode :character Median :-76.53
## Mean : 3.605 Mean :-76.53
## 3rd Qu.: 4.000 3rd Qu.:-76.52
## Max. :10.000 Max. :-76.46
## NA's :3 NA's :3
## latitud
## Min. :3.333
## 1st Qu.:3.381
## Median :3.416
## Mean :3.418
## 3rd Qu.:3.452
## Max. :3.498
## NA's :3
En este análisis se trabajó con una base de datos que reúne información de 8,322 propiedades. Cada registro corresponde a una vivienda y cuenta con 13 atributos asociados, que describen diferentes características relevantes para el estudio del mercado inmobiliario urbano.
Relación área construida vs precio
library(ggplot2)
ggplot(datos_inmuebles, aes(x = areaconst, y = preciom, color = areaconst)) +
geom_point() +
scale_color_viridis_c(option = "plasma") +
labs(title = "Área construida vs. precio",
x = "Área construida (m²)",
y = "Precio (millones)",
color = "Área") +
theme_classic()
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
Los datos evidencian que el tamaño de la construcción influye en el
valor de la vivienda: propiedades más grandes suelen tener precios más
altos. Sin embargo, la amplia dispersión de puntos muestra que esta no
es la única variable que incide en el precio, lo que sugiere la
presencia de otros factores como ubicación, estado del inmueble o
antigüedad.
Valores faltantes
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ lubridate 1.9.4 ✔ tibble 3.2.1
## ✔ purrr 1.0.2 ✔ tidyr 1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::combine() masks gridExtra::combine()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ tibble::view() masks summarytools::view()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
porcentaje_na <- map_dfr(names(datos_inmuebles), ~ {
tibble(variable = .x,
porcentaje_na = round(mean(is.na(datos_inmuebles[[.x]])) * 100, 2))
}) %>%
arrange(desc(porcentaje_na))
ggplot(porcentaje_na, aes(x = reorder(variable, porcentaje_na), y = porcentaje_na, fill = porcentaje_na)) +
geom_bar(stat = "identity") +
coord_flip() +
scale_fill_gradient(low = "#FEE08B", high = "#D73027") +
labs(title = "Porcentaje de datos faltantes",
x = "Variable",
y = "% de NA") +
theme_minimal()
El análisis univariado reveló que las variables “piso” y “parqueadero”
son las que presentan un mayor porcentaje de datos faltantes dentro del
conjunto. Una proporción tan alta de valores ausentes puede reducir la
calidad del análisis y generar sesgos en las conclusiones. Por esta
razón, se decidió excluir estos atributos para garantizar una
interpretación más sólida de los resultados.
Asimismo, se optó por eliminar las variables “barrio” e “id”. En el caso de id, su función es meramente identificadora y no aporta valor analítico; mientras que barrio, en este contexto, no ofrece información relevante para los métodos estadísticos aplicados y podría introducir ruido innecesario al modelo.
Limpieza de datos
# Eliminación de columnas irrelevantes y casos incompletos
inmuebles_limpios <- datos_inmuebles %>%
select(-id, -piso, -barrio, -parqueaderos) %>%
drop_na()
# Conversión de variables categóricas a factores numéricos
datos_inmuebles$zona <- factor(datos_inmuebles$zona,
levels = c("Zona Centro", "Zona Norte", "Zona Oeste", "Zona Oriente", "Zona Sur"),
labels = c(1, 2, 3, 4, 5))
datos_inmuebles$tipo <- factor(datos_inmuebles$tipo,
levels = c("Casa", "Apartamento"),
labels = c(1, 2))
# Verificación de estructura
str(inmuebles_limpios)
## tibble [8,319 × 9] (S3: tbl_df/tbl/data.frame)
## $ zona : chr [1:8319] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ estrato : num [1:8319] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8319] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8319] 70 120 220 280 90 87 52 137 150 380 ...
## $ banios : num [1:8319] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8319] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8319] "Casa" "Casa" "Casa" "Casa" ...
## $ longitud : num [1:8319] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8319] 3.43 3.43 3.44 3.44 3.46 ...
Tras depurar el conjunto de datos, se eliminaron las columnas ‘id’, ‘piso’, ‘barrio’ y ‘parqueadero’, así como las filas que contenían valores faltantes. Como resultado, la base final quedó conformada por 8,319 registros y 9 variables. Estas variables incluyen información tanto categórica, como numérica, lo que permite abordar el análisis desde una perspectiva mixta que combina descripciones cualitativas y mediciones cuantitativas.
Análisis de Componentes Principales (PCA)
library(FactoMineR) # Para que PCA sea el correcto
## Warning: package 'FactoMineR' was built under R version 4.4.3
library(factoextra) # Visualización
## Warning: package 'factoextra' was built under R version 4.4.3
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(ggplot2) # Gráficos
is_ggplot <- function(x) inherits(x, "ggplot")
library(factoextra)
library(ggplot2)
# Escalado de variables numéricas relevantes
inmuebles_escalados <- scale(inmuebles_limpios[, 2:5])
# PCA
pca_result <- PCA(inmuebles_escalados, graph = FALSE)
# Varianza explicada
fviz_eig(pca_result, addlabels = TRUE, barfill = "#4DAF4A", barcolor = "#377EB8") +
theme_minimal()
El análisis de componentes principales muestra que el primer componente concentra gran parte de la información de los datos. Al sumar el segundo componente, se logra explicar la mayor parte de la variabilidad total. Esto significa que la base de datos puede resumirse de forma adecuada usando solo uno o dos componentes, facilitando su interpretación y análisis.
# Variables en el espacio de componentes
fviz_pca_var(pca_result,
col.var = "contrib",
gradient.cols = c("#F7FCB9", "#31A354"),
repel = TRUE)
La proyección de las variables en el plano de los componentes
principales permite identificar qué mide cada componente y cómo se
relaciona con las variables originales. En este caso, el primer
componente está más vinculado con variables como estrato y precio,
mientras que el segundo se asocia principalmente con el área construida.
Esto ayuda a interpretar el significado de cada eje en el análisis.
Análisis de Conglomerados (K-means)
# Variables para clustering
vars_cluster <- inmuebles_limpios %>%
select(estrato, preciom, areaconst, banios, habitaciones)
vars_cluster_scaled <- scale(vars_cluster)
# Método del codo
wcss <- sapply(1:10, function(k) {
kmeans(vars_cluster_scaled, centers = k, nstart = 10)$tot.withinss
})
plot(1:10, wcss, type = "b", pch = 19,
xlab = "Número de clusters", ylab = "WCSS",
main = "Método del codo")
# Ajuste final con k = 3
set.seed(321)
modelo_k3 <- kmeans(vars_cluster_scaled, centers = 3, nstart = 10)
inmuebles_con_cluster <- inmuebles_limpios %>%
mutate(cluster = factor(modelo_k3$cluster))
# Visualización
ggplot(inmuebles_con_cluster, aes(x = estrato, y = preciom, color = cluster)) +
geom_point(alpha = 0.6) +
scale_color_brewer(palette = "Dark2") +
labs(title = "Clusters según estrato y precio",
x = "Estrato",
y = "Precio (millones)",
color = "Cluster") +
theme_minimal()
El gráfico de clusters de propiedades muestra una relación positiva
entre el estrato socioeconómico y el precio de las viviendas. A medida
que aumenta el estrato, también lo hace el precio promedio y la cantidad
de agrupaciones identificadas, con mayor concentración en los estratos
altos (5 y 6) que en los bajos (1 y 2).
En cuanto a la distribución, el cluster 1 aparece con mayor frecuencia en estratos medios (3, 4 y 5) y con menor presencia en el estrato 6. El cluster 2 predomina en los estratos más altos (5 y 6), mientras que el cluster 3 se encuentra principalmente en estratos medios (3 y 4) y, en menor medida, en el estrato 6. Esto sugiere que cada cluster refleja perfiles de propiedades asociados a rangos de estrato y precio específicos.
Análisis de Correspondencia
library(FactoMineR)
set.seed(456)
muestra_inmuebles <- sample_n(datos_inmuebles, 2000)
muestra_inmuebles$estrato <- as.factor(muestra_inmuebles$estrato)
tabla_contingencia <- table(muestra_inmuebles$zona, muestra_inmuebles$estrato)
resultado_ca <- CA(tabla_contingencia)
# Scree plot
fviz_screeplot(resultado_ca, addlabels = TRUE, ylim = c(0, 80), col = "#08519C") +
ylab("Porcentaje de varianza explicada") +
xlab("Dimensiones")
El gráfico permite identificar patrones espaciales entre el estrato
socioeconómico y la zona geográfica. El estrato 6 se concentra
principalmente en la Zona Oeste, mientras que los estratos 4 y 5
predominan en las Zonas Sur y Norte. El estrato 3, por su parte, se
localiza sobre todo en las Zonas Oriente y Centro.
En términos de análisis factorial, la Dimensión 1 explica la mayor parte de la variabilidad del conjunto de datos, mientras que la Dimensión 2 aporta una fracción adicional relevante. La suma de ambas dimensiones representa un alto porcentaje de la variabilidad acumulada, lo que indica que el plano formado por ellas resume de forma efectiva la estructura original de la información.
Las dos primeras dimensiones explican la gran mayoría de la variabilidad del conjunto de datos, lo que indica que son suficientes para representar casi toda la información original sin necesidad de considerar más dimensiones.
Conclusiones
El análisis de componentes principales permitió identificar qué variables concentran la mayor parte de la información relevante para explicar el comportamiento del precio de la vivienda. El primer componente sintetiza gran parte de la variabilidad y está principalmente vinculado con el estrato socioeconómico, el precio y el área construida, mientras que la inclusión del segundo componente refuerza notablemente la capacidad explicativa, permitiendo representar los datos de forma simplificada sin perder información clave.
El análisis de clusters mediante k-means segmentó las propiedades en grupos con características diferenciadas. Se observó una relación positiva entre el estrato, el precio y la distribución de los grupos: los estratos altos concentran propiedades de mayor valor y presentan patrones de agrupación distintos a los estratos bajos. Además, cada cluster mostró tendencias específicas según el tipo de vivienda (apartamentos o casas) y el rango de estrato predominante.
En el análisis de correlación, se identificaron relaciones claras entre variables: el número de habitaciones y baños está fuertemente asociado, así como el estrato y el precio. También se observan correlaciones moderadas entre el área construida y el número de habitaciones, y entre el precio y la cantidad de baños.
El análisis de correspondencias múltiples confirmó asociaciones significativas entre variables categóricas y numéricas, en especial entre la zona geográfica y el estrato. Se evidenció que el estrato 6 se concentra en la Zona Oeste, mientras que los estratos 4 y 5 predominan en las Zonas Sur y Norte. Las dos primeras dimensiones explicaron la gran mayoría de la información, validando la efectividad de este método para simplificar y representar el conjunto de datos.