La base de datos corresponde a un corte de oferta inmobiliaria residencial urbana compuesto por 8.322 registros (filas) y 13 variables (columnas). Cada fila representa una propiedad (inmueble en oferta) identificada por un id numérico y caracterizada por atributos territoriales, socioeconómicos, físicos y geográficos, lo que permite analizar el mercado desde varias perspectivas: valorización, tipología de vivienda, segmentación y patrones espaciales.
En cuanto a la localización, el inmueble se clasifica por zona (p. ej., Norte, Sur, Oriente, Oeste, Centro) y por barrio, además de incorporar coordenadas latitud y longitud, que habilitan análisis geoespaciales y visualización en mapas. La dimensión socioeconómica está representada por la variable estrato (valores observados entre 3 y 6 en el extracto mostrado), útil para interpretar diferencias de mercado según niveles de ingreso y condiciones urbanas. La dimensión física y funcional incluye el tipo de vivienda (Casa/Apartamento), el piso (registrado como texto y con presencia de valores faltantes), el área construida (areaconst) y la dotación del inmueble medida por habitaciones, baños y parqueaderos (esta última también con faltantes en algunos casos).
Finalmente, la variable preciom recoge el precio por metro cuadrado (en la unidad monetaria definida en la fuente), que junto con el área y la dotación permite estudiar el comportamiento del precio, su relación con las características del inmueble y su variación territorial.
library(paqueteMODELOS)
# Carga el dataset del paquete al entorno
data("vivienda") # si falla, prueba data("vivenda")
# Validación: confirmar que existe y es tabla
stopifnot(exists("vivienda"))
stopifnot(is.data.frame(vivienda))
# Renombrar a un nombre seguro para el resto del pipeline
df_raw <- vivienda
rm(vivienda) # opcional, para evitar confusión
glimpse(df_raw)
En esta sección se realiza la preparación inicial de la base de datos para garantizar consistencia y calidad antes de aplicar los análisis multivariados (PCA, clustering y correspondencias). Primero, se parte del conjunto original (df_raw) y se eliminan registros duplicados para evitar sesgos por doble conteo. Luego se estandarizan los tipos de datos: variables identificadoras y cuantitativas (como id, estrato, preciom, areaconst, parqueaderos, banios, habitaciones, latitud y longitud) se convierten a formato numérico; mientras que las variables categóricas asociadas al contexto territorial y tipología de la vivienda (zona, tipo, barrio) se convierten en factores para facilitar análisis descriptivos y de correspondencia. Adicionalmente, la variable piso, que originalmente puede venir como texto (por ejemplo “02”), se transforma a número para permitir su uso en modelos y estadísticos.
Como parte del control de calidad, se generan dos banderas: flag_geo, que identifica registros sin coordenadas geográficas (latitud/longitud faltantes), y flag_vals, que detecta observaciones con valores críticos o no plausibles (por ejemplo, precio o área construida faltante o menor/igual a cero).
Finalmente, se calcula un resumen estadístico formal de la variable estrato, organizándolo en una tabla con rótulos (mínimo, cuartiles, mediana, media, máximo y número de valores faltantes). Esta tabla se incorpora al informe como “Tabla 1”, proporcionando una lectura clara de la distribución del estrato socioeconómico y permitiendo documentar la calidad y cobertura de esta variable clave en el análisis del mercado inmobiliario.
df <- df_raw %>%
dplyr::distinct() %>%
dplyr::mutate(
id = as.numeric(id),
zona = as.factor(zona),
tipo = as.factor(tipo),
barrio = as.factor(barrio),
piso = readr::parse_number(as.character(piso)),
estrato = as.numeric(estrato),
estrato_cat = factor(
estrato,
levels = sort(unique(estrato[!is.na(estrato)])),
ordered = TRUE
),
preciom = as.numeric(preciom),
areaconst = as.numeric(areaconst),
parqueaderos = as.numeric(parqueaderos),
banios = as.numeric(banios),
habitaciones = as.numeric(habitaciones),
longitud = as.numeric(longitud),
latitud = as.numeric(latitud)
) %>%
dplyr::mutate(
flag_geo = is.na(latitud) | is.na(longitud),
flag_vals = is.na(preciom) | is.na(areaconst) | preciom <= 0 | areaconst <= 0
)
s <- summary(df$estrato)
tabla_estrato <- tibble::tibble(
Indicador = c("Mínimo", "1er cuartil (Q1)", "Mediana", "Media", "3er cuartil (Q3)", "Máximo", "Registros sin dato (NA)"),
Valor = c(
as.numeric(s["Min."]),
as.numeric(s["1st Qu."]),
as.numeric(s["Median"]),
round(as.numeric(s["Mean"]), 3),
as.numeric(s["3rd Qu."]),
as.numeric(s["Max."]),
as.integer(s["NA's"])
)
)
knitr::kable(
tabla_estrato,
align = c("l","r"),
caption = "Tabla 1. Estadísticos descriptivos de la variable 'Estrato'."
)
| Indicador | Valor |
|---|---|
| Mínimo | 3.000 |
| 1er cuartil (Q1) | 4.000 |
| Mediana | 5.000 |
| Media | 4.634 |
| 3er cuartil (Q3) | 5.000 |
| Máximo | 6.000 |
| Registros sin dato (NA) | 2.000 |
La variable estrato presenta un rango de 3 a 6 y una alta concentración en los estratos 4 y 5 (Q1=4; Mediana=5; Q3=5), con un valor promedio de 4,634. Se identifican 2 registros sin información de estrato, los cuales se manejan como faltantes en los análisis multivariados y se excluyen o agrupan en “No informa” para análisis descriptivos.
En este bloque se realiza ingeniería de variables para enriquecer la base con indicadores que facilitan el análisis económico y comparativo del mercado inmobiliario. En particular, se calcula un precio total aproximado (precio_total_aprox) combinando el precio reportado (preciom) con el área construida (areaconst), y se construyen métricas de “intensidad” o estandarización por tamaño, como la densidad de habitaciones por m² (dens_habitaciones), la relación baños/habitación (ratio_banios_hab, protegiendo contra división por cero), y los parqueaderos por cada 100 m² (parqueo_100m2). Adicionalmente, se crean transformaciones logarítmicas (log_preciom y log_precio_total) para reducir asimetrías y estabilizar la variabilidad, lo que mejora el desempeño e interpretación de técnicas como PCA y clustering.
Finalmente, se usa skimr::skim() sobre variables clave para generar un resumen descriptivo (distribución, faltantes y estadísticos) que valida la consistencia de estas nuevas variables antes de continuar con el análisis (Ver tabla 2.
df <- df %>%
mutate(
precio_total_aprox = preciom * areaconst,
dens_habitaciones = habitaciones / areaconst,
ratio_banios_hab = banios / pmax(habitaciones, 1),
parqueo_100m2 = (parqueaderos / areaconst) * 100,
log_preciom = log1p(preciom),
log_precio_total = log1p(precio_total_aprox)
)
tabla2 <- df %>%
select(preciom, areaconst, precio_total_aprox, log_preciom) %>%
skimr::skim() %>%
as.data.frame()
knitr::kable(
tabla2,
caption = "Tabla 2. Resumen descriptivo (skimr) de variables clave: precio, área y transformaciones."
)
| skim_type | skim_variable | n_missing | complete_rate | numeric.mean | numeric.sd | numeric.p0 | numeric.p25 | numeric.p50 | numeric.p75 | numeric.p100 | numeric.hist |
|---|---|---|---|---|---|---|---|---|---|---|---|
| numeric | preciom | 1 | 0.9998798 | 4.338919e+02 | 3.286472e+02 | 58.000000 | 220.000000 | 330.000000 | 5.400000e+02 | 1.999000e+03 | ▇▂▁▁▁ |
| numeric | areaconst | 2 | 0.9997596 | 1.749349e+02 | 1.429641e+02 | 30.000000 | 80.000000 | 123.000000 | 2.290000e+02 | 1.745000e+03 | ▇▁▁▁▁ |
| numeric | precio_total_aprox | 2 | 0.9997596 | 1.081980e+05 | 1.814814e+05 | 2900.000000 | 18000.000000 | 42400.000000 | 1.150000e+05 | 2.854800e+06 | ▇▁▁▁▁ |
| numeric | log_preciom | 1 | 0.9998798 | 5.844004e+00 | 6.677956e-01 | 4.077537 | 5.398163 | 5.802118 | 6.293419e+00 | 7.600903e+00 | ▁▆▇▅▂ |
Este resumen de skimr muestra la distribución y calidad de cuatro variables clave (precio, área y transformaciones) para 8.321 observaciones. En términos de informe, lo más importante es:
Calidad de datos (faltantes): preciom tiene 1 valor faltante y areaconst / precio_total_aprox tienen 2 faltantes. La tasa de completitud es prácticamente total (≈100%), por lo que estas variables son sólidas para análisis posteriores.
preciom (precio): Promedio 433,89 y mediana 330, con un rango amplio (58–1999) y desviación estándar alta (328,65). Esto indica alta heterogeneidad de precios y una distribución sesgada hacia valores altos (se ve en el histograma).
areaconst (área construida): Promedio 174,93 m², mediana 123 m², con rango 30–1745 m². La diferencia entre media y mediana sugiere presencia de propiedades muy grandes que elevan el promedio (cola derecha).
precio_total_aprox (proxy de precio total): Mediana 42.400 vs promedio 108.198, con un máximo de 2.854.800. La brecha media–mediana confirma un sesgo fuerte y outliers importantes, esperables en mercados donde coexisten segmentos de lujo con oferta estándar.
log_preciom (transformación logarítmica): Presenta una distribución mucho más “estable” (media 5,84, sd 0,67) y un histograma más concentrado, lo que sugiere que el logaritmo reduce el efecto de extremos y deja la variable más adecuada para técnicas como PCA y clustering.
El mercado en la base es altamente heterogéneo en precio y tamaño, con colas derechas (segmentos premium) que influyen fuertemente en promedios. Por eso, usar medianas/cuartiles y transformaciones como log_preciom mejora la comparabilidad y la robustez del análisis.
En esta sección se realiza un diagnóstico de calidad de datos antes de avanzar a los análisis multivariados. Primero, se calcula un resumen de valores faltantes por variable (cantidad y porcentaje) y se ordena para identificar rápidamente cuáles columnas presentan mayor incompletitud.
Posteriormente, se ejecuta una detección preliminar de valores atípicos (outliers) para un conjunto de variables numéricas clave mediante el criterio IQR (1.5 veces el rango intercuartílico), reportando cuántas observaciones caen fuera de los límites esperados. Este paso permite anticipar posibles sesgos o distorsiones y decidir si se requieren tratamientos adicionales (p. ej., revisión, recorte o transformaciones) antes de aplicar PCA, clustering y modelos de valoración.
Datos faltantes: Ver Tabla 3. Resumen de datos faltantes:
tabla3_faltantes <- naniar::miss_var_summary(df) %>%
dplyr::arrange(dplyr::desc(pct_miss))
knitr::kable(
tabla3_faltantes,
digits = 2,
caption = "Tabla 3. Resumen de valores faltantes por variable (n y porcentaje)."
)
| variable | n_miss | pct_miss |
|---|---|---|
| piso | 2637 | 31.7 |
| parqueaderos | 1604 | 19.3 |
| parqueo_100m2 | 1604 | 19.3 |
| id | 2 | 0.0240 |
| zona | 2 | 0.0240 |
| estrato | 2 | 0.0240 |
| areaconst | 2 | 0.0240 |
| banios | 2 | 0.0240 |
| habitaciones | 2 | 0.0240 |
| tipo | 2 | 0.0240 |
| barrio | 2 | 0.0240 |
| longitud | 2 | 0.0240 |
| latitud | 2 | 0.0240 |
| estrato_cat | 2 | 0.0240 |
| precio_total_aprox | 2 | 0.0240 |
| dens_habitaciones | 2 | 0.0240 |
| ratio_banios_hab | 2 | 0.0240 |
| log_precio_total | 2 | 0.0240 |
| preciom | 1 | 0.0120 |
| log_preciom | 1 | 0.0120 |
| flag_geo | 0 | 0 |
| flag_vals | 0 | 0 |
Este resultado muestra el perfil de faltantes de la base (22 variables evaluadas) y permite identificar rápidamente dónde está el principal reto de completitud:
Faltantes críticos y concentrados
piso: 2.637 valores faltantes (31,7%). Es la variable con mayor pérdida de información; su uso en PCA/clustering debe tratarse con cuidado (imputación, categoría “desconocido”, o excluirla de ciertos análisis).
parqueaderos: 1.604 faltantes (19,3%).
parqueo_100m2: también 1.604 faltantes (19,3%) porque depende directamente de parqueaderos (si no hay parqueaderos, no se puede calcular el indicador).
Faltantes marginales
La mayoría de variables restantes tienen solo 2 faltantes (0,024%): id, zona, estrato, areaconst, banios, habitaciones, tipo, barrio, latitud, longitud y las variables derivadas que dependen de ellas (estrato_cat, precio_total_aprox, etc.).
preciom tiene 1 faltante (0,012%) y por arrastre log_preciom también.
Banderas de calidad completas
flag_geo y flag_vals aparecen con 0 faltantes, lo cual es esperado (son variables binarias creadas en el pipeline).
La base es muy completa en casi todas las variables, pero hay dos focos claros de incompletitud: piso (≈1/3 de la base) y parqueaderos (≈1/5). Esto sugiere que, para los análisis multivariados, conviene definir una estrategia explícita para estas variables (imputación, exclusión o recodificación), mientras que el resto de campos no representa un problema significativo de calidad.
Datos Atípicos: El siguiente cuadro (Tabla 4), resume cuántos registros caen fuera de los límites esperados según la regla IQR (1.5× rango intercuartílico) para cada variable. En otras palabras, son observaciones atípicas frente al comportamiento “central” de la muestra (no necesariamente errores, pero sí casos extremos que pueden influir en promedios, PCA y clustering).
# Detección simple de outliers (IQR) para variables numéricas clave
num_vars <- c("preciom", "areaconst", "precio_total_aprox",
"banios", "habitaciones", "parqueaderos", "piso")
outlier_counts <- purrr::map_dfr(num_vars, function(v){
x <- df[[v]]
x <- x[is.finite(x)]
if (length(x) < 10) return(tibble(var = v, outliers = NA_integer_))
q1 <- quantile(x, 0.25, na.rm = TRUE)
q3 <- quantile(x, 0.75, na.rm = TRUE)
iqr <- q3 - q1
lower <- q1 - 1.5 * iqr
upper <- q3 + 1.5 * iqr
tibble(
var = v,
outliers = sum(df[[v]] < lower | df[[v]] > upper, na.rm = TRUE)
)
})
knitr::kable(
outlier_counts,
caption = "Tabla 4. Conteo de valores atípicos por variable (criterio IQR 1.5×).",
col.names = c("Variable", "N° de outliers")
)
| Variable | N° de outliers |
|---|---|
| preciom | 552 |
| areaconst | 382 |
| precio_total_aprox | 911 |
| banios | 72 |
| habitaciones | 888 |
| parqueaderos | 567 |
| piso | 297 |
Estos resultados muestran que:
precio_total_aprox (911 outliers) y habitaciones (888 outliers): son las variables con más valores extremos. Esto suele ocurrir cuando hay segmentos muy distintos (ej. inmuebles grandes o multipropósito) o registros inconsistentes (habitaciones demasiado altas para el área).
parqueaderos (567) y preciom (552): también muestran muchos extremos; típico en mercados con oferta de lujo y/o propiedades con parqueaderos inusualmente altos.
areaconst (382) y piso (297): presencia moderada de extremos (propiedades muy grandes o pisos muy altos/bajos respecto al resto).
banios (72): es la variable más estable, con pocos casos extremos.
Histogramas de precio: lectura e implicaciones para el análisis
Histograma de preciom (escala original) (Gráfico 1) El histograma muestra una distribución fuertemente asimétrica hacia la derecha, donde la mayor parte de las propiedades se concentra en rangos de precio bajos y medios, mientras que un grupo reducido alcanza valores muy altos. Esta cola derecha pronunciada evidencia una alta heterogeneidad del mercado, asociada a la coexistencia de segmentos diferenciados (por ejemplo, vivienda estándar vs. alta gama). La presencia de valores extremos (outliers) implica que métricas como la media pueden verse influidas por pocos casos, por lo que para describir el mercado resulta más apropiado apoyarse en medianas y cuartiles, además de realizar comparaciones desagregadas por zona, estrato y tipo de vivienda.
Histograma de log(preciom + 1) (transformación logarítmica)(Gráfico 2) Tras aplicar la transformación logarítmica, la distribución se vuelve más compacta y balanceada, reduciendo el efecto de los valores extremos y facilitando la comparación entre propiedades. En esta escala, los precios altos dejan de dominar la forma del histograma, lo que sugiere una estructura más “regular” del mercado y una menor influencia de la cola derecha. Esto respalda el uso de log(preciom + 1) como variable de trabajo en análisis multivariados, ya que mejora la estabilidad estadística y la robustez de técnicas como el PCA y el clustering, al disminuir la distorsión causada por observaciones de precios excepcionalmente elevados.
p1 <- ggplot(df, aes(preciom)) +
geom_histogram(bins = 50) +
scale_x_continuous(labels = scales::comma) +
labs(title = "Gráfico 1. Distribución de preciom", x = "preciom", y = "Frecuencia")
p2 <- ggplot(df, aes(log_preciom)) +
geom_histogram(bins = 50) +
labs(title = "Gráfico 2. Distribución de log(preciom + 1)", x = "log(preciom + 1)", y = "Frecuencia")
p1 / p2
La matriz de correlaciones evidencia una estructura clara del mercado donde el precio (preciom) se asocia fuertemente con variables que reflejan tamaño y estándar del inmueble, especialmente área construida (areaconst), parqueaderos y baños, mientras que la relación con habitaciones es moderada, sugiriendo que el mercado valora más el metraje y las amenidades que el simple conteo de cuartos.
Como era esperable, el precio total aproximado (precio_total_aprox) presenta correlaciones altas con preciom y areaconst, lo cual confirma su carácter derivado y advierte sobre redundancia si se incluye junto con sus componentes en análisis multivariados.
Adicionalmente, las variables de densidad (por ejemplo, dens_habitaciones) muestran correlaciones negativas con el precio y el tamaño, indicando que los inmuebles más costosos y grandes tienden a tener menor densidad de habitaciones por m² (espacios más amplios). La transformación logarítmica (log_preciom) mantiene una asociación alta con el precio original y mejora la estabilidad de la distribución, por lo que resulta más adecuada para técnicas como PCA y clustering.
Finalmente, piso muestra correlaciones bajas con el precio y, dado su alto porcentaje de faltantes, su aporte analítico es limitado y debe manejarse con cautela (imputación o exclusión según el objetivo)(Ver matriz de correlaciones numéricas)(Ver Gráfico 3).
num_for_corr <- df %>%
select(preciom, areaconst, parqueaderos, banios, habitaciones, piso, precio_total_aprox,
dens_habitaciones, ratio_banios_hab, parqueo_100m2, log_preciom, log_precio_total)
GGally::ggcorr(num_for_corr, label = TRUE, label_round = 2, size = 3) +
ggtitle("Gráfico 3. Matriz de correlaciones (numéricas)")
En esta sección se aplicó un Análisis de Componentes Principales (PCA) con el fin de reducir la dimensionalidad del conjunto de datos y visualizar la estructura subyacente del mercado inmobiliario a partir de variables numéricas clave. Para ello, se seleccionaron atributos que representan tanto el nivel de precio como características físicas de la oferta: log_preciom (precio en escala logarítmica para disminuir el efecto de valores extremos), areaconst (área construida), parqueaderos, banios y habitaciones.
Dado que algunas variables presentan valores faltantes, se realizó una imputación basada en PCA (usando validación cruzada para estimar el número óptimo de componentes de imputación), garantizando una matriz completa y coherente con las relaciones multivariadas observadas.
Posteriormente, se ejecutó el PCA con estandarización de variables para hacerlas comparables pese a sus diferentes escalas, y se obtuvo la descomposición en componentes que concentran la mayor parte de la variación. Finalmente, los resultados se interpretan mediante visualizaciones (scree plot, mapa de variables y proyección de individuos), permitiendo identificar qué atributos explican en mayor medida las diferencias de precio y configuración de la oferta en el mercado.
# 1) Variables numéricas para capturar precio + atributos de oferta (sin redundancias)
# - Usamos log_preciom por robustez
# - Excluimos precio_total_aprox / log_precio_total por redundancia con precio y área
pca_vars <- c("log_preciom", "areaconst", "parqueaderos", "banios", "habitaciones")
X <- df %>% dplyr::select(dplyr::all_of(pca_vars))
# 2) Imputación basada en PCA para manejar NA (ej. parqueaderos)
set.seed(123)
ncp_est <- missMDA::estim_ncpPCA(X, ncp.max = 10, method.cv = "Kfold", nbsim = 5)
imp <- missMDA::imputePCA(X, ncp = ncp_est$ncp)
X_imp <- imp$completeObs
# 3) PCA con estandarización (para comparar variables en distintas escalas)
res_pca <- FactoMineR::PCA(X_imp, scale.unit = TRUE, graph = FALSE)
# 4) Tabla de varianza explicada (evidencia de reducción dimensional)
eig <- as.data.frame(res_pca$eig)
eig$`Varianza acumulada (%)` <- cumsum(eig$`percentage of variance`)
eig
El gráfico de varianza explicada (scree plot) muestra que el primer componente principal (PC1) concentra la mayor parte de la variación del conjunto de datos, explicando 66,4% de la información. El segundo componente (PC2) aporta un 16,4% adicional. En conjunto, los dos primeros componentes explican el 82,8% de la variación total, lo que indica que el mercado puede representarse de forma adecuada y sintética en un plano bidimensional (PC1–PC2) para fines de visualización e interpretación.
A partir del tercer componente, los aportes individuales son considerablemente menores (PC3: 7,2%; PC4: 6,3%; PC5: 3,7%), evidenciando un “codo” después del segundo componente y una curva que se aplana. Esto sugiere que los componentes posteriores capturan variaciones más específicas o residuales, mientras que la estructura principal del mercado está dominada por las dos primeras dimensiones, lo que respalda su uso como base para análisis posteriores como segmentación (clustering) y comparación de perfiles de oferta (Ver gráfico 4).
El gráfico de estructura de variables y contribución (círculo de
correlaciones del PCA) permite interpretar qué características del
inmueble explican las dos dimensiones principales del análisis. En
primer lugar, se observa que todas las variables (log_preciom,
areaconst, banios, parqueaderos y habitaciones) se orientan hacia
valores positivos en Dim1 (66,4%), lo que indica que esta dimensión
resume un gradiente general de escala y valorización: a mayor área y
dotación (más baños y parqueaderos), mayor tiende a ser el nivel de
precio (en escala logarítmica). Por tanto, Dim1 representa la estructura
dominante del mercado, diferenciando inmuebles de menor tamaño y menor
estándar frente a inmuebles más grandes, mejor dotados y de mayor
valor.
En segundo lugar, Dim2 (16,4%) introduce una diferenciación adicional relacionada con la configuración interna del inmueble: habitaciones se proyecta principalmente hacia valores positivos de esta dimensión, mientras que log_preciom y parqueaderos tienden a ubicarse hacia valores negativos, sugiriendo un contraste entre propiedades con mayor número de habitaciones y aquellas cuyo perfil está más asociado a dotación (parqueaderos) y nivel de precio.
En conjunto, este gráfico confirma que la variación del mercado se
explica principalmente por una dimensión de tamaño/amenidades y precio,
complementada por una segunda dimensión que captura diferencias en la
composición o distribución de la vivienda (Ver Gráfico 5).
Se identificaron cuatro propiedades representativas ubicadas en los extremos del plano PCA: dos extremos en PC1 (menor y mayor escala/valorización del inmueble) y dos extremos en PC2 (configuraciones contrastantes asociadas principalmente al número de habitaciones frente a un perfil más orientado a precio/amenidades). Estos casos sirven como puntos de referencia para interpretar el gradiente principal del mercado y su variación secundaria (ver Tabla 5).
library(dplyr)
library(ggplot2)
library(factoextra)
# Coordenadas de individuos (filas = propiedades)
scores <- as.data.frame(res_pca$ind$coord) %>%
mutate(row_id = row_number()) # identificador por fila
# ---- Selección automática de casos extremos (recomendado) ----
# 2 casos extremos en Dim1 (mín y máx)
casos_dim1 <- scores %>%
slice_min(Dim.1, n = 1) %>%
bind_rows(scores %>% slice_max(Dim.1, n = 1)) %>%
mutate(grupo = "Extremos Dim1")
# 2 casos extremos en Dim2 (mín y máx)
casos_dim2 <- scores %>%
slice_min(Dim.2, n = 1) %>%
bind_rows(scores %>% slice_max(Dim.2, n = 1)) %>%
mutate(grupo = "Extremos Dim2")
casos <- bind_rows(casos_dim1, casos_dim2)
tabla_casos <- casos %>%
dplyr::select(row_id, Dim.1, Dim.2, grupo)
knitr::kable(
tabla_casos,
caption = "Tabla 5. Casos extremos identificados en el plano PCA (Dim1 vs Dim2).",
col.names = c("ID (fila)", "Dimensión 1 (PC1)", "Dimensión 2 (PC2)", "Grupo")
)
| ID (fila) | Dimensión 1 (PC1) | Dimensión 2 (PC2) | Grupo | |
|---|---|---|---|---|
| 8035 | 8035 | -3.370053 | 0.4724439 | Extremos Dim1 |
| 1762 | 1762 | 9.814548 | -3.0088362 | Extremos Dim1 |
| 2926 | 2926 | 2.512951 | -6.1174113 | Extremos Dim2 |
| 6135 | 6135 | 2.135257 | 4.3123761 | Extremos Dim2 |
El gráfico de individuos del PCA (PC1 vs PC2) presenta la distribución de las propiedades en un plano bidimensional que resume la mayor parte de la variación del conjunto de datos. La Dimensión 1 (PC1), ubicada en el eje horizontal, constituye el principal eje de diferenciación del mercado y separa la oferta desde inmuebles con menor escala y valorización hacia inmuebles con mayor escala, dotación y nivel de precio, coherente con su relación con variables como log_preciom, areaconst, banios y parqueaderos.
La Dimensión 2 (PC2), en el eje vertical, introduce una diferenciación secundaria asociada a la configuración del inmueble, destacando contrastes relacionados con la distribución interna (por ejemplo, mayor presencia relativa de habitaciones frente a perfiles más asociados a amenidades y precio).
La nube central de puntos sugiere un segmento amplio de oferta con características cercanas al promedio, mientras que la dispersión hacia los extremos evidencia la existencia de propiedades con perfiles claramente diferenciados dentro del mercado.
Los casos extremos resaltados permiten ilustrar estas diferencias: los puntos en los extremos de PC1 representan propiedades ubicadas en los límites del gradiente de valorización/escala, y los puntos extremos en PC2 muestran configuraciones particulares que se apartan del patrón central. En conjunto, la proyección confirma que el mercado puede interpretarse de manera sintética a través de dos dimensiones principales, facilitando la exploración de segmentaciones y perfiles de oferta en análisis posteriores.
# ---- Gráfico Individuals PCA ----
# Nota: evito repel/labels masivos para que no se "pegue" con 8k puntos.
p <- fviz_pca_ind(
res_pca,
geom.ind = "point",
col.ind = "grey80",
alpha.ind = 0.25,
pointsize = 0.8
) +
geom_point(
data = casos_dim1,
aes(x = Dim.1, y = Dim.2),
color = "red", size = 3
) +
geom_point(
data = casos_dim2,
aes(x = Dim.1, y = Dim.2),
color = "blue", size = 3
) +
ggtitle("Gráfico 6. PCA: Individuos (PC1 vs PC2) con casos extremos destacados") +
labs(x = "Dimensión 1 (PC1)", y = "Dimensión 2 (PC2)")
p
library(dplyr)
library(factoextra)
library(cluster)
# Scores PCA de individuos (coordenadas por componente)
pc_scores <- as.data.frame(res_pca$ind$coord) %>%
mutate(row_id = row_number())
# Elegir cuántas dimensiones usar en clustering
k_dims <- 3 # puedes dejarlo en 2 o 3; con 3 suele mejorar segmentación
X_clust <- pc_scores %>% dplyr::select(dplyr::all_of(paste0("Dim.", 1:k_dims)))
# (Opcional) estandarizar scores (no es obligatorio; ya vienen comparables)
X_mat <- as.matrix(X_clust)
Para determinar el número de conglomerados se evaluaron dos criterios complementarios: el método del codo (Elbow/WSS) y el índice de Silhouette. En el gráfico Elbow se observa una reducción muy marcada de la variabilidad intra-cluster al pasar de𝑘=1 a valores mayores, y especialmente una mejora sustancial hasta alrededor de𝑘=4; a partir de ese punto la curva se aplana, lo que indica rendimientos decrecientes al incrementar el número de grupos (ver gráfico 7).
Por su parte, aunque el criterio Silhouette alcanza su máximo en un
número menor de clusters, para𝑘=4 se mantiene un nivel de separación
todavía razonable y, sobre todo, ofrece una granularidad interpretativa
superior para el objetivo del estudio: caracterizar segmentos del
mercado con diferencias relevantes en precio, tamaño y dotación, y
posteriormente analizar su composición por zona y estrato socioeconómico
(Ver Gráfico 8).
En consecuencia, se seleccionó 𝑘=4 como un equilibrio entre calidad de
agrupación (cohesión interna y reducción del WSS) y utilidad analítica,
permitiendo distinguir perfiles de oferta más accionables para la toma
de decisiones estratégicas.
La tabla presenta el tamaño de cada conglomerado obtenido con la solución de k = 4, es decir, cuántas propiedades quedaron asignadas a cada segmento del mercado. Se observa que el Cluster 4 concentra la mayor proporción de registros (4.009 propiedades), por lo que representa el segmento más masivo o predominante de la oferta. En segundo lugar aparece el Cluster 1 con 2.732 propiedades, indicando un grupo también relevante en volumen. Los Clusters 2 y 3 son más pequeños (740 y 840 propiedades, respectivamente), lo que sugiere segmentos más específicos o de nicho dentro del mercado. En conjunto, esta distribución evidencia un mercado donde la oferta se agrupa principalmente en dos segmentos de alta presencia (clusters 4 y 1), complementados por dos segmentos minoritarios que pueden reflejar perfiles particulares de vivienda y oportunidades estratégicas diferenciadas.
set.seed(123)
# X_mat = matriz de scores PCA usada para clustering (Dim1..Dimk)
km4 <- kmeans(X_mat, centers = 4, nstart = 25)
# Guardar la asignación en df (solo k=4)
df <- df %>%
mutate(
row_id = row_number(),
cluster = factor(km4$cluster)
)
# Tabla de tamaños por cluster
tabla6_tamanos <- as.data.frame(table(df$cluster))
names(tabla6_tamanos) <- c("Cluster", "n")
knitr::kable(
tabla6_tamanos,
caption = "Tabla 6. Tamaño (n) de propiedades por cluster (k = 4).",
align = c("c", "r")
)
| Cluster | n |
|---|---|
| 1 | 840 |
| 2 | 4009 |
| 3 | 740 |
| 4 | 2732 |
En el plano de las dos primeras dimensiones del PCA (Dim1 y Dim2), el gráfico muestra cómo las propiedades se agrupan en cuatro segmentos y cómo se relacionan entre sí en términos de similitud multivariada. Se observa que los clusters no forman “islas” totalmente separadas, sino que presentan zonas de solapamiento, lo cual es esperable en un mercado inmobiliario donde los atributos (precio, área y dotación) cambian de forma continua.
Sin embargo, se aprecian patrones de diferenciación: hay un grupo (verde, Cluster 2) que se concentra principalmente hacia valores más altos de Dim1 y más bajos de Dim2, indicando un perfil relativamente distinto del núcleo central; otro grupo (rojo, Cluster 1) se ubica hacia valores positivos de Dim1 con mayor densidad en el centro-derecha del plano, sugiriendo un segmento más “típico” dentro de la oferta de nivel medio/alto; el Cluster 4 (morado) aparece más centrado y funciona como una franja de transición entre perfiles; y el Cluster 3 (azul) se muestra más disperso y con una envolvente amplia, lo que sugiere mayor heterogeneidad interna (incluye inmuebles con combinaciones variadas de atributos, incluso casos menos frecuentes).
En conjunto, el gráfico confirma que la solución de k = 4 captura una segmentación del mercado con perfiles diferenciables en el espacio de características, manteniendo una estructura realista donde existen gradientes y transiciones entre tipos de vivienda.
La segmentación en cuatro clusters (k = 4) evidencia perfiles claramente diferenciados por valorización (precio por m²), escala (área construida) y dotación (baños, habitaciones y parqueaderos).
El Cluster 2 (n = 4.009) concentra la mayor parte de la oferta y representa el segmento más compacto y económico, con una valorización baja (mediana 219) y menor área (mediana 78 m²), además de dotación básica (2 baños, 3 habitaciones y 1 parqueadero).
El Cluster 4 (n = 2.732) corresponde a una oferta intermedia o de gama media consolidada, con mayor tamaño (mediana 168 m²) y mejor dotación (4 baños y 2 parqueaderos), acompañada de una valorización media-alta (mediana 475).
El Cluster 3 (n = 740) agrupa viviendas de gran escala y alta capacidad habitacional, destacándose por su área elevada (mediana 300 m²) y un número notablemente alto de habitaciones (mediana 7), con un precio por m² intermedio (mediana 430), lo que sugiere inmuebles amplios cuyo valor se explica principalmente por metraje y capacidad.
Finalmente, el Cluster 1 (n = 840) representa el segmento premium, con la mayor valorización por m² (mediana 1.050), gran área (mediana 400 m²) y dotación superior (5 baños y 4 parqueaderos), constituyendo un nicho de alto valor relevante para estrategias de captación selectiva, valoración y decisiones de inversión (Ver Tabla 7).
# --- Validación mínima para evitar error si no se creó el cluster ---
stopifnot("cluster" %in% names(df))
# 1) Perfil numérico por cluster (medianas)
perfil_k4 <- df %>%
group_by(cluster) %>%
summarise(
n = n(),
med_preciom = median(preciom, na.rm = TRUE),
med_areaconst = median(areaconst, na.rm = TRUE),
med_banios = median(banios, na.rm = TRUE),
med_habitaciones = median(habitaciones, na.rm = TRUE),
med_parqueaderos = median(parqueaderos, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(cluster)
knitr::kable(
perfil_k4,
caption = "Tabla 7. Perfil numérico (medianas) por cluster (k = 4)."
)
| cluster | n | med_preciom | med_areaconst | med_banios | med_habitaciones | med_parqueaderos |
|---|---|---|---|---|---|---|
| 1 | 840 | 1050 | 400 | 5 | 4 | 4 |
| 2 | 4009 | 219 | 78 | 2 | 3 | 1 |
| 3 | 740 | 430 | 300 | 5 | 7 | 2 |
| 4 | 2732 | 475 | 168 | 4 | 3 | 2 |
La distribución por zona dentro de cada cluster evidencia una concentración territorial consistente: la Zona Sur agrupa la mayor proporción de inmuebles en los cuatro segmentos (entre 49,2% y 64,4%), confirmando su papel como principal área de oferta. No obstante, existen patrones diferenciados por segmento. El Cluster 1 es el más concentrado en el sur (64,4%) y complementa su presencia principalmente en la Zona Oeste (20,8%), mientras que el Cluster 2 muestra una estructura Sur–Norte más marcada (59,7% y 27,4%, respectivamente). El Cluster 3 presenta la distribución más diversificada, con participaciones relevantes en Sur (49,2%), Norte (22,3%) y Oriente (17,6%), lo que sugiere una presencia más extendida territorialmente. Finalmente, el Cluster 4 combina predominio en Sur (52,3%) con una presencia importante en Oeste (26,1%) y Norte (19,7%). En conjunto, los resultados indican que, aunque la oferta se concentra en el sur, cada segmento presenta un patrón espacial particular que puede orientar estrategias diferenciadas de valoración, captación y comercialización por territorio (Ver Tabla 8).
# 2) Distribución por zona (porcentaje dentro de cada cluster)
zona_k4 <- df %>%
count(cluster, zona, name = "n") %>%
group_by(cluster) %>%
mutate(
pct = n / sum(n),
pct_label = percent(pct, accuracy = 0.1)
) %>%
ungroup() %>%
arrange(cluster, desc(pct))
knitr::kable(
zona_k4,
caption = "Tabla 8. Distribución por zona dentro de cada cluster (k = 4)."
)
| cluster | zona | n | pct | pct_label |
|---|---|---|---|---|
| 1 | Zona Sur | 541 | 0.6440476 | 64.4% |
| 1 | Zona Oeste | 175 | 0.2083333 | 20.8% |
| 1 | Zona Norte | 118 | 0.1404762 | 14.0% |
| 1 | Zona Oriente | 4 | 0.0047619 | 0.5% |
| 1 | Zona Centro | 2 | 0.0023810 | 0.2% |
| 2 | Zona Sur | 2392 | 0.5966575 | 59.7% |
| 2 | Zona Norte | 1100 | 0.2743826 | 27.4% |
| 2 | Zona Oeste | 266 | 0.0663507 | 6.6% |
| 2 | Zona Oriente | 190 | 0.0473934 | 4.7% |
| 2 | Zona Centro | 61 | 0.0152158 | 1.5% |
| 3 | Zona Sur | 364 | 0.4918919 | 49.2% |
| 3 | Zona Norte | 165 | 0.2229730 | 22.3% |
| 3 | Zona Oriente | 130 | 0.1756757 | 17.6% |
| 3 | Zona Oeste | 43 | 0.0581081 | 5.8% |
| 3 | Zona Centro | 38 | 0.0513514 | 5.1% |
| 4 | Zona Sur | 1429 | 0.5230600 | 52.3% |
| 4 | Zona Oeste | 714 | 0.2613470 | 26.1% |
| 4 | Zona Norte | 537 | 0.1965593 | 19.7% |
| 4 | Zona Oriente | 27 | 0.0098829 | 1.0% |
| 4 | Zona Centro | 23 | 0.0084187 | 0.8% |
| 4 | NA | 2 | 0.0007321 | 0.1% |
La distribución por estrato dentro de cada cluster evidencia una segmentación socioeconómica clara. El Cluster 1 se asocia fuertemente con estratos altos, concentrando 68,9% de sus inmuebles en estrato 6 y 23,2% en estrato 5, lo que indica un perfil predominantemente de alta gama. El Cluster 2 presenta un patrón típico de estratos medios, con predominio de estrato 4 (37,7%) y estrato 5 (32,0%), además de una participación relevante en estrato 3 (25,6%) y baja presencia en estrato 6 (4,7%).
El Cluster 3 se caracteriza por una mayor concentración en estrato 3 (40,0%), complementada por estratos 4 (23,5%) y 5 (30,8%), reflejando un segmento más orientado a estratos medio-bajos.
Finalmente, el Cluster 4 muestra un perfil alto pero más balanceado entre estrato 6 (43,1%) y estrato 5 (38,3%), con menor participación de estratos 3 y 4. En conjunto, estos resultados confirman que los conglomerados capturan diferencias sustantivas del mercado inmobiliario no solo en atributos de oferta, sino también en su distribución socioeconómica, lo cual permite orientar estrategias diferenciadas por segmento.
# 3) Distribución por estrato (porcentaje dentro de cada cluster)
estrato_k4 <- df %>%
count(cluster, estrato_cat, name = "n") %>%
group_by(cluster) %>%
mutate(
pct = n / sum(n),
pct_label = percent(pct, accuracy = 0.1)
) %>%
ungroup() %>%
arrange(cluster, estrato_cat)
knitr::kable(
estrato_k4,
caption = "Tabla 9. Distribución por estrato dentro de cada cluster (k = 4)."
)
| cluster | estrato_cat | n | pct | pct_label |
|---|---|---|---|---|
| 1 | 3 | 17 | 0.0202381 | 2.0% |
| 1 | 4 | 49 | 0.0583333 | 5.8% |
| 1 | 5 | 195 | 0.2321429 | 23.2% |
| 1 | 6 | 579 | 0.6892857 | 68.9% |
| 2 | 3 | 1026 | 0.2559242 | 25.6% |
| 2 | 4 | 1513 | 0.3774008 | 37.7% |
| 2 | 5 | 1281 | 0.3195311 | 32.0% |
| 2 | 6 | 189 | 0.0471439 | 4.7% |
| 3 | 3 | 296 | 0.4000000 | 40.0% |
| 3 | 4 | 174 | 0.2351351 | 23.5% |
| 3 | 5 | 228 | 0.3081081 | 30.8% |
| 3 | 6 | 42 | 0.0567568 | 5.7% |
| 4 | 3 | 114 | 0.0417277 | 4.2% |
| 4 | 4 | 393 | 0.1438507 | 14.4% |
| 4 | 5 | 1046 | 0.3828697 | 38.3% |
| 4 | 6 | 1177 | 0.4308199 | 43.1% |
| 4 | NA | 2 | 0.0007321 | 0.1% |
En esta sección se realizó un Análisis de Correspondencia simple (CA) para examinar la relación entre dos variables categóricas del mercado inmobiliario: zona y tipo de vivienda. Primero, se construyó una base específica para el análisis, conservando únicamente estas dos variables y excluyendo registros con valores faltantes, con el fin de garantizar una tabla de frecuencias consistente.
Posteriormente, se elaboró la tabla de contingencia Zona × Tipo, que resume cuántas propiedades de cada tipo se observan en cada zona. Como validación estadística inicial, se aplicó una prueba Chi-cuadrado de independencia para evaluar si la distribución del tipo de vivienda varía significativamente entre zonas. Posteriormente, se ejecutó el CA, que proyecta las categorías en un espacio factorial de baja dimensión, permitiendo visualizar y sintetizar los patrones de asociación: categorías cercanas en el eje principal (Dim1) sugieren combinaciones zona–tipo más frecuentes de lo esperado, mientras que posiciones opuestas reflejan contrastes en la composición de la oferta. Finalmente, se generó una visualización estable del resultado (en 1D o 2D según las dimensiones disponibles) para facilitar la interpretación en el informe.
En la Tabla de frecuencias Zona por Tipo de vivienda, muestra la distribución observada de la oferta por zona y tipo de vivienda (frecuencias absolutas). Lo que se evidencia es un patrón territorial claro:
La Zona Sur concentra el mayor volumen del mercado para ambos tipos (2.787 apartamentos y 1.939 casas), por lo que funciona como el principal polo de oferta en la base.
En términos de composición, hay zonas donde predomina fuertemente un tipo:
Zona Oeste está marcada por una oferta principalmente de apartamentos (1.029 vs 169 casas), es decir, alrededor de 86% apartamentos.
Zona Centro y Zona Oriente presentan predominio de casas (Centro: 100 vs 24; Oriente: 289 vs 62), con proporciones aproximadas de 81%–82% casas.
Zona Norte y Zona Sur muestran un patrón más mixto, pero con mayor presencia de apartamentos:
Zona Norte: 1.198 apartamentos vs 722 casas (≈ 62% apartamentos).
Zona Sur: 2.787 apartamentos vs 1.939 casas (≈ 59% apartamentos).
En el total general, la base refleja más apartamentos que casas (5.100 vs 3.219), es decir, cerca de 61% apartamentos en el conjunto.
En conjunto, estos resultados sugieren que el tipo de vivienda varía según la zona, lo que respalda la utilidad del Análisis de Correspondencia para visualizar esas asociaciones (zonas con perfil más “vertical” de apartamentos vs zonas con perfil más “tradicional” de casas) (Ver Tabla 10).
# 1) Preparar datos (zona y tipo) y quitar NA
df_ca_zt <- df %>%
transmute(
zona = factor(zona),
tipo = factor(tipo)
) %>%
filter(!is.na(zona), !is.na(tipo)) %>%
droplevels()
# 2) Tabla de contingencia
tab_zt <- table(df_ca_zt$zona, df_ca_zt$tipo)
kable(as.data.frame.matrix(tab_zt),
caption = "Tabla 10. Frecuencias Zona × Tipo de vivienda.")
| Apartamento | Casa | |
|---|---|---|
| Zona Centro | 24 | 100 |
| Zona Norte | 1198 | 722 |
| Zona Oeste | 1029 | 169 |
| Zona Oriente | 62 | 289 |
| Zona Sur | 2787 | 1939 |
La prueba Chi-cuadrado de independencia entre zona y tipo de vivienda muestra un estadístico muy alto (X² = 690,93) con 4 grados de libertad y un p-valor ≈ 0 (extremadamente pequeño). Esto implica que se rechaza la hipótesis de independencia, es decir, existe evidencia estadísticamente significativa de que la distribución del tipo de vivienda (Casa/Apartamento) no es la misma en todas las zonas (Ver Tabla 11).
En términos prácticos, el mercado presenta un patrón territorial claro: ciertas zonas concentran proporcionalmente más apartamentos y otras más casas, por lo que la zona es un factor relevante para caracterizar la estructura de la oferta y sustenta el uso del Análisis de Correspondencia para visualizar estas asociaciones (ver Tabla Prueba Chi-cuadrado para Zona × Tipo).
# 3) Chi-cuadrado
chi_zt <- chisq.test(tab_zt)
kable(
data.frame(
Estadistico = "Chi-cuadrado",
X2 = unname(chi_zt$statistic),
gl = unname(chi_zt$parameter),
p_valor = unname(chi_zt$p.value)
),
caption = "Tabla 11. Prueba Chi-cuadrado para Zona × Tipo."
)
| Estadistico | X2 | gl | p_valor |
|---|---|---|---|
| Chi-cuadrado | 690.9297 | 4 | 0 |
Dado que tipo tiene solo dos categorías, el CA se resume en una única dimensión (Dim1), que explica el 100% de la inercia, y representa el principal contraste del mercado: zonas con predominio relativo de apartamentos frente a zonas con predominio relativo de casas. En este patrón, la Zona Oeste y, en menor medida, Zona Norte y Zona Sur se asocian con una mayor presencia de apartamentos, mientras que la Zona Centro y la Zona Oriente muestran una oferta relativamente más orientada a casas. En conjunto, los resultados indican que el tipo de vivienda disponible en el mercado urbano está condicionado por la estructura territorial, aportando evidencia útil para estrategias diferenciadas de valoración y comercialización por zona (Ver Tabla 12).
# 4) CA
ncp_zt <- min(nrow(tab_zt) - 1, ncol(tab_zt) - 1)
res_ca_zt <- FactoMineR::CA(tab_zt, ncp = ncp_zt, graph = FALSE)
eig_zt <- as.data.frame(res_ca_zt$eig)
kable(eig_zt, caption = "Tabla 12. Inercia explicada por dimensión (CA Zona × Tipo).")
| eigenvalue | percentage of variance | cumulative percentage of variance | |
|---|---|---|---|
| dim 1 | 0.0830544 | 100 | 100 |
En el gráfico de CA simple (1D), todos los puntos están ubicados sobre una sola línea (la Dimensión 1), lo que indica que toda la asociación Zona–Tipo se resume en un único eje. La lectura clave es por proximidad: las categorías que aparecen más cerca entre sí sobre la Dimensión 1 tienden a estar más asociadas en el patrón de oferta.
En el panel Tipo, Casa queda claramente hacia el extremo izquierdo, mientras Apartamento queda hacia el derecho. Por tanto, la Dimensión 1 puede interpretarse como un eje “Casa ↔︎ Apartamento”.
En el panel Zona, se observa que Zona Oriente se ubica hacia el lado de Casa, lo que sugiere una asociación relativa de esa zona con oferta tipo casa.
Zona Oeste aparece más hacia el lado de Apartamento, indicando una asociación relativa de esa zona con oferta tipo apartamento.
Zona Norte y Zona Sur están más cerca del centro (y relativamente más cercanas al lado de Apartamento que al de Casa), lo que sugiere un comportamiento menos extremo: su patrón se parece más al promedio general y no está tan marcado hacia un solo tipo como Oriente u Oeste.
Zona Centro queda cerca del centro del eje (y próxima a Apartamento en el gráfico), lo que indica que su perfil también es más promedio comparado con las zonas más extremas.
En síntesis, el gráfico muestra que la estructura principal de la relación Zona–Tipo está dominada por un contraste: Oriente se alinea más con “Casa”, mientras Oeste se alinea más con “Apartamento”; las demás zonas se ubican en posiciones intermedias (Ver Gráfico 10).
# 5) Coordenadas
row_coord <- as.data.frame(res_ca_zt$row$coord)
col_coord <- as.data.frame(res_ca_zt$col$coord)
# Función robusta: extrae la Dim1 como la primera columna
get_dim1 <- function(coord_df) as.numeric(coord_df[[1]])
if (ncp_zt == 1) {
row_plot <- data.frame(
Grupo = "Zona",
Categoria = rownames(row_coord),
Dim1 = get_dim1(row_coord)
)
col_plot <- data.frame(
Grupo = "Tipo",
Categoria = rownames(col_coord),
Dim1 = get_dim1(col_coord)
)
coords <- bind_rows(row_plot, col_plot)
ggplot(coords, aes(x = Dim1, y = 0, label = Categoria)) +
geom_point() +
geom_text(vjust = -0.8, size = 3) +
facet_wrap(~Grupo, scales = "free_x") +
labs(
title = "Gráfico 10. CA simple (1D): Asociación Zona × Tipo sobre Dim1",
x = "Dimensión 1 (CA)",
y = ""
) +
theme_minimal() +
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.grid.minor = element_blank())
} else {
# 2D: usar 1ra y 2da columna (Dim1 y Dim2)
row_plot <- data.frame(
Grupo = "Zona",
Categoria = rownames(row_coord),
Dim1 = as.numeric(row_coord[[1]]),
Dim2 = as.numeric(row_coord[[2]])
)
col_plot <- data.frame(
Grupo = "Tipo",
Categoria = rownames(col_coord),
Dim1 = as.numeric(col_coord[[1]]),
Dim2 = as.numeric(col_coord[[2]])
)
coords <- bind_rows(row_plot, col_plot)
ggplot(coords, aes(x = Dim1, y = Dim2, label = Categoria, shape = Grupo)) +
geom_point(size = 2) +
geom_text(vjust = -0.7, size = 3) +
labs(
title = "Gráfico 10. CA simple (2D): Asociación Zona × Tipo (Dim1 vs Dim2)",
x = "Dimensión 1 (CA)",
y = "Dimensión 2 (CA)"
) +
theme_minimal()
}
El análisis integral de la oferta inmobiliaria urbana, a partir de 8.322 registros y 13 variables, evidenció un mercado altamente heterogéneo en precio y tamaño, con distribuciones sesgadas y presencia de valores extremos, especialmente en precio total aproximado, número de habitaciones y parqueaderos. Esta estructura confirma la coexistencia de segmentos estándar y segmentos premium, por lo que el uso de medianas, cuartiles y transformaciones logarítmicas resultó clave para obtener lecturas robustas y comparables.
La exploración descriptiva y el análisis de correlaciones mostraron que el mercado valora principalmente el metraje y las amenidades (área construida, baños y parqueaderos) por encima del simple número de habitaciones, y que variables derivadas como el precio total aproximado son útiles para aproximaciones económicas, pero deben manejarse con cuidado por su alta dispersión. En términos de calidad de datos, la base presenta completitud casi total en las variables centrales del análisis, con dos focos claros de incompletitud: piso (31,7% faltantes) y parqueaderos (19,3%), lo que justifica precaución al incorporarlas en técnicas multivariadas.
El PCA permitió sintetizar la estructura del mercado: las dos primeras dimensiones explican 82,8% de la variación, donde la primera dimensión representa un gradiente dominante de escala y valorización (precio, área y dotación), y la segunda captura diferencias más finas asociadas a configuración interna. Esta reducción confirmó que el mercado puede interpretarse adecuadamente en un plano de baja dimensión, facilitando la segmentación posterior.
Con base en esa estructura, el análisis de conglomerados con k=4 ofreció una segmentación útil y accionable, equilibrando calidad de agrupación (reducción del WSS) y granularidad interpretativa. Los cuatro clusters identifican perfiles consistentes y diferenciables: un segmento premium (Cluster 1) con mayor valorización y dotación; un segmento económico/compacto (Cluster 2) masivo y de menor área y precio; un segmento amplio de alta capacidad habitacional (Cluster 3) con muchas habitaciones y gran metraje; y un segmento medio consolidado (Cluster 4) con valorización media-alta y dotación superior a la estándar. La distribución por zona mostró una concentración transversal de la oferta en la Zona Sur, pero con patrones territoriales diferenciados por segmento; y la composición por estrato confirmó que los clusters capturan una segmentación socioeconómica real, con asociaciones claras entre perfiles de oferta y estratos predominantes.
Finalmente, el análisis de correspondencia simple entre zona y tipo de vivienda demostró que la oferta no es territorialmente neutral: existe un contraste estructural entre zonas relativamente más asociadas a apartamentos (especialmente Oeste) y zonas más asociadas a casas (especialmente Oriente), mientras Norte y Sur presentan comportamientos más intermedios. En conjunto, los resultados ofrecen una lectura coherente: el mercado se organiza por un gradiente principal de valorización/escala, se segmenta en cuatro perfiles con utilidad estratégica y además presenta patrones territoriales y tipológicos que pueden orientar decisiones de análisis, valoración y caracterización del comportamiento de la oferta por zona.