Una empresa inmobiliaria necesita entender mejor el mercado urbano de
vivienda para tomar decisiones de compra, venta y valoración con más
criterio. Para eso se analizaron 8.322 propiedades residenciales (datos
obtenidos de OLX, disponibles en el paquete paqueteMODELOS)
con tres técnicas de análisis multivariado -componentes principales,
conglomerados y correspondencias- apoyadas en mapas y gráficos.
En términos generales, la variación del mercado se puede resumir en dos dimensiones: el tamaño/valor de la propiedad por un lado, y la relación entre estrato y número de habitaciones por otro. A partir de esas dimensiones las propiedades se agrupan en cuatro segmentos con precios, áreas y estratos bastante distintos entre sí, lo que permite pensar en estrategias de precio diferenciadas en lugar de un enfoque único. También se encontró que el tipo de vivienda (casa o apartamento) no se reparte igual en todas las zonas de la ciudad -la relación es estadísticamente significativa- y que tanto los precios como los segmentos siguen un patrón geográfico claro y no aleatorio.
Con esto la empresa puede priorizar zonas, ajustar precios por segmento y enfocar mejor sus esfuerzos comerciales.
Una empresa inmobiliaria de una gran ciudad quiere entender mejor su mercado de vivienda para tomar decisiones más informadas. Cuenta con una base de datos amplia sobre las propiedades residenciales que tiene en oferta, pero hasta ahora no la ha explotado más allá de lo descriptivo. El objetivo de este trabajo es hacer un análisis más completo de esos datos que ayude a identificar patrones, relaciones y segmentos útiles para las decisiones de compra, venta y valoración de inmuebles.
Para eso se abordan cuatro frentes: primero, un análisis de componentes principales para reducir la dimensionalidad de las variables numéricas y ver qué características explican mejor la variación de precios; segundo, un análisis de conglomerados para agrupar las propiedades en segmentos con características parecidas; tercero, un análisis de correspondencias para ver cómo se relacionan variables categóricas como el tipo de vivienda, la zona y el barrio; y por último, visualizaciones y mapas que resuman todo lo anterior de forma clara para la dirección de la empresa.
Los conceptos usados aquí se apoyan en los tutoriales del paquete
paqueteMODELOS (Tutorial101, Tutorial102 y Tutorial103),
donde se explican los fundamentos de cada técnica.
El análisis de componentes principales (PCA) es una técnica de reducción de dimensionalidad: toma un grupo de variables numéricas correlacionadas y las transforma en un número menor de componentes ortogonales (no correlacionados entre sí), ordenados de mayor a menor según la varianza que explican. Se calcula a partir de los eigenvalores y eigenvectores de la matriz de correlación, y en la práctica sirve para resumir la información original con la menor pérdida posible de varianza.
El análisis de conglomerados (cluster) es una técnica de aprendizaje no supervisado que agrupa observaciones parecidas entre sí -y distintas de las de otros grupos- a partir de una medida de distancia. Para decidir cuántos grupos usar se suele recurrir al método del codo (que mira cómo cae la varianza intra-clúster a medida que se agregan grupos) o al índice de silueta (que mide qué tan bien separados y cohesionados quedan los grupos).
El análisis de correspondencias explora la relación entre variables categóricas a partir de una tabla de contingencia. Descompone la inercia de esa asociación (el equivalente categórico a la varianza) en dimensiones que se pueden graficar, ubicando las categorías de fila y de columna en un mismo plano. Cuando hay más de dos variables categóricas se usa su extensión, el análisis de correspondencias múltiple (ACM).
La base proviene de un ejercicio de webscraping sobre el portal OLX y contiene 8,322 registros de propiedades residenciales con 13 variables:
data.frame(
Variable = c("id","zona","piso","estrato","preciom","areaconst","parqueaderos",
"banios","habitaciones","tipo","barrio","longitud","latitud"),
Descripción = c("Identificador de la propiedad","Zona geográfica de la ciudad",
"Número de piso (alta proporción de datos faltantes)",
"Estrato socioeconómico","Precio en millones de pesos",
"Área construida (m²)","Número de parqueaderos",
"Número de baños","Número de habitaciones",
"Tipo de propiedad (Casa / Apartamento)","Barrio",
"Coordenada geográfica (longitud)","Coordenada geográfica (latitud)")
) %>% tabla(caption = "Diccionario de variables")| Variable | Descripción |
|---|---|
| id | Identificador de la propiedad |
| zona | Zona geográfica de la ciudad |
| piso | Número de piso (alta proporción de datos faltantes) |
| estrato | Estrato socioeconómico |
| preciom | Precio en millones de pesos |
| areaconst | Área construida (m²) |
| parqueaderos | Número de parqueaderos |
| banios | Número de baños |
| habitaciones | Número de habitaciones |
| tipo | Tipo de propiedad (Casa / Apartamento) |
| barrio | Barrio |
| longitud | Coordenada geográfica (longitud) |
| latitud | Coordenada geográfica (latitud) |
Las coordenadas y los nombres de barrio (Valle del Lili, Ciudad Jardín, Pance, La Flora, entre otros) dejan ver que se trata de Santiago de Cali, lo cual ayuda a interpretar mejor los resultados geográficos más adelante.
na_tab <- data.frame(Variable = names(vivienda), Faltantes = colSums(is.na(vivienda))) %>%
mutate(`% Faltante` = round(100*Faltantes/nrow(vivienda),1)) %>%
arrange(desc(Faltantes))
na_tab %>% tabla(caption = "Valores faltantes por variable", digits = 1)| Variable | Faltantes | % Faltante | |
|---|---|---|---|
| piso | piso | 2,638 | 31.7 |
| parqueaderos | parqueaderos | 1,605 | 19.3 |
| id | id | 3 | 0.0 |
| zona | zona | 3 | 0.0 |
| estrato | estrato | 3 | 0.0 |
| areaconst | areaconst | 3 | 0.0 |
| banios | banios | 3 | 0.0 |
| habitaciones | habitaciones | 3 | 0.0 |
| tipo | tipo | 3 | 0.0 |
| barrio | barrio | 3 | 0.0 |
| longitud | longitud | 3 | 0.0 |
| latitud | latitud | 3 | 0.0 |
| preciom | preciom | 2 | 0.0 |
piso (32% de faltantes) y parqueaderos
(19%) son las variables con más datos ausentes; las demás tienen
faltantes marginales, de máximo 3 registros. Por eso piso
se deja por fuera de los análisis cuantitativos: no aporta lo suficiente
como para justificar el hueco de información que tiene. Para PCA y
conglomerados se usan solo los registros completos en las variables
numéricas relevantes (incluyendo parqueaderos), y para
correspondencias se usan los registros completos en zona, tipo, barrio y
estrato, que al no depender de parqueaderos permite
conservar más observaciones. Además, preciom y
areaconst se transforman con logaritmo natural antes de PCA
y cluster, porque tienen un sesgo marcado hacia la derecha (la media
casi dobla la mediana) y sin esa transformación unas pocas propiedades
de lujo terminarían dominando el análisis.
num_vars <- c("estrato","preciom","areaconst","parqueaderos","banios","habitaciones")
viv_num <- vivienda %>%
filter(if_all(all_of(c(num_vars, "zona","tipo","latitud","longitud")), ~ !is.na(.))) %>%
mutate(log_preciom = log(preciom), log_areaconst = log(areaconst))
n_pca <- nrow(viv_num)El conjunto depurado para PCA y cluster conserva 6,717 propiedades, un 80.7% del total.
vivienda %>%
select(estrato, preciom, areaconst, parqueaderos, banios, habitaciones) %>%
summary() %>% as.data.frame.matrix() %>% tabla(caption = "Resumen estadístico de variables numéricas")| estrato | preciom | areaconst | parqueaderos | banios | habitaciones | |
|---|---|---|---|---|---|---|
| X | Min. :3.000 | Min. : 58.0 | Min. : 30.0 | Min. : 1.000 | Min. : 0.000 | Min. : 0.000 |
| X.1 | 1st Qu.:4.000 | 1st Qu.: 220.0 | 1st Qu.: 80.0 | 1st Qu.: 1.000 | 1st Qu.: 2.000 | 1st Qu.: 3.000 |
| X.2 | Median :5.000 | Median : 330.0 | Median : 123.0 | Median : 2.000 | Median : 3.000 | Median : 3.000 |
| X.3 | Mean :4.634 | Mean : 433.9 | Mean : 174.9 | Mean : 1.835 | Mean : 3.111 | Mean : 3.605 |
| X.4 | 3rd Qu.:5.000 | 3rd Qu.: 540.0 | 3rd Qu.: 229.0 | 3rd Qu.: 2.000 | 3rd Qu.: 4.000 | 3rd Qu.: 4.000 |
| X.5 | Max. :6.000 | Max. :1999.0 | Max. :1745.0 | Max. :10.000 | Max. :10.000 | Max. :10.000 |
| X.6 | NA’s :3 | NA’s :2 | NA’s :3 | NA’s :1605 | NA’s :3 | NA’s :3 |
ggplot(vivienda %>% filter(!is.na(zona)), aes(x = reorder(zona, preciom, median), y = preciom, fill = zona)) +
geom_boxplot(show.legend = FALSE, outlier.alpha = 0.3) +
scale_fill_manual(values = colorRampPalette(paleta_seg)(5)) +
coord_flip() +
labs(x = NULL, y = "Precio (millones COP)") +
theme_minimal(base_size = 12)Distribución de precio por zona
mat_cor <- cor(viv_num %>% select(estrato, log_preciom, log_areaconst, parqueaderos, banios, habitaciones))
corrplot(mat_cor, method = "color", type = "upper", addCoef.col = "black",
tl.col = "black", tl.srt = 45, number.cex = 0.8, col = colorRampPalette(c(col_sec,"white",col_prin))(200))Matriz de correlación entre variables numéricas
Las variables numéricas están correlacionadas entre sí de forma moderada a fuerte (precio-área y área-baños, por ejemplo), lo cual justifica reducir su dimensionalidad con PCA.
El flujo de trabajo fue el siguiente. Primero se depuraron los datos:
se trataron los faltantes, se transformaron con logaritmo las variables
más asimétricas y se estandarizaron (media 0, varianza 1) antes de
entrar a PCA y cluster. Luego se corrió el PCA con
FactoMineR::PCA() sobre las seis variables numéricas
estandarizadas, seleccionando el número de componentes con el criterio
del codo y la varianza acumulada. Para el cluster, el número de grupos
se definió con el índice de silueta
(factoextra::fviz_nbclust) calculado sobre una muestra
representativa, y el modelo final se ajustó con k-means
(nstart = 25) sobre todo el conjunto depurado; los grupos
resultantes se renombraron como segmentos de mercado según su precio
promedio, para que sean más fáciles de leer desde el negocio. Para las
correspondencias se construyó una tabla de contingencia zona-tipo
(correspondencia clásica, con prueba chi-cuadrado de independencia) y un
análisis de correspondencias múltiple entre zona, tipo y barrio,
agrupando los barrios menos frecuentes en la categoría “Otros” para no
perder interpretabilidad. Por último, se generaron mapas de dispersión
geográfica coloreados por precio y por segmento.
Todo el análisis se hizo en R, con los paquetes
FactoMineR, factoextra, ggplot2 y
dplyr.
pca_vars <- viv_num %>% select(estrato, log_preciom, log_areaconst, parqueaderos, banios, habitaciones)
res.pca <- PCA(pca_vars, scale.unit = TRUE, graph = FALSE)
eig_tab <- as.data.frame(res.pca$eig)
names(eig_tab) <- c("Eigenvalor","% Varianza","% Varianza acumulada")fviz_eig(res.pca, addlabels = TRUE, barfill = col_prin, barcolor = col_prin, linecolor = col_sec) +
labs(title = NULL, x = "Componente", y = "% de varianza explicada")Varianza explicada por componente
| Eigenvalor | % Varianza | % Varianza acumulada | |
|---|---|---|---|
| comp 1 | 3.67 | 61.23 | 61.23 |
| comp 2 | 1.21 | 20.24 | 81.47 |
| comp 3 | 0.49 | 8.10 | 89.57 |
| comp 4 | 0.29 | 4.78 | 94.35 |
| comp 5 | 0.24 | 3.94 | 98.29 |
Las dos primeras componentes explican 81.5% de la varianza total, suficiente para resumir la estructura del mercado en un plano de dos dimensiones sin perder demasiada información.
fviz_pca_var(res.pca, col.var = "contrib", gradient.cols = c(col_terc, col_sec, "#7a0177"),
repel = TRUE) + labs(title = NULL)Círculo de correlación de variables
data.frame(Variable = rownames(res.pca$var$cor),
`Correlación Dim.1` = round(res.pca$var$cor[,1],2),
`Correlación Dim.2` = round(res.pca$var$cor[,2],2),
`Contribución Dim.1 (%)` = round(res.pca$var$contrib[,1],1),
`Contribución Dim.2 (%)` = round(res.pca$var$contrib[,2],1),
check.names = FALSE) %>%
tabla(caption = "Correlación y contribución de variables a los dos primeros componentes")| Variable | Correlación Dim.1 | Correlación Dim.2 | Contribución Dim.1 (%) | Contribución Dim.2 (%) | |
|---|---|---|---|---|---|
| estrato | estrato | 0.6 | -0.7 | 9.2 | 41.7 |
| log_preciom | log_preciom | 0.9 | -0.2 | 22.8 | 5.2 |
| log_areaconst | log_areaconst | 0.9 | 0.2 | 21.9 | 3.1 |
| parqueaderos | parqueaderos | 0.8 | -0.1 | 16.3 | 1.9 |
| banios | banios | 0.9 | 0.2 | 21.0 | 2.9 |
| habitaciones | habitaciones | 0.6 | 0.7 | 8.8 | 45.3 |
La primera dimensión se puede leer como “tamaño y valor de la propiedad”: correlaciona positivamente con precio, área, baños y parqueaderos, y separa las propiedades grandes y costosas (a la derecha) de las pequeñas y económicas (a la izquierda). La segunda dimensión contrasta el estrato (negativo) con el número de habitaciones (positivo), y en la práctica separa viviendas de estrato alto con pocas habitaciones -típicamente apartamentos- de viviendas de estrato más bajo pero con más habitaciones, como suelen ser las casas familiares grandes.
fviz_pca_ind(res.pca, geom = "point", alpha.ind = 0.4,
col.ind = viv_num$tipo, palette = c(col_prin, col_sec),
addEllipses = TRUE, legend.title = "Tipo") + labs(title = NULL)Individuos proyectados en el plano principal, coloreados por tipo de vivienda
Casas y apartamentos ocupan zonas parcialmente distintas del plano, sobre todo a lo largo de la segunda dimensión, lo cual tiene sentido dadas sus diferencias típicas en número de habitaciones y estrato.
set.seed(123)
muestra_idx <- sample(seq_len(nrow(pca_vars)), min(1500, nrow(pca_vars)))
fviz_nbclust(scale(pca_vars[muestra_idx, ]), kmeans, method = "silhouette", k.max = 8) +
labs(title = NULL)Selección del número óptimo de clústeres (índice de silueta, muestra representativa)
set.seed(123)
k_final <- 4
km <- kmeans(scale(pca_vars), centers = k_final, nstart = 25)
viv_num$cluster_raw <- factor(km$cluster)
perfil <- viv_num %>% group_by(cluster_raw) %>%
summarise(n = n(), precio = mean(preciom), area = mean(areaconst),
estrato = mean(estrato), parqueaderos = mean(parqueaderos),
banios = mean(banios), habitaciones = mean(habitaciones)) %>%
arrange(desc(precio))
nombres_segmento <- c("Premium", "Amplio de gama media", "Estándar", "Económico compacto")[1:k_final]
mapa_nombres <- setNames(nombres_segmento, perfil$cluster_raw)
viv_num$segmento <- factor(mapa_nombres[as.character(viv_num$cluster_raw)], levels = nombres_segmento)
perfil$segmento <- nombres_segmento
sil_idx <- sample(seq_len(nrow(pca_vars)), min(2000, nrow(pca_vars)))
sil <- silhouette(km$cluster[sil_idx], dist(scale(pca_vars)[sil_idx, ]))
sil_avg <- round(mean(sil[,3]), 2)Con el índice de silueta se llegó a 4 conglomerados, ajustados con k-means sobre las 6,717 propiedades del conjunto depurado. El índice de silueta promedio, estimado sobre una muestra de validación, quedó en 0.3.
Para que sean más fáciles de usar comercialmente, los clústeres se renombraron como segmentos de mercado según su precio promedio:
perfil %>% select(Segmento = segmento, `N° propiedades` = n, `Precio prom. (M COP)` = precio,
`Área prom. (m²)` = area, `Estrato prom.` = estrato,
`Parqueaderos prom.` = parqueaderos, `Baños prom.` = banios,
`Habitaciones prom.` = habitaciones) %>%
tabla(caption = "Perfil promedio de cada segmento de mercado", digits = 2)| Segmento | N° propiedades | Precio prom. (M COP) | Área prom. (m²) | Estrato prom. | Parqueaderos prom. | Baños prom. | Habitaciones prom. |
|---|---|---|---|---|---|---|---|
| Premium | 986 | 1,066.56 | 391.91 | 5.71 | 3.76 | 5.15 | 4.40 |
| Amplio de gama media | 2,124 | 511.30 | 164.43 | 5.49 | 1.92 | 3.42 | 3.29 |
| Estándar | 853 | 439.93 | 283.61 | 4.03 | 1.70 | 4.20 | 5.84 |
| Económico compacto | 2,754 | 231.15 | 86.82 | 4.25 | 1.12 | 2.16 | 2.89 |
fviz_cluster(list(data = scale(pca_vars), cluster = viv_num$segmento),
geom = "point", alpha = 0.4, palette = paleta_seg,
ellipse.type = "convex", ggtheme = theme_minimal(base_size = 12),
legend.title = "Segmento") + labs(title = NULL)Segmentos de mercado proyectados sobre las dos primeras componentes principales
tab_seg_tipo <- table(viv_num$segmento, viv_num$tipo)
tab_seg_zona <- table(viv_num$segmento, viv_num$zona)ggplot(viv_num, aes(x = segmento, y = preciom, fill = segmento)) +
geom_boxplot(show.legend = FALSE, outlier.alpha = 0.3) +
scale_fill_manual(values = paleta_seg) +
labs(x = NULL, y = "Precio (millones COP)") +
theme_minimal(base_size = 12) +
theme(axis.text.x = element_text(angle = 15, hjust = 1))Distribución de precio por segmento
En resumen, el segmento Premium agrupa las propiedades de mayor precio y área -pensando en valorización y clientes de alto poder adquisitivo-, mientras que Económico compacto concentra la oferta más económica y compacta, más relevante para estrategias de volumen y rotación rápida.
viv_cat <- vivienda %>% filter(!is.na(zona), !is.na(tipo), !is.na(barrio), !is.na(estrato))
tab_zt <- table(viv_cat$zona, viv_cat$tipo)
chi_zt <- chisq.test(tab_zt)| Apartamento | Casa | |
|---|---|---|
| Zona Centro | 24 | 100 |
| Zona Norte | 1,198 | 722 |
| Zona Oeste | 1,029 | 169 |
| Zona Oriente | 62 | 289 |
| Zona Sur | 2,787 | 1,939 |
La prueba chi-cuadrado de independencia (X² = 690.9, gl = 4, p < 0.001) confirma que zona y tipo de vivienda están asociados de forma significativa: la oferta de apartamentos y casas no se reparte igual en toda la ciudad.
Como tipo solo tiene dos categorías, esa asociación
queda resumida en una única dimensión (el rango es mín(filas-1,
columnas-1) = 1), así que en vez de un mapa de correspondencia en dos
dimensiones se muestra directamente como proporciones por zona:
ggplot(viv_cat, aes(x = reorder(zona, as.numeric(factor(tipo))), fill = tipo)) +
geom_bar(position = "fill") +
scale_fill_manual(values = c(col_prin, col_sec), name = "Tipo") +
scale_y_continuous(labels = scales::percent) +
coord_flip() +
labs(x = NULL, y = "Proporción") +
theme_minimal(base_size = 12)Proporción de tipo de vivienda por zona (componente de correspondencia)
Zona Oeste tiene una proporción mayor de apartamentos, mientras que en Zona Oriente y Zona Centro predominan las casas. Zona Norte y Zona Sur, que concentran el mayor volumen de oferta, tienen una mezcla más pareja de los dos tipos.
top_barrios <- names(sort(table(viv_cat$barrio), decreasing = TRUE))[1:10]
viv_cat <- viv_cat %>% mutate(barrio_grp = ifelse(barrio %in% top_barrios, barrio, "Otros"))
mca_data <- viv_cat %>% select(zona, tipo, barrio_grp) %>% mutate(across(everything(), as.factor))
res.mca <- MCA(mca_data, graph = FALSE)
eig_mca <- as.data.frame(res.mca$eig)[1:5, ]
names(eig_mca) <- c("Eigenvalor","% Inercia","% Inercia acumulada")Para ver zona, tipo y barrio al mismo tiempo se aplicó un análisis de correspondencias múltiple, agrupando los barrios menos frecuentes en la categoría “Otros” (se dejaron los 10 barrios más frecuentes de forma individual).
| Eigenvalor | % Inercia | % Inercia acumulada | |
|---|---|---|---|
| dim 1 | 0.56 | 11.25 | 11.25 |
| dim 2 | 0.53 | 10.63 | 21.89 |
| dim 3 | 0.45 | 9.01 | 30.90 |
| dim 4 | 0.35 | 7.06 | 37.96 |
| dim 5 | 0.33 | 6.67 | 44.63 |
fviz_mca_var(res.mca, repel = TRUE, col.var = "contrib",
gradient.cols = c(col_terc, col_sec, "#7a0177")) + labs(title = NULL)Mapa de categorías: zona, tipo y barrio (ACM)
El primer eje separa sobre todo a Zona Oeste (con barrios como Ciudad Jardín y Pance) del resto de la ciudad, y el segundo diferencia a Zona Norte de barrios con alta concentración de oferta como La Flora y Valle del Lili. En la práctica, barrio y zona terminan contando una historia parecida, pero el barrio agrega un nivel de detalle que la zona por sí sola no captura.
ggplot(viv_num, aes(x = longitud, y = latitud, color = log_preciom)) +
geom_point(alpha = 0.5, size = 1) +
scale_color_gradient(low = col_terc, high = "#7a0177", name = "log(Precio)") +
coord_fixed(1.05) +
labs(x = "Longitud", y = "Latitud") +
theme_minimal(base_size = 12)Distribución geográfica de precios
ggplot(viv_num, aes(x = longitud, y = latitud, color = segmento)) +
geom_point(alpha = 0.5, size = 1) +
scale_color_manual(values = paleta_seg, name = "Segmento") +
coord_fixed(1.05) +
labs(x = "Longitud", y = "Latitud") +
theme_minimal(base_size = 12)Distribución geográfica de los segmentos de mercado
Los mapas dejan ver que el precio y el segmento no se distribuyen al azar en el espacio: hay agrupaciones geográficas claras -el segmento Premium, por ejemplo, se concentra en corredores específicos de la ciudad- que van en la misma línea de lo que ya mostraba el análisis de correspondencias.
La variabilidad del mercado analizado se explica, en buena parte, por dos dimensiones: el tamaño/valor de la propiedad y la relación entre estrato y número de habitaciones. Sobre esa base, el mercado se divide en 4 segmentos con perfiles bastante distintos en precio, área y estrato, que van desde el Premium de alto valor hasta el Económico compacto de alta rotación. También queda claro que la zona y el tipo de vivienda están asociados de forma significativa, y que el barrio agrega un nivel de detalle adicional dentro de cada zona. Por último, tanto el precio como los segmentos siguen un patrón espacial bastante marcado, visible en los mapas y coherente con el análisis de correspondencias, lo que confirma que la ubicación pesa mucho en el valor de una propiedad.
Con estos resultados, tiene sentido que la empresa maneje precios diferenciados por segmento en lugar de un precio único por zona, usando los perfiles descritos arriba como referencia. También conviene priorizar geográficamente: concentrar la captación de propiedades Premium en las zonas y barrios donde ya se agrupan, y usar el segmento Económico compacto para estrategias de volumen. Como Zona Oeste concentra apartamentos y Zona Oriente/Centro concentran casas, vale la pena ajustar el portafolio de captación según lo que realmente se mueve en cada zona. Y en general, conviene repetir este tipo de análisis cada cierto tiempo a medida que se actualice la base de datos, para detectar cambios en el mercado a tiempo.
| Apartamento | Casa | |
|---|---|---|
| Premium | 296 | 690 |
| Amplio de gama media | 1,550 | 574 |
| Estándar | 40 | 813 |
| Económico compacto | 2,345 | 409 |
| Zona Centro | Zona Norte | Zona Oeste | Zona Oriente | Zona Sur | |
|---|---|---|---|---|---|
| Premium | 2 | 104 | 263 | 1 | 616 |
| Amplio de gama media | 2 | 361 | 653 | 0 | 1,108 |
| Estándar | 38 | 181 | 47 | 93 | 494 |
| Económico compacto | 22 | 641 | 135 | 69 | 1,887 |
data.frame(Categoría = rownames(res.mca$var$contrib),
`Contribución Dim.1 (%)` = round(res.mca$var$contrib[,1],1),
`Contribución Dim.2 (%)` = round(res.mca$var$contrib[,2],1),
check.names = FALSE) %>%
arrange(desc(`Contribución Dim.1 (%)`)) %>%
tabla(caption = "Contribución de categorías a las dimensiones del ACM")| Categoría | Contribución Dim.1 (%) | Contribución Dim.2 (%) | |
|---|---|---|---|
| Zona Oeste | Zona Oeste | 33.0 | 4.3 |
| santa teresita | santa teresita | 19.0 | 4.1 |
| los cristales | los cristales | 11.3 | 2.3 |
| Zona Sur | Zona Sur | 11.2 | 9.4 |
| Casa | Casa | 6.5 | 2.7 |
| ciudad jardín | ciudad jardín | 4.2 | 1.8 |
| Apartamento | Apartamento | 4.1 | 1.7 |
| pance | pance | 2.8 | 1.8 |
| valle del lili | valle del lili | 2.2 | 8.4 |
| Zona Norte | Zona Norte | 1.2 | 30.9 |
| el caney | el caney | 1.1 | 1.1 |
| el ingenio | el ingenio | 0.9 | 1.2 |
| la flora | la flora | 0.9 | 15.1 |
| la hacienda | la hacienda | 0.7 | 1.0 |
| Zona Oriente | Zona Oriente | 0.5 | 2.3 |
| Zona Centro | Zona Centro | 0.2 | 0.8 |
| Otros | Otros | 0.2 | 3.8 |
| acopi | acopi | 0.1 | 7.4 |
El código de cada sección se puede ver desplegando los bloques
(“Code”) en la versión HTML del informe. Todo el documento se generó de
forma reproducible con R Markdown, directamente sobre los datos de
paqueteMODELOS.
## $R.version
## $R.version$platform
## [1] "x86_64-w64-mingw32"
##
## $R.version$arch
## [1] "x86_64"
##
## $R.version$os
## [1] "mingw32"
##
## $R.version$crt
## [1] "ucrt"
##
## $R.version$system
## [1] "x86_64, mingw32"
##
## $R.version$status
## [1] ""
##
## $R.version$major
## [1] "4"
##
## $R.version$minor
## [1] "5.2"
##
## $R.version$year
## [1] "2025"
##
## $R.version$month
## [1] "10"
##
## $R.version$day
## [1] "31"
##
## $R.version$`svn rev`
## [1] "88974"
##
## $R.version$language
## [1] "R"
##
## $R.version$version.string
## [1] "R version 4.5.2 (2025-10-31 ucrt)"
##
## $R.version$nickname
## [1] "[Not] Part in a Rumble"
##
##
## $platform
## [1] "x86_64-w64-mingw32/x64"
##
## $locale
## [1] "LC_COLLATE=Spanish_Colombia.utf8;LC_CTYPE=Spanish_Colombia.utf8;LC_MONETARY=Spanish_Colombia.utf8;LC_NUMERIC=C;LC_TIME=Spanish_Colombia.utf8"
Modelos Estadísticos para la Toma de Decisiones — Pontificia Universidad
Javeriana, Grupo B
Johan David Perdomo Campos