UNIVERSIDAD PONTIFICIA JAVERIANA CALI
Maestría en Ciencia de Datos
Actividad 1: Evaluación de la Oferta Inmobiliaria Urbana
Presentado por:
Dainer Orlando Cruz Chate
Modelos Estadísticos para la Toma de Decisiones
2026
La comprensión del mercado inmobiliario urbano constituye un elemento fundamental para la toma de decisiones estratégicas en empresas dedicadas a la compra, venta y valoración de bienes raíces. En un entorno caracterizado por una amplia diversidad de inmuebles, variaciones en los precios de oferta y múltiples factores físicos, espaciales y socioeconómicos que influyen en la formación del valor de las viviendas, resulta necesario aplicar metodologías analíticas que permitan transformar grandes volúmenes de datos en información útil para el apoyo a las decisiones empresariales. En este contexto, la estadística multivariada se ha consolidado como una herramienta fundamental para identificar patrones ocultos, reducir la complejidad de la información y facilitar la interpretación de fenómenos complejos mediante el análisis simultáneo de múltiples variables [1], [2].
La presente actividad se desarrolla a partir de una base de datos real correspondiente a viviendas ofertadas en el mercado inmobiliario urbano, con el propósito de analizar integralmente las características que influyen en el comportamiento de la oferta y los precios de los inmuebles. Este tipo de análisis cobra especial relevancia debido a que la valoración de una vivienda depende de factores diversos, tales como el área construida, el número de habitaciones, la ubicación geográfica, las características del entorno urbano y el estrato socioeconómico, entre otros aspectos que interactúan de manera simultánea y generan patrones difíciles de identificar mediante análisis univariados o bivariados tradicionales [3], [4].
Con el fin de abordar esta problemática, se emplean diferentes técnicas estadísticas multivariadas orientadas a reconocer las estructuras subyacentes de los datos y apoyar la toma de decisiones basada en evidencia. En primer lugar, el Análisis de Componentes Principales (ACP) permite reducir la dimensionalidad del conjunto de datos al transformar un gran número de variables correlacionadas en un conjunto reducido de componentes que conservan la mayor proporción posible de la variabilidad original. Esta técnica facilita la identificación de los factores más influyentes en la determinación de los precios y en la configuración de la oferta inmobiliaria [1], [5].
De manera complementaria, el Análisis de Conglomerados se utiliza para identificar grupos homogéneos de viviendas con características similares. La segmentación obtenida permite reconocer perfiles de inmuebles y zonas de mercado que comparten comportamientos comunes, proporcionando información valiosa para la formulación de estrategias comerciales, la identificación de nichos de mercado y la evaluación de oportunidades de inversión [2], [6].
Asimismo, el Análisis de Correspondencias constituye una herramienta adecuada para estudiar las relaciones existentes entre variables categóricas, tales como el tipo de vivienda, la zona urbana y el barrio. Esta metodología permite representar gráficamente las asociaciones entre categorías y facilita la comprensión de los patrones de comportamiento presentes en el mercado inmobiliario, aportando una visión complementaria al análisis cuantitativo de las variables numéricas [2], [7].
Adicionalmente, la visualización de datos desempeña un papel fundamental dentro del proceso analítico, ya que permite comunicar de manera clara y efectiva los resultados obtenidos. La utilización de gráficos multivariados, mapas temáticos y representaciones bidimensionales de componentes o conglomerados favorece la interpretación de los hallazgos y facilita la transferencia del conocimiento generado hacia los responsables de la toma de decisiones dentro de la organización [8].
En concordancia con los objetivos planteados, el presente informe reconoce los diferentes elementos que componen las técnicas estadísticas multivariadas empleadas, utiliza herramientas apropiadas para la solución de problemas reales asociados al mercado inmobiliario urbano y presenta los resultados siguiendo la estructura formal de un informe estadístico, incluyendo el análisis de resultados, conclusiones, recomendaciones y anexos correspondientes. De esta manera, se busca generar conocimiento útil que contribuya a mejorar los procesos de valoración, segmentación y gestión estratégica de la oferta inmobiliaria, fortaleciendo la capacidad de la empresa para competir en un mercado dinámico y altamente competitivo [4], [6].
En los últimos años, el mercado inmobiliario urbano se ha caracterizado por una dinámica cada vez más compleja, influenciada por factores económicos, sociales, demográficos y territoriales que afectan de manera directa el comportamiento de la oferta y la demanda de vivienda. La creciente disponibilidad de información proveniente de portales inmobiliarios, empresas del sector y plataformas digitales ha generado grandes volúmenes de datos que contienen información valiosa sobre las características físicas, económicas y geográficas de los inmuebles ofertados. Sin embargo, la existencia de estos datos no garantiza por sí sola una adecuada comprensión del mercado, razón por la cual resulta necesario emplear técnicas estadísticas que permitan transformar los datos en conocimiento útil para la toma de decisiones.
En este contexto, una empresa inmobiliaria líder en una gran ciudad dispone de una extensa base de datos con información relacionada con diferentes propiedades residenciales disponibles en el mercado. Esta información incluye variables asociadas al precio de oferta, área construida, ubicación, estrato socioeconómico, características físicas de las viviendas y otras variables relevantes para la valoración de inmuebles. No obstante, debido a la naturaleza multidimensional de estos datos, resulta difícil identificar patrones de comportamiento, relaciones entre variables y segmentos de mercado mediante análisis descriptivos tradicionales.
La necesidad de comprender de manera integral el comportamiento de la oferta inmobiliaria ha llevado a que las organizaciones del sector incorporen metodologías analíticas avanzadas que faciliten la identificación de factores asociados al valor de los inmuebles, la caracterización de segmentos homogéneos y el reconocimiento de oportunidades de negocio. En este sentido, las técnicas de análisis multivariado constituyen una alternativa adecuada para explorar simultáneamente múltiples variables y descubrir estructuras subyacentes que no son evidentes mediante métodos convencionales de análisis [1], [2].
Por lo anterior, este proyecto propone desarrollar un análisis holístico del mercado inmobiliario urbano utilizando herramientas estadísticas multivariadas como el Análisis de Componentes Principales (ACP), el Análisis de Conglomerados y el Análisis de Correspondencias. Estas técnicas permitirán reducir la complejidad de la información, identificar factores determinantes en la variación de los precios, segmentar las viviendas en grupos con características similares y analizar las asociaciones existentes entre variables categóricas relevantes para el sector inmobiliario. Los resultados obtenidos aportarán información estratégica para apoyar la toma de decisiones relacionadas con la compra, venta y valoración de propiedades en un entorno cada vez más competitivo y orientado al uso de datos.
La toma de decisiones en el sector inmobiliario exige cada vez mayores niveles de precisión y soporte analítico. Aspectos como la valoración adecuada de los inmuebles, la identificación de oportunidades de inversión, la segmentación de mercados y el diseño de estrategias comerciales dependen en gran medida de la capacidad de las organizaciones para interpretar correctamente la información disponible. En consecuencia, el análisis de datos se ha convertido en un elemento fundamental para fortalecer la competitividad empresarial y reducir la incertidumbre asociada a las decisiones de negocio.
La presente investigación se justifica desde una perspectiva metodológica, práctica y estratégica. Desde el punto de vista metodológico, permite aplicar técnicas de estadística multivariada ampliamente reconocidas en la literatura científica para analizar fenómenos complejos caracterizados por la interacción simultánea de múltiples variables. El uso de herramientas como el Análisis de Componentes Principales, el Análisis de Conglomerados y el Análisis de Correspondencias facilita la identificación de patrones ocultos y la generación de conocimiento a partir de grandes volúmenes de información [2], [5].
Desde una perspectiva práctica, el proyecto permitirá comprender los factores que influyen en los precios de oferta de las viviendas, identificar grupos homogéneos de inmuebles y establecer relaciones entre características relevantes del mercado. Esta información resulta particularmente útil para optimizar los procesos de valoración inmobiliaria, mejorar las estrategias comerciales y orientar las decisiones de inversión hacia segmentos con mayor potencial de rentabilidad.
Asimismo, el proyecto aporta valor estratégico a la organización al proporcionar una visión integral del mercado inmobiliario urbano. La identificación de segmentos de mercado, la comprensión del comportamiento de la oferta y la detección de patrones asociados a determinadas zonas o tipologías de vivienda permiten diseñar estrategias basadas en evidencia y reducir el riesgo derivado de decisiones fundamentadas únicamente en la experiencia o el juicio subjetivo.
Finalmente, este estudio contribuye al fortalecimiento de las competencias analíticas asociadas a la Ciencia de Datos y a los Modelos Estadísticos para la Toma de Decisiones, permitiendo aplicar conocimientos teóricos a una problemática real mediante el uso de herramientas estadísticas apropiadas. De esta manera, el proyecto cumple con los criterios académicos establecidos al reconocer los elementos fundamentales de las técnicas empleadas, aplicar métodos estadísticos adecuados para resolver un problema en contexto y presentar los resultados bajo la estructura formal de un informe estadístico con sus respectivos anexos.
Analizar integralmente la oferta inmobiliaria urbana mediante técnicas de estadística multivariada para identificar patrones, relaciones y segmentos de mercado que contribuyan a mejorar la toma de decisiones estratégicas de la empresa inmobiliaria.
El presente proyecto tiene como alcance el análisis integral de una base de datos correspondiente a la oferta inmobiliaria urbana de una gran ciudad, con el propósito de identificar patrones, relaciones y segmentaciones relevantes que contribuyan a mejorar los procesos de compra, venta y valoración de propiedades por parte de una empresa inmobiliaria.
El estudio se desarrollará mediante la aplicación de técnicas de estadística multivariada sobre la información disponible de las viviendas ofertadas, considerando variables tanto cuantitativas como cualitativas relacionadas con las características físicas, económicas y geográficas de los inmuebles.
Alcance analítico.
El proyecto contempla las siguientes actividades:
1. Comprensión y exploración de los datos.
2. Preparación de la información.
3. Análisis de Componentes Principales (ACP).
4. Análisis de Conglomerados.
5. Análisis de Correspondencias.
6. Visualización de resultados.
7. Interpretación y formulación de recomendaciones.
Alcance geográfico.
El análisis se limitará a las viviendas urbanas contenidas en la base de datos suministrada para el caso de estudio en Cali. Los resultados serán válidos para el contexto y período representado en dicha información.
Alcance temporal.
El proyecto comprende únicamente el análisis de la información disponible en la base de datos entregada. No contempla la actualización en tiempo real de los datos ni la construcción de modelos predictivos futuros basados en nuevas observaciones.
Exclusiones del proyecto.
Las siguientes actividades están fuera del alcance del estudio:
Desarrollo de modelos de predicción de precios mediante Machine Learning. Implementación de sistemas transaccionales para la empresa. Recolección de nuevos datos en campo. Valoración individual de inmuebles específicos. Estudios financieros, jurídicos o tributarios asociados a las propiedades. Implementación de plataformas tecnológicas o sistemas de información.
El proyecto se desarrollará bajo un enfoque cuantitativo, exploratorio y descriptivo, apoyado en técnicas de análisis estadístico multivariado. La metodología busca transformar los datos disponibles en información útil para comprender el comportamiento del mercado inmobiliario urbano y facilitar la toma de decisiones estratégicas relacionadas con la compra, venta y valoración de propiedades.
La metodología propuesta se compone de siete fases secuenciales que permiten garantizar la calidad de los datos, la rigurosidad del análisis y la adecuada interpretación de los resultados:
Actividades:
| Componente | Descripcion | Finalidad |
|---|---|---|
| Objetivo | Identificar la estructura, calidad y caracteristicas generales de la informacion disponible. | Comprender la estructura general de la base de datos y establecer su estado inicial. |
| Inventario de variables |
Clasificacion de variables cuantitativas. Clasificacion de variables cualitativas. Identificacion de la variable principal de interes (precio). |
Identificar las variables disponibles y definir su papel dentro del analisis. |
| Analisis descriptivo |
Variables numericas: media, mediana, desviacion estandar, coeficiente de
variacion, valores minimos y maximos. Variables categoricas: frecuencias absolutas, frecuencias relativas y tablas de contingencia. |
Caracterizar estadisticamente la informacion disponible. |
| Evaluacion de calidad de datos |
Identificacion de valores faltantes. Deteccion de registros duplicados. Deteccion de datos atipicos. Verificacion de consistencia de la informacion. |
Determinar el nivel de confiabilidad y preparacion de los datos para analisis posteriores. |
| Herramientas |
Tablas descriptivas. Histogramas. Diagramas de caja y bigotes. Graficos de barras. |
Apoyar la exploracion visual y estadistica de la informacion. |
| Producto esperado | Resumen de la exploracion de datos y diagnostico de calidad. | Documentar hallazgos y establecer lineamientos para las fases posteriores. |
Fuente: Elaboración Propia.
| Componente | Descripcion | Finalidad |
|---|---|---|
| Objetivo | Construir una base de datos confiable y adecuada para la aplicacion de tecnicas multivariadas. | Garantizar la calidad y consistencia de los datos antes de aplicar tecnicas multivariadas. |
| Tratamiento de datos faltantes |
Imputacion estadistica. Eliminacion de registros cuando sea necesario. Validacion de completitud de la informacion. |
Reducir sesgos derivados de informacion incompleta y mejorar la integridad de la base de datos. |
| Tratamiento de valores atipicos |
Identificacion mediante boxplots. Evaluacion del impacto sobre los resultados. Decision de correccion o conservacion de los registros. |
Controlar observaciones extremas que puedan afectar los resultados de los analisis estadisticos. |
| Estandarizacion de variables | Estandarizacion mediante puntuaciones Z para variables en diferentes escalas, tales como area, precio, habitaciones y banos. | Hacer comparables las variables y evitar que las diferencias de escala dominen los resultados. |
| Producto esperado | Base de datos depurada y lista para el analisis multivariado. | Disponer de una base de datos adecuada para ACP, Analisis de Conglomerados y Analisis de Correspondencias. |
Fuente: Elaboración Propia.
| Componente | Descripcion | Finalidad |
|---|---|---|
| Objetivo | Reducir la dimensionalidad del conjunto de datos e identificar los factores que explican la mayor proporcion de la variabilidad observada. | Sintetizar la informacion y reducir la complejidad del conjunto de datos sin perder una proporcion significativa de la variabilidad. |
| Verificacion de aplicabilidad |
Analisis de la matriz de correlaciones. Aplicacion de la prueba KMO. Aplicacion de la prueba de esfericidad de Bartlett. |
Verificar que los datos cumplen los supuestos necesarios para la aplicacion del Analisis de Componentes Principales. |
| Construccion del ACP |
Obtencion de autovalores. Determinacion del numero optimo de componentes principales. Calculo de la varianza explicada acumulada. |
Obtener una representacion reducida de los datos mediante componentes principales estadisticamente relevantes. |
| Interpretacion |
Identificacion de las variables mas influyentes. Identificacion de factores asociados al precio. Identificacion de factores asociados a la oferta inmobiliaria. |
Comprender los factores subyacentes que explican la estructura de la oferta inmobiliaria y su relacion con el precio. |
| Criterio de exito | Los componentes retenidos deberan explicar al menos el 70% de la variabilidad total. | Garantizar que la reduccion dimensional conserve una capacidad explicativa suficiente para el analisis posterior. |
| Productos esperados |
Tabla de componentes principales. Grafico Scree Plot. Plano factorial. Interpretacion de componentes. |
Documentar y visualizar los resultados obtenidos para facilitar su interpretacion y comunicacion. |
Fuente: Elaboración Propia.
Una vez identificadas las principales dimensiones que explican la variabilidad del mercado inmobiliario mediante el Análisis de Componentes Principales (ACP), se procede a la aplicación del Análisis de Conglomerados sobre la base vivienda_limpia. Esta técnica permitió agrupar las viviendas según sus características comunes, facilitando la identificación de perfiles homogéneos de inmuebles. De esta manera, se obtuvo una visión más estructurada del comportamiento de la oferta inmobiliaria y de los patrones presentes en los datos analizados.
| Componente | Descripcion | Finalidad |
|---|---|---|
| Objetivo | Identificar grupos homogeneos de viviendas con caracteristicas similares. | Identificar segmentos de viviendas con patrones y caracteristicas comunes dentro del mercado inmobiliario. |
| Seleccion de variables |
Utilizacion de variables originales relevantes. Incorporacion de los componentes principales obtenidos mediante ACP. |
Seleccionar la informacion mas representativa para mejorar la calidad y estabilidad de la segmentacion. |
| Agrupamiento |
Aplicacion de Clustering Jerarquico. Aplicacion del metodo de Ward. Aplicacion del algoritmo K-Means. |
Construir agrupaciones estadisticamente coherentes que permitan diferenciar perfiles de vivienda. |
| Determinacion del numero optimo de grupos |
Evaluacion mediante dendrograma. Aplicacion del metodo del codo. Analisis del indice de Silhouette. |
Determinar el numero de segmentos que mejor representa la estructura del mercado analizado. |
| Caracterizacion de segmentos |
Descripcion de los grupos segun precio. Descripcion de los grupos segun area. Descripcion de los grupos segun ubicacion. Descripcion de los grupos segun estrato. Descripcion de los grupos segun tipo de vivienda. |
Interpretar las caracteristicas distintivas de cada segmento para facilitar su analisis y comparacion. |
| Producto esperado | Segmentacion del mercado inmobiliario con grupos claramente definidos. | Obtener una segmentacion util para apoyar la toma de decisiones estrategicas en el mercado inmobiliario. |
Fuente: Elaboración Propia.
| Componente | Descripcion | Finalidad |
|---|---|---|
| Objetivo | Estudiar las relaciones existentes entre variables categoricas asociadas al mercado inmobiliario. | Comprender la estructura de asociacion existente entre las variables categoricas del mercado inmobiliario. |
| Construccion de tablas de contingencia |
Construccion de tablas de contingencia entre tipo de vivienda y
zona. Construccion de tablas de contingencia entre zona y estrato. Construccion de tablas de contingencia entre barrio y tipo de vivienda. |
Identificar patrones de relacion entre variables categoricas relevantes para la caracterizacion de la oferta inmobiliaria. |
| Aplicacion del analisis de correspondencias |
Obtencion de dimensiones principales. Obtencion de coordenadas de categorias. Identificacion de asociaciones relevantes entre las categorias analizadas. |
Reducir la complejidad de las relaciones observadas y destacar las asociaciones mas representativas. |
| Interpretacion grafica | Identificacion e interpretacion de asociaciones entre categorias proximas en el plano factorial. | Facilitar la interpretacion visual de los vinculos existentes entre categorias y detectar agrupamientos o proximidades relevantes. |
| Producto esperado | Mapa perceptual de relaciones entre categorias. | Generar evidencia grafica y analitica que permita interpretar las relaciones entre categorias del mercado inmobiliario. |
Fuente: Elaboración Propia.
| Componente | Descripcion | Finalidad |
|---|---|---|
| Objetivo | Consolidar los hallazgos obtenidos y generar informacion util para la toma de decisiones. | Transformar los resultados estadisticos en conocimiento util para apoyar la toma de decisiones. |
| Sintesis de hallazgos |
Integracion de resultados provenientes del Analisis de Componentes
Principales (ACP). Integracion de resultados del Analisis de Conglomerados. Integracion de resultados del Analisis de Correspondencias. |
Integrar la evidencia generada por las tecnicas multivariadas para obtener una vision global del mercado inmobiliario. |
| Identificacion de oportunidades |
Identificacion de segmentos de alto valor. Identificacion de mercados emergentes. Identificacion de factores asociados a mayores precios. Identificacion de caracteristicas diferenciales de los inmuebles. |
Detectar oportunidades de negocio y factores clave asociados al comportamiento de la oferta inmobiliaria. |
| Formulacion de recomendaciones |
Formulacion de recomendaciones orientadas a la compra de
propiedades. Formulacion de estrategias comerciales. Apoyo a la valoracion de inmuebles. Mejoramiento de la segmentacion del mercado. Orientacion para decisiones de inversion inmobiliaria. |
Proponer acciones concretas y estrategias basadas en la evidencia obtenida durante el analisis. |
| Producto esperado | Informe ejecutivo con conclusiones y recomendaciones estrategicas. | Presentar de forma clara los hallazgos, conclusiones y recomendaciones derivadas del estudio. |
Para evaluar el cumplimiento del proyecto se establecen los siguientes criterios:
| Criterio | Objetivo | Umbral |
|---|---|---|
| Reduccion de dimensionalidad | Aplicar ACP para sintetizar la informacion y reducir la dimensionalidad. | Varianza explicada acumulada >= 70%. |
| Identificacion de segmentos | Aplicar Analisis de Conglomerados para identificar grupos homogeneos. |
Conglomerados interpretables. Diferencias estadisticas evidentes entre grupos. |
| Identificacion de relaciones categoricas | Aplicar Analisis de Correspondencias para evaluar asociaciones entre variables categoricas. |
Asociaciones claras entre tipo de vivienda, zona y
barrio. Representacion grafica interpretable. |
| Calidad de la visualizacion | Generar visualizaciones que comuniquen claramente los resultados. |
Graficos comprensibles y correctamente etiquetados. Identificacion visual de patrones relevantes. |
| Valor para la toma de decisiones | Generar hallazgos y recomendaciones utiles para la toma de decisiones. |
Identificacion de oportunidades de mercado. Identificacion de segmentos estrategicos. Identificacion de factores asociados a mayores precios. |
Esta fase se orienta a comprender la problemática planteada por la empresa inmobiliaria y los objetivos analíticos del estudio. A partir de la identificación de las necesidades de información y las variables disponibles, se establece el marco que guiará la aplicación de técnicas de análisis multivariado para apoyar la toma de decisiones estratégicas en el mercado de vivienda urbana.
La empresa inmobiliaria dispone de una base de datos con información detallada de viviendas urbanas y requiere comprender cómo interactúan las diferentes características de los inmuebles para mejorar los procesos de compra, venta, comercialización y valoración de propiedades.
Desde una perspectiva estadística, el problema consiste en identificar las variables que explican el comportamiento de los precios de oferta, detectar patrones de asociación entre las características de las viviendas y segmentar el mercado en grupos homogéneos que permitan apoyar la toma de decisiones estratégicas.
Dado que la base de datos contiene múltiples variables cuantitativas y cualitativas relacionadas con los inmuebles, se requiere aplicar técnicas de análisis multivariado que permitan examinar simultáneamente todas las dimensiones del fenómeno estudiado.
¿Cuáles son los factores que influyen en los precios de las viviendas urbanas y cómo pueden identificarse segmentos homogéneos de propiedades mediante técnicas de análisis multivariado para apoyar la toma de decisiones estratégicas de una empresa inmobiliaria?
De forma complementaria, pueden plantearse las siguientes preguntas específicas:
¿Qué variables explican la mayor variabilidad de los precios de las viviendas? ¿Existen grupos de propiedades con características similares? ¿Qué relación existe entre variables categóricas como tipo de vivienda, zona y barrio? ¿Qué características distinguen a los segmentos más atractivos del mercado? ¿Cómo pueden utilizarse los hallazgos para optimizar la compra, venta y valoración de inmuebles?
En esta fase se desarrolla el proceso de comprensión y exploración inicial de la base de datos vivienda, con el propósito de identificar sus principales características, estructura, calidad de los datos y posibles limitaciones para el análisis posterior. Con el fin de mantener la fluidez del documento y evitar la inclusión de extensos bloques de programación dentro del cuerpo principal del informe, el código completo utilizado para la ejecución de las actividades correspondientes a las fases 2, 3 y 4 se presenta en el Anexo 1, garantizando la trazabilidad, reproducibilidad y transparencia del proceso analítico realizado.
La base de datos vivienda utilizada en el presente estudio fue obtenida a partir del repositorio público disponible en GitHub correspondiente al paquete MODELOS.
Este repositorio proporciona los datos empleados con fines académicos y de aprendizaje en análisis estadístico y ciencia de datos. La base contiene información relacionada con la oferta inmobiliaria urbana de Cali y constituye la fuente principal para la aplicación de las técnicas multivariadas desarrolladas en este proyecto.
Las actividades desarrolladas para lograr su obtención fueron:
| Variable | Descripcion |
|---|---|
| id | Identificador del registro |
| zona | Zona geografica de la vivienda |
| piso | Piso donde se ubica el inmueble |
| estrato | Estrato socioeconomico |
| preciom | Precio de oferta |
| areaconst | Area construida |
| parqueaderos | Numero de parqueaderos |
| banios | Numero de banios |
| habitaciones | Numero de habitaciones |
| tipo | Tipo de vivienda |
| barrio | Barrio de ubicacion |
| longitud | Coordenada longitud |
| latitud | Coordenada latitud |
Fuente: Elaboración Propia.
El proceso de inventario y clasificación de las variables se apoyó en el diccionario de datos de la base vivienda (ver Anexo 2), con el propósito de validar tanto la definición de cada variable como las características de los datos asociados. Este ejercicio permitió identificar su naturaleza, estructura y nivel de medición, proporcionando una comprensión integral del conjunto de datos y sirviendo como base para los análisis posteriores. La clasificación obtenida se presenta a continuación.
| Variable | Registros | Completitud | Naturaleza | Observacion |
|---|---|---|---|---|
| id | 8319 | 99.96 | Cuantitativa | Identificador unico |
| zona | 8319 | 99.96 | Cualitativa | Zona geografica |
| piso | 5684 | 68.30 | Cuantitativa | Piso de la vivienda |
| estrato | 8319 | 99.96 | Cuantitativa | Estrato socioeconomico |
| preciom | 8320 | 99.98 | Cuantitativa | Variable de interes principal |
| areaconst | 8319 | 99.96 | Cuantitativa | Area construida |
| parqueaderos | 6717 | 80.71 | Cuantitativa | Numero de parqueaderos |
| banios | 8319 | 99.96 | Cuantitativa | Numero de banios |
| habitaciones | 8319 | 99.96 | Cuantitativa | Numero de habitaciones |
| tipo | 8319 | 99.96 | Cualitativa | Tipo de vivienda |
| barrio | 8319 | 99.96 | Cualitativa | Barrio |
| longitud | 8319 | 99.96 | Cuantitativa | Coordenada longitud |
| latitud | 8319 | 99.96 | Cuantitativa | Coordenada latitud |
Fuente: Elaboración Propia.
| Variable | Media | Mediana | Desv_Estandar | Coef_Variacion | Minimo | Maximo |
|---|---|---|---|---|---|---|
| id | 4160.00 | 4160.00 | 2401.63 | 57.73 | 1.00 | 8319.00 |
| estrato | 4.63 | 5.00 | 1.03 | 22.21 | 3.00 | 6.00 |
| preciom | 433.89 | 330.00 | 328.65 | 75.74 | 58.00 | 1999.00 |
| areaconst | 174.93 | 123.00 | 142.96 | 81.72 | 30.00 | 1745.00 |
| parqueaderos | 1.84 | 2.00 | 1.12 | 61.30 | 1.00 | 10.00 |
| banios | 3.11 | 3.00 | 1.43 | 45.90 | 0.00 | 10.00 |
| habitaciones | 3.61 | 3.00 | 1.46 | 40.48 | 0.00 | 10.00 |
| longitud | -76.53 | -76.53 | 0.02 | -0.02 | -76.59 | -76.46 |
| latitud | 3.42 | 3.42 | 0.04 | 1.25 | 3.33 | 3.50 |
Fuente: Elaboración Propia.
Variables categóricas: frecuencias absolutas y relativas.
|
Variable |
Categoria |
Frecuencia_Absoluta |
Frecuencia_Relativa |
|---|---|---|---|
|
zona |
Zona Centro |
124 |
1.49 |
|
zona |
Zona Norte |
1920 |
23.08 |
|
zona |
Zona Oeste |
1198 |
14.40 |
|
zona |
Zona Oriente |
351 |
4.22 |
|
zona |
Zona Sur |
4726 |
56.81 |
|
tipo |
Apartamento |
5100 |
61.31 |
|
tipo |
Casa |
3219 |
38.69 |
|
barrio |
20 de julio |
3 |
0.04 |
|
barrio |
3 de julio |
1 |
0.01 |
|
barrio |
acopi |
158 |
1.90 |
|
barrio |
agua blanca |
1 |
0.01 |
|
barrio |
aguablanca |
2 |
0.02 |
|
barrio |
aguacatal |
109 |
1.31 |
|
barrio |
alameda |
16 |
0.19 |
|
barrio |
alameda del rio |
1 |
0.01 |
|
barrio |
alameda del río |
2 |
0.02 |
|
barrio |
alamos |
14 |
0.17 |
|
barrio |
alborada |
1 |
0.01 |
|
barrio |
alcazares |
2 |
0.02 |
|
barrio |
alférez real |
5 |
0.06 |
|
barrio |
alferez real |
2 |
0.02 |
|
barrio |
alfonso lopez |
1 |
0.01 |
|
barrio |
alfonso lópez |
21 |
0.25 |
|
barrio |
alfonso lópez i |
1 |
0.01 |
|
barrio |
alto jordán |
1 |
0.01 |
|
barrio |
altos de guadalupe |
4 |
0.05 |
|
barrio |
altos de menga |
3 |
0.04 |
|
barrio |
altos de santa |
1 |
0.01 |
|
barrio |
antonio nariño |
2 |
0.02 |
|
barrio |
aranjuez |
15 |
0.18 |
|
barrio |
arboleda |
5 |
0.06 |
|
barrio |
arboleda campestre candelaria |
1 |
0.01 |
|
barrio |
arboledas |
38 |
0.46 |
|
barrio |
atanasio girardot |
9 |
0.11 |
|
barrio |
autopista sur |
1 |
0.01 |
|
barrio |
bajo aguacatal |
1 |
0.01 |
|
barrio |
barranquilla |
6 |
0.07 |
|
barrio |
barrio 7de agosto |
1 |
0.01 |
|
barrio |
barrio el recuerdo |
1 |
0.01 |
|
barrio |
barrio eucarístico |
1 |
0.01 |
|
barrio |
barrio obrero |
1 |
0.01 |
|
barrio |
barrio tranquilo y |
1 |
0.01 |
|
barrio |
base aérea |
2 |
0.02 |
|
barrio |
belalcazar |
3 |
0.04 |
|
barrio |
Belalcazar |
1 |
0.01 |
|
barrio |
belisario caicedo |
2 |
0.02 |
|
barrio |
bella suiza |
18 |
0.22 |
|
barrio |
bella suiza alta |
4 |
0.05 |
|
barrio |
bellavista |
43 |
0.52 |
|
barrio |
benjamín herrera |
8 |
0.10 |
|
barrio |
berlin |
1 |
0.01 |
|
barrio |
bloques del limonar |
1 |
0.01 |
|
barrio |
bochalema |
33 |
0.40 |
|
barrio |
bolivariano |
1 |
0.01 |
|
barrio |
bosques de alboleda |
1 |
0.01 |
|
barrio |
bosques del limonar |
21 |
0.25 |
|
barrio |
boyacá |
1 |
0.01 |
|
barrio |
bretaña |
16 |
0.19 |
|
barrio |
brisas de guadalupe |
1 |
0.01 |
|
barrio |
brisas de los |
81 |
0.97 |
|
barrio |
Brisas De Los |
1 |
0.01 |
|
barrio |
brisas del guabito |
1 |
0.01 |
|
barrio |
brisas del limonar |
1 |
0.01 |
|
barrio |
Bueno Madrid |
1 |
0.01 |
|
barrio |
buenos aires |
7 |
0.08 |
|
barrio |
caldas |
1 |
0.01 |
|
barrio |
Cali |
37 |
0.44 |
|
barrio |
cali bella |
1 |
0.01 |
|
barrio |
cali canto |
1 |
0.01 |
|
barrio |
calibella |
1 |
0.01 |
|
barrio |
calicanto |
8 |
0.10 |
|
barrio |
calicanto viii |
1 |
0.01 |
|
barrio |
calima |
6 |
0.07 |
|
barrio |
calimio norte |
5 |
0.06 |
|
barrio |
calipso |
11 |
0.13 |
|
barrio |
cambulos |
3 |
0.04 |
|
barrio |
camino real |
35 |
0.42 |
|
barrio |
Camino Real |
1 |
0.01 |
|
barrio |
campestre |
1 |
0.01 |
|
barrio |
caney |
88 |
1.06 |
|
barrio |
caney especial |
5 |
0.06 |
|
barrio |
cañasgordas |
7 |
0.08 |
|
barrio |
cañaveralejo |
12 |
0.14 |
|
barrio |
cañaverales |
21 |
0.25 |
|
barrio |
cañaverales los samanes |
1 |
0.01 |
|
barrio |
capri |
56 |
0.67 |
|
barrio |
cascajal |
1 |
0.01 |
|
barrio |
cataya real |
1 |
0.01 |
|
barrio |
ceibas |
1 |
0.01 |
|
barrio |
centelsa |
1 |
0.01 |
|
barrio |
centenario |
15 |
0.18 |
|
barrio |
Centenario |
1 |
0.01 |
|
barrio |
centro |
4 |
0.05 |
|
barrio |
cerro cristales |
22 |
0.26 |
|
barrio |
cerros de guadalupe |
1 |
0.01 |
|
barrio |
champagnat |
14 |
0.17 |
|
barrio |
chapinero |
7 |
0.08 |
|
barrio |
chiminangos |
17 |
0.20 |
|
barrio |
Chiminangos |
1 |
0.01 |
|
barrio |
chiminangos 1 etapa |
1 |
0.01 |
|
barrio |
chiminangos 2 etapa |
2 |
0.02 |
|
barrio |
chipichape |
30 |
0.36 |
|
barrio |
ciudad 2000 |
95 |
1.14 |
|
barrio |
Ciudad 2000 |
1 |
0.01 |
|
barrio |
ciudad antejardin |
1 |
0.01 |
|
barrio |
ciudad bochalema |
48 |
0.58 |
|
barrio |
ciudad capri |
13 |
0.16 |
|
barrio |
ciudad cordoba |
20 |
0.24 |
|
barrio |
ciudad córdoba |
15 |
0.18 |
|
barrio |
ciudad córdoba reservado |
1 |
0.01 |
|
barrio |
ciudad country |
1 |
0.01 |
|
barrio |
ciudad del campo |
1 |
0.01 |
|
barrio |
ciudad jardin |
22 |
0.26 |
|
barrio |
ciudad jardín |
516 |
6.20 |
|
barrio |
Ciudad Jardín |
2 |
0.02 |
|
barrio |
ciudad jardin pance |
1 |
0.01 |
|
barrio |
ciudad los alamos |
1 |
0.01 |
|
barrio |
ciudad los álamos |
25 |
0.30 |
|
barrio |
ciudad meléndez |
1 |
0.01 |
|
barrio |
ciudad melendez |
1 |
0.01 |
|
barrio |
ciudad modelo |
7 |
0.08 |
|
barrio |
ciudad pacifica |
2 |
0.02 |
|
barrio |
Ciudad Pacifica |
1 |
0.01 |
|
barrio |
ciudad real |
3 |
0.04 |
|
barrio |
ciudad talanga |
1 |
0.01 |
|
barrio |
ciudad universitaria |
1 |
0.01 |
|
barrio |
ciudadela comfandi |
17 |
0.20 |
|
barrio |
ciudadela del río |
1 |
0.01 |
|
barrio |
ciudadela melendez |
1 |
0.01 |
|
barrio |
ciudadela paso ancho |
1 |
0.01 |
|
barrio |
ciudadela pasoancho |
21 |
0.25 |
|
barrio |
colinas de menga |
3 |
0.04 |
|
barrio |
colinas del bosque |
1 |
0.01 |
|
barrio |
colinas del sur |
8 |
0.10 |
|
barrio |
colon |
1 |
0.01 |
|
barrio |
colseguros |
44 |
0.53 |
|
barrio |
colseguros andes |
4 |
0.05 |
|
barrio |
Colseguros Andes |
1 |
0.01 |
|
barrio |
comfenalco |
1 |
0.01 |
|
barrio |
compartir |
1 |
0.01 |
|
barrio |
conjunto gibraltar |
1 |
0.01 |
|
barrio |
cristales |
83 |
1.00 |
|
barrio |
cristobal colón |
14 |
0.17 |
|
barrio |
cristóbal colón |
2 |
0.02 |
|
barrio |
cuarto de legua |
44 |
0.53 |
|
barrio |
departamental |
29 |
0.35 |
|
barrio |
ed benjamin herrera |
1 |
0.01 |
|
barrio |
el bosque |
49 |
0.59 |
|
barrio |
El Bosque |
1 |
0.01 |
|
barrio |
el caney |
208 |
2.50 |
|
barrio |
El Caney |
1 |
0.01 |
|
barrio |
el castillo |
6 |
0.07 |
|
barrio |
el cedro |
8 |
0.10 |
|
barrio |
el diamante |
2 |
0.02 |
|
barrio |
el dorado |
6 |
0.07 |
|
barrio |
el gran limonar |
8 |
0.10 |
|
barrio |
el guabal |
19 |
0.23 |
|
barrio |
el guabito |
1 |
0.01 |
|
barrio |
el ingenio |
202 |
2.43 |
|
barrio |
El Ingenio |
1 |
0.01 |
|
barrio |
el ingenio 3 |
1 |
0.01 |
|
barrio |
el ingenio i |
19 |
0.23 |
|
barrio |
el ingenio ii |
21 |
0.25 |
|
barrio |
el ingenio iii |
20 |
0.24 |
|
barrio |
el jardín |
15 |
0.18 |
|
barrio |
el jordán |
1 |
0.01 |
|
barrio |
el lido |
59 |
0.71 |
|
barrio |
el limonar |
135 |
1.62 |
|
barrio |
el nacional |
1 |
0.01 |
|
barrio |
el paraíso |
3 |
0.04 |
|
barrio |
el peñon |
60 |
0.72 |
|
barrio |
el prado |
2 |
0.02 |
|
barrio |
el refugio |
120 |
1.44 |
|
barrio |
el rodeo |
1 |
0.01 |
|
barrio |
el sena |
1 |
0.01 |
|
barrio |
el trébol |
5 |
0.06 |
|
barrio |
el troncal |
19 |
0.23 |
|
barrio |
el vallado |
1 |
0.01 |
|
barrio |
eucarístico |
2 |
0.02 |
|
barrio |
evaristo garcía |
2 |
0.02 |
|
barrio |
farrallones de pance |
1 |
0.01 |
|
barrio |
fenalco kennedy |
1 |
0.01 |
|
barrio |
fepicol |
1 |
0.01 |
|
barrio |
flora |
1 |
0.01 |
|
barrio |
flora industrial |
16 |
0.19 |
|
barrio |
floralia |
6 |
0.07 |
|
barrio |
fonaviemcali |
1 |
0.01 |
|
barrio |
francisco eladio ramirez |
1 |
0.01 |
|
barrio |
fuentes de la |
1 |
0.01 |
|
barrio |
gaitan |
1 |
0.01 |
|
barrio |
gran limonar |
24 |
0.29 |
|
barrio |
granada |
15 |
0.18 |
|
barrio |
guadalupe |
21 |
0.25 |
|
barrio |
guadalupe alto |
1 |
0.01 |
|
barrio |
guaduales |
2 |
0.02 |
|
barrio |
guayaquil |
16 |
0.19 |
|
barrio |
hacienda alferez real |
1 |
0.01 |
|
barrio |
ingenio |
1 |
0.01 |
|
barrio |
ingenio i |
1 |
0.01 |
|
barrio |
ingenio ii |
1 |
0.01 |
|
barrio |
jamundi |
4 |
0.05 |
|
barrio |
jamundi alfaguara |
1 |
0.01 |
|
barrio |
jorge eliecer gaitán |
1 |
0.01 |
|
barrio |
jorge isaacs |
1 |
0.01 |
|
barrio |
jose manuel marroquín |
1 |
0.01 |
|
barrio |
juanamb√∫ |
53 |
0.64 |
|
barrio |
juanambu |
2 |
0.02 |
|
barrio |
junin |
18 |
0.22 |
|
barrio |
junín |
6 |
0.07 |
|
barrio |
la alborada |
5 |
0.06 |
|
barrio |
la alianza |
5 |
0.06 |
|
barrio |
la arboleda |
18 |
0.22 |
|
barrio |
la base |
15 |
0.18 |
|
barrio |
la buitrera |
3 |
0.04 |
|
barrio |
la campiña |
13 |
0.16 |
|
barrio |
la cascada |
7 |
0.08 |
|
barrio |
la ceibas |
1 |
0.01 |
|
barrio |
la esmeralda |
1 |
0.01 |
|
barrio |
la flora |
366 |
4.40 |
|
barrio |
La Flora |
2 |
0.02 |
|
barrio |
la floresta |
18 |
0.22 |
|
barrio |
la fortaleza |
4 |
0.05 |
|
barrio |
la gran colombia |
1 |
0.01 |
|
barrio |
la hacienda |
164 |
1.97 |
|
barrio |
La Hacienda |
2 |
0.02 |
|
barrio |
la independencia |
12 |
0.14 |
|
barrio |
la libertad |
2 |
0.02 |
|
barrio |
la luisa |
1 |
0.01 |
|
barrio |
la merced |
26 |
0.31 |
|
barrio |
la morada |
1 |
0.01 |
|
barrio |
la nueva base |
8 |
0.10 |
|
barrio |
la playa |
1 |
0.01 |
|
barrio |
la portada al |
1 |
0.01 |
|
barrio |
la primavera |
1 |
0.01 |
|
barrio |
la reforma |
1 |
0.01 |
|
barrio |
la rivera |
11 |
0.13 |
|
barrio |
la rivera i |
2 |
0.02 |
|
barrio |
la rivera ii |
2 |
0.02 |
|
barrio |
la riverita |
1 |
0.01 |
|
barrio |
la riviera |
1 |
0.01 |
|
barrio |
la selva |
11 |
0.13 |
|
barrio |
la villa del |
1 |
0.01 |
|
barrio |
laflora |
1 |
0.01 |
|
barrio |
lares de comfenalco |
1 |
0.01 |
|
barrio |
las acacias |
12 |
0.14 |
|
barrio |
las américas |
3 |
0.04 |
|
barrio |
las camelias |
1 |
0.01 |
|
barrio |
las ceibas |
23 |
0.28 |
|
barrio |
las delicias |
5 |
0.06 |
|
barrio |
las granjas |
10 |
0.12 |
|
barrio |
las quintas de |
1 |
0.01 |
|
barrio |
las vegas |
1 |
0.01 |
|
barrio |
las vegas de |
1 |
0.01 |
|
barrio |
libertadores |
3 |
0.04 |
|
barrio |
los alamos |
1 |
0.01 |
|
barrio |
los alcazares |
17 |
0.20 |
|
barrio |
los alcázares |
5 |
0.06 |
|
barrio |
los andes |
21 |
0.25 |
|
barrio |
los cambulos |
25 |
0.30 |
|
barrio |
los cámbulos |
6 |
0.07 |
|
barrio |
los cristales |
154 |
1.85 |
|
barrio |
los cristales club |
1 |
0.01 |
|
barrio |
los farallones |
4 |
0.05 |
|
barrio |
los guaduales |
25 |
0.30 |
|
barrio |
Los Guaduales |
1 |
0.01 |
|
barrio |
los guayacanes |
3 |
0.04 |
|
barrio |
los jockeys |
1 |
0.01 |
|
barrio |
los libertadores |
4 |
0.05 |
|
barrio |
los parques barranquilla |
6 |
0.07 |
|
barrio |
los robles |
1 |
0.01 |
|
barrio |
lourdes |
2 |
0.02 |
|
barrio |
mamellan |
1 |
0.01 |
|
barrio |
manzanares |
5 |
0.06 |
|
barrio |
mariano ramos |
1 |
0.01 |
|
barrio |
marroquín iii |
1 |
0.01 |
|
barrio |
mayapan las vegas |
46 |
0.55 |
|
barrio |
meléndez |
23 |
0.28 |
|
barrio |
melendez |
52 |
0.63 |
|
barrio |
menga |
23 |
0.28 |
|
barrio |
metropolitano del norte |
21 |
0.25 |
|
barrio |
miradol del aguacatal |
1 |
0.01 |
|
barrio |
miraflores |
25 |
0.30 |
|
barrio |
Miraflores |
1 |
0.01 |
|
barrio |
morichal de comfandi |
3 |
0.04 |
|
barrio |
multicentro |
27 |
0.32 |
|
barrio |
municipal |
3 |
0.04 |
|
barrio |
napoles |
2 |
0.02 |
|
barrio |
nápoles |
29 |
0.35 |
|
barrio |
normandia |
5 |
0.06 |
|
barrio |
normandía |
154 |
1.85 |
|
barrio |
normandía west point |
1 |
0.01 |
|
barrio |
norte |
9 |
0.11 |
|
barrio |
norte la flora |
1 |
0.01 |
|
barrio |
nueva base |
1 |
0.01 |
|
barrio |
nueva floresta |
15 |
0.18 |
|
barrio |
nueva tequendama |
73 |
0.88 |
|
barrio |
oasis de comfandi |
6 |
0.07 |
|
barrio |
oasis de pasoancho |
1 |
0.01 |
|
barrio |
occidente |
11 |
0.13 |
|
barrio |
pacara |
19 |
0.23 |
|
barrio |
pacará |
4 |
0.05 |
|
barrio |
palmas del ingenio |
1 |
0.01 |
|
barrio |
pampa linda |
26 |
0.31 |
|
barrio |
pampalinda |
12 |
0.14 |
|
barrio |
panamericano |
9 |
0.11 |
|
barrio |
pance |
409 |
4.92 |
|
barrio |
Pance |
3 |
0.04 |
|
barrio |
parcelaciones pance |
61 |
0.73 |
|
barrio |
parque residencial el |
1 |
0.01 |
|
barrio |
paseo de los |
2 |
0.02 |
|
barrio |
paso del comercio |
6 |
0.07 |
|
barrio |
pasoancho |
6 |
0.07 |
|
barrio |
poblado campestre |
2 |
0.02 |
|
barrio |
ponce |
1 |
0.01 |
|
barrio |
popular |
6 |
0.07 |
|
barrio |
portada de comfandi |
2 |
0.02 |
|
barrio |
portales de comfandi |
1 |
0.01 |
|
barrio |
porvenir |
3 |
0.04 |
|
barrio |
prados de oriente |
6 |
0.07 |
|
barrio |
prados del limonar |
20 |
0.24 |
|
barrio |
Prados Del Limonar |
1 |
0.01 |
|
barrio |
prados del norte |
126 |
1.51 |
|
barrio |
Prados Del Norte |
1 |
0.01 |
|
barrio |
prados del sur |
2 |
0.02 |
|
barrio |
primavera |
2 |
0.02 |
|
barrio |
primero de mayo |
37 |
0.44 |
|
barrio |
primitivo crespo |
3 |
0.04 |
|
barrio |
puente del comercio |
6 |
0.07 |
|
barrio |
puente palma |
1 |
0.01 |
|
barrio |
quintas de don |
72 |
0.87 |
|
barrio |
Quintas De Don |
1 |
0.01 |
|
barrio |
quintas de salomia |
4 |
0.05 |
|
barrio |
rafael uribe uribe |
1 |
0.01 |
|
barrio |
refugio |
2 |
0.02 |
|
barrio |
rep√∫blica de israel |
1 |
0.01 |
|
barrio |
rincon de la |
1 |
0.01 |
|
barrio |
rincón de salomia |
1 |
0.01 |
|
barrio |
riveras del valle |
1 |
0.01 |
|
barrio |
rozo la torre |
1 |
0.01 |
|
barrio |
saavedra galindo |
4 |
0.05 |
|
barrio |
salomia |
40 |
0.48 |
|
barrio |
samanes |
1 |
0.01 |
|
barrio |
samanes de guadalupe |
1 |
0.01 |
|
barrio |
sameco |
1 |
0.01 |
|
barrio |
san antonio |
24 |
0.29 |
|
barrio |
san bosco |
8 |
0.10 |
|
barrio |
san carlos |
4 |
0.05 |
|
barrio |
san cayetano |
9 |
0.11 |
|
barrio |
san fernando |
54 |
0.65 |
|
barrio |
San Fernando |
1 |
0.01 |
|
barrio |
san fernando nuevo |
10 |
0.12 |
|
barrio |
san fernando viejo |
18 |
0.22 |
|
barrio |
san joaquin |
4 |
0.05 |
|
barrio |
san joaquín |
16 |
0.19 |
|
barrio |
san juan bosco |
7 |
0.08 |
|
barrio |
san judas |
1 |
0.01 |
|
barrio |
san judas tadeo |
2 |
0.02 |
|
barrio |
san luis |
2 |
0.02 |
|
barrio |
san luís |
1 |
0.01 |
|
barrio |
san nicolas |
1 |
0.01 |
|
barrio |
san nicolás |
1 |
0.01 |
|
barrio |
san pedro |
3 |
0.04 |
|
barrio |
san vicente |
48 |
0.58 |
|
barrio |
santa |
1 |
0.01 |
|
barrio |
santa anita |
48 |
0.58 |
|
barrio |
Santa Anita |
2 |
0.02 |
|
barrio |
santa anita sur |
1 |
0.01 |
|
barrio |
santa bárbara |
3 |
0.04 |
|
barrio |
santa elena |
10 |
0.12 |
|
barrio |
santa fe |
8 |
0.10 |
|
barrio |
santa helena de |
1 |
0.01 |
|
barrio |
santa isabel |
63 |
0.76 |
|
barrio |
Santa Isabel |
1 |
0.01 |
|
barrio |
santa monica |
51 |
0.61 |
|
barrio |
Santa Monica |
1 |
0.01 |
|
barrio |
santa mónica |
3 |
0.04 |
|
barrio |
santa mónica alta |
1 |
0.01 |
|
barrio |
santa monica norte |
2 |
0.02 |
|
barrio |
santa monica popular |
2 |
0.02 |
|
barrio |
santa mónica popular |
7 |
0.08 |
|
barrio |
santa monica residencial |
5 |
0.06 |
|
barrio |
santa mónica residencial |
39 |
0.47 |
|
barrio |
santa rita |
45 |
0.54 |
|
barrio |
santa rosa |
1 |
0.01 |
|
barrio |
santa teresita |
262 |
3.15 |
|
barrio |
Santa Teresita |
1 |
0.01 |
|
barrio |
Santafe |
1 |
0.01 |
|
barrio |
santander |
1 |
0.01 |
|
barrio |
santo domingo |
5 |
0.06 |
|
barrio |
Santo Domingo |
1 |
0.01 |
|
barrio |
sector aguacatal |
1 |
0.01 |
|
barrio |
sector cañaveralejo guadalupe |
2 |
0.02 |
|
barrio |
seminario |
32 |
0.38 |
|
barrio |
sierras de normandía |
1 |
0.01 |
|
barrio |
siete de agosto |
8 |
0.10 |
|
barrio |
simón bolivar |
1 |
0.01 |
|
barrio |
tejares cristales |
4 |
0.05 |
|
barrio |
tejares de san |
14 |
0.17 |
|
barrio |
templete |
4 |
0.05 |
|
barrio |
tequendama |
44 |
0.53 |
|
barrio |
tequendema |
1 |
0.01 |
|
barrio |
terrón colorado |
1 |
0.01 |
|
barrio |
torres de comfandi |
57 |
0.69 |
|
barrio |
unicentro cali |
1 |
0.01 |
|
barrio |
unión de vivienda |
3 |
0.04 |
|
barrio |
urbanización barranquilla |
4 |
0.05 |
|
barrio |
urbanización boyacá |
1 |
0.01 |
|
barrio |
urbanización colseguros |
3 |
0.04 |
|
barrio |
urbanizacion el saman |
1 |
0.01 |
|
barrio |
urbanizacion gratamira |
1 |
0.01 |
|
barrio |
urbanización la flora |
83 |
1.00 |
|
barrio |
urbanización la merced |
4 |
0.05 |
|
barrio |
urbanización la nueva |
4 |
0.05 |
|
barrio |
urbanización las cascadas |
1 |
0.01 |
|
barrio |
urbanizacion lili |
2 |
0.02 |
|
barrio |
urbanización nueva granada |
3 |
0.04 |
|
barrio |
urbanización pacara |
1 |
0.01 |
|
barrio |
urbanización río lili |
5 |
0.06 |
|
barrio |
urbanización san joaquin |
4 |
0.05 |
|
barrio |
urbanización tequendama |
7 |
0.08 |
|
barrio |
valle de lili |
1 |
0.01 |
|
barrio |
valle del lili |
1008 |
12.12 |
|
barrio |
Valle Del Lili |
1 |
0.01 |
|
barrio |
valle grande |
1 |
0.01 |
|
barrio |
versalles |
71 |
0.85 |
|
barrio |
villa colombia |
6 |
0.07 |
|
barrio |
villa de veracruz |
6 |
0.07 |
|
barrio |
villa del lago |
10 |
0.12 |
|
barrio |
villa del parque |
1 |
0.01 |
|
barrio |
villa del prado |
51 |
0.61 |
|
barrio |
Villa Del Prado |
1 |
0.01 |
|
barrio |
villa del sol |
25 |
0.30 |
|
barrio |
villa del sur |
5 |
0.06 |
|
barrio |
villas de veracruz |
8 |
0.10 |
|
barrio |
Villas De Veracruz |
1 |
0.01 |
|
barrio |
vipasa |
32 |
0.38 |
|
barrio |
zona centro |
1 |
0.01 |
|
barrio |
zona norte |
32 |
0.38 |
|
barrio |
zona norte los |
1 |
0.01 |
|
barrio |
zona oeste |
26 |
0.31 |
|
barrio |
zona oriente |
18 |
0.22 |
|
barrio |
zona residencial |
1 |
0.01 |
|
barrio |
zona sur |
74 |
0.89 |
Fuente: Elaboración Propia.
Tabla de contingencia.
| Zona Centro | Zona Norte | Zona Oeste | Zona Oriente | Zona Sur | |
|---|---|---|---|---|---|
| Apartamento | 24 | 1198 | 1029 | 62 | 2787 |
| Casa | 100 | 722 | 169 | 289 | 1939 |
Fuente: Elaboración Propia.
| 3 | 4 | 5 | 6 | |
|---|---|---|---|---|
| Zona Centro | 105 | 14 | 4 | 1 |
| Zona Norte | 572 | 407 | 769 | 172 |
| Zona Oeste | 54 | 84 | 290 | 770 |
| Zona Oriente | 340 | 8 | 2 | 1 |
| Zona Sur | 382 | 1616 | 1685 | 1043 |
Fuente: Elaboración Propia.
| 3 | 4 | 5 | 6 | |
|---|---|---|---|---|
| Zona Centro | 84.68 | 11.29 | 3.23 | 0.81 |
| Zona Norte | 29.79 | 21.2 | 40.05 | 8.96 |
| Zona Oeste | 4.51 | 7.01 | 24.21 | 64.27 |
| Zona Oriente | 96.87 | 2.28 | 0.57 | 0.28 |
| Zona Sur | 8.08 | 34.19 | 35.65 | 22.07 |
🟢 Verde pastel → frecuencia relativa más alta. 🟡 Amarillo pastel → frecuencias intermedias. 🔴 Rosa pastel → frecuencia relativa más baja.
Fuente: Elaboración Propia.
| variable | cantidad_nulos | porcentaje_nulos |
|---|---|---|
| id | 3 | 0.0360490 |
| zona | 3 | 0.0360490 |
| piso | 2638 | 31.6991108 |
| estrato | 3 | 0.0360490 |
| preciom | 2 | 0.0240327 |
| areaconst | 3 | 0.0360490 |
| parqueaderos | 1605 | 19.2862293 |
| banios | 3 | 0.0360490 |
| habitaciones | 3 | 0.0360490 |
| tipo | 3 | 0.0360490 |
| barrio | 3 | 0.0360490 |
| longitud | 3 | 0.0360490 |
| latitud | 3 | 0.0360490 |
Fuente: Elaboración Propia.
Gráfica 1. Frecuencia de datos faltantes por variable.
Fuente: Elaboración Propia.
Gráfica 2. Detección de valores atípico por variable.
Fuente: Elaboración Propia.
Durante la etapa de preparación de los datos se realizó una evaluación de la calidad, variabilidad y capacidad explicativa de cada variable disponible. Como resultado de este análisis, las variables piso y parqueaderos fueron excluidas de la base analítica utilizada en las técnicas multivariadas.
En el caso de la variable piso, se observó una baja capacidad discriminante dentro del conjunto de datos, debido a su limitada contribución para explicar las diferencias entre los inmuebles analizados. Adicionalmente, la variable presentó una relación débil con la variable de interés principal (preciom), por lo que su inclusión aportaba escasa información para los objetivos de reducción de dimensionalidad y segmentación.
Respecto a la variable parqueaderos, se identificó una distribución altamente concentrada en un número reducido de categorías, generando una variabilidad limitada y reduciendo su capacidad para diferenciar adecuadamente los inmuebles. Asimismo, su aporte a la explicación de la estructura general de la base resultó marginal en comparación con otras variables de mayor relevancia, como área construida, número de habitaciones, número de baños, estrato y ubicación.
La exclusión de estas variables permitió construir una base analítica más consistente, reduciendo la presencia de información redundante o poco informativa y favoreciendo la aplicación de técnicas multivariadas como el Análisis de Componentes Principales (ACP), el Análisis de Conglomerados y el Análisis de Correspondencias, cuyos resultados dependen de la capacidad explicativa y la variabilidad de las variables incluidas.
Adicionalmente, ambas variables presentaron una contribución limitada a la explicación de la variabilidad total de los datos y no mostraron una influencia significativa en los análisis exploratorios realizados, razón por la cual fueron descartadas para evitar incorporar ruido estadístico y mejorar la interpretabilidad de los resultados obtenidos.
La base de datos vivienda está compuesta por 8.322 registros y 13 variables, las cuales describen características físicas, espaciales y económicas de inmuebles residenciales. La exploración inicial permitió identificar una estructura de datos adecuada para el desarrollo del estudio, con información relacionada con precio de oferta, área construida, estrato socioeconómico, ubicación geográfica, tipo de vivienda y características habitacionales.
A partir del inventario de variables y de los análisis descriptivos realizados, se evidenció la coexistencia de variables cuantitativas y cualitativas, condición que resulta apropiada para la aplicación de técnicas multivariadas orientadas a la reducción de dimensionalidad, segmentación de viviendas y análisis de relaciones categóricas. Asimismo, se confirmó que la variable preciom constituye la variable de interés principal, al representar el precio de oferta de los inmuebles y ser el eje central de la investigación.
En términos de calidad de los datos, se evaluó la presencia de valores faltantes, registros duplicados, consistencia de la información y observaciones atípicas. Los resultados mostraron que, aunque la base presenta una estructura sólida y utilizable para fines analíticos, existen diferencias importantes en las escalas de medición de las variables. Por ejemplo, variables como preciom y areaconst presentan magnitudes considerablemente superiores a variables como banios o habitaciones, situación que puede generar que las variables de mayor escala dominen los resultados de los análisis multivariados.
Adicionalmente, la detección de valores atípicos permitió identificar observaciones extremas asociadas principalmente a variables relacionadas con el tamaño y valor de los inmuebles. Aunque estos registros pueden corresponder a propiedades reales del mercado y no necesariamente a errores de captura, su presencia puede influir significativamente en los estadísticos descriptivos y en la formación de grupos durante los procesos de segmentación.
Con base en este diagnóstico, resulta necesario realizar una fase de preparación y transformación de los datos, orientada a mejorar la calidad y comparabilidad de la información. Esta etapa incluye el tratamiento de valores faltantes, la evaluación de observaciones atípicas y, especialmente, la estandarización de las variables numéricas mediante puntuaciones Z. Este procedimiento se justifica porque las técnicas que serán aplicadas posteriormente, como el Análisis de Componentes Principales (ACP) y el Análisis de Conglomerados, son sensibles a las diferencias de escala entre variables. Sin una transformación previa, variables con valores absolutos elevados tendrían una influencia desproporcionada en los resultados, dificultando la identificación de patrones reales en la información.
En consecuencia, el diagnóstico realizado permite concluir que la base de datos posee un nivel de calidad adecuado para el desarrollo del estudio; sin embargo, requiere procesos de depuración y transformación que garanticen la validez estadística, la comparabilidad de las variables y la confiabilidad de los resultados obtenidos en las etapas posteriores del análisis multivariado.
En esta fase se realizan las actividades necesarias para garantizar la calidad y consistencia de la información. Esto incluye la revisión, limpieza y adecuación de los datos, con el fin de disponer de una base analítica confiable para la aplicación de las técnicas estadísticas posteriores.
He creado este bloque de código R, el cual tiene como objetivo reemplazar por valores faltantes (NA) aquellos registros que previamente fueron identificados como valores atípicos, conservando la trazabilidad de las observaciones originales. Ello facilita la imputación que se haga posteriormente a los datos, con el objeto de mejorar su calidad.
Convertir atipicos en NA solamente en datos_trabajo:
if (exists("auditoria_atipicos") &&
nrow(auditoria_atipicos) > 0L) {
for (i in seq_len(nrow(auditoria_atipicos))) {
posicion <- match(
auditoria_atipicos$fila_original[i],
datos_trabajo$fila_original
)
if (!is.na(posicion)) {
datos_trabajo[posicion, auditoria_atipicos$variable[i]] <- NA
}
}
}
Mediante aplicación de las herramientas de imputación KNN Mixta, permitió (vér Anexo 1, 5. IMPUTACION KNN MIXTA):
La selección de variables para la imputación: Se identificaron las variables que participarían en el proceso de imputación, excluyendo los campos de identificación (id y fila_original), ya que no aportan información para determinar similitudes entre viviendas.
La clasificación de variables según su naturaleza:Las variables seleccionadas fueron clasificadas en numéricas y categóricas. Adicionalmente, se identificaron variables discretas (estrato, banios y habitaciones) para preservar su naturaleza entera durante la imputación.
La estandarización robusta de variables numéricas: Las variables numéricas fueron escaladas utilizando la mediana y el rango intercuartílico (IQR), reduciendo la influencia de valores extremos y garantizando que todas las variables contribuyeran de manera equilibrada al cálculo de distancias.
La definición de la moda ponderada: Se implementó un mecanismo para imputar variables categóricas mediante una moda ponderada, asignando mayor importancia a los vecinos más similares a cada observación faltante.
La construcción de la métrica de distancia mixta: Se desarrolló una función capaz de calcular distancias considerando simultáneamente variables numéricas y categóricas, permitiendo medir la similitud entre viviendas de forma integral.
La creación de la auditoría de imputación: Se generó una estructura de control para registrar cada valor imputado, incluyendo la variable afectada, el origen del dato faltante, el método aplicado y la cantidad de vecinos utilizados.
La identificación de valores faltantes: Para cada variable, se localizaron los registros con información faltante que requerían ser completados antes de continuar con el análisis multivariado.
La selección de vecinos más similares: Para cada dato faltante se identificaron observaciones comparables mediante la distancia mixta calculada sobre las características disponibles de las viviendas.
La aplicación de imputación KNN: Los valores faltantes fueron reemplazados utilizando los cinco vecinos más cercanos. Para variables numéricas se empleó un promedio ponderado por distancia y para variables categóricas una moda ponderada.
La aplicación de mecanismos de respaldo: Cuando no fue posible encontrar observaciones suficientemente comparables, se aplicaron métodos alternativos de imputación: la mediana para variables numéricas y la moda para variables categóricas.
La identificación del origen de la imputación: Se determinó si cada valor imputado correspondía a un dato originalmente faltante o a un valor atípico previamente reemplazado por NA durante la fase de depuración.
La actualización de la base analítica: Los valores imputados fueron incorporados progresivamente a la base de trabajo, permitiendo que las nuevas observaciones completadas participaran en imputaciones. posteriores.
El registro de trazabilidad: Cada imputación quedó documentada en la tabla de auditoría, garantizando la trazabilidad y reproducibilidad del proceso de preparación de datos.
Al finalizar el procedimiento, se obtuvo una base de datos completa y consistente, en la cual los valores faltantes y los valores atípicos tratados fueron reemplazados mediante un enfoque KNN mixto, preservando las relaciones existentes entre las variables y reduciendo el sesgo asociado a la pérdida de información.
En la Siguiente tabla se muestran los resultado de la imputación:
| variable | Total_imputaciones | Faltantes_originales | Valores_atipicos | Vecinos_promedio | Metodo_principal |
|---|---|---|---|---|---|
| areaconst | 3 | 3 | 0 | 5.00 | KNN |
| banios | 3 | 3 | 0 | 5.00 | KNN |
| barrio | 3 | 3 | 0 | 5.00 | KNN |
| estrato | 3 | 3 | 0 | 1.67 | Respaldo: mediana |
| habitaciones | 3 | 3 | 0 | 5.00 | KNN |
| latitud | 3 | 3 | 0 | 5.00 | KNN |
| longitud | 3 | 3 | 0 | 5.00 | KNN |
| preciom | 2 | 2 | 0 | 5.00 | KNN |
| tipo | 3 | 3 | 0 | 5.00 | KNN |
| zona | 3 | 3 | 0 | 0.00 | Respaldo: moda |
Fuente: Elaboración Propia.
Gráfica 3. Datos faltantes antes y después de la limpieza.
Fuente: Elaboración Propia.
La base analítica final denominada vivienda_limpia (Ver tabla ##) quedó conformada por 1.894 registros completamente depurados. Como resultado de las etapas de limpieza, tratamiento de valores faltantes, manejo de datos atípicos e identificación de duplicados, el conjunto de datos presenta 0 valores faltantes, 0 registros duplicados y 0 observaciones atípicas pendientes de tratamiento, garantizando así condiciones adecuadas para la aplicación de las técnicas multivariadas contempladas en el estudio.
| n | mean | sd | min | median | max | |
|---|---|---|---|---|---|---|
| zona* | 8322 | 3.92 | 1.33 | 1.00 | 5.00 | 5.00 |
| estrato | 8322 | 4.63 | 1.03 | 3.00 | 5.00 | 6.00 |
| preciom | 8322 | 433.89 | 328.61 | 58.00 | 330.00 | 1999.00 |
| areaconst | 8322 | 174.94 | 142.94 | 30.00 | 123.00 | 1745.00 |
| banios | 8322 | 3.11 | 1.43 | 0.00 | 3.00 | 10.00 |
| habitaciones | 8322 | 3.61 | 1.46 | 0.00 | 3.00 | 10.00 |
| tipo* | 8322 | 1.39 | 0.49 | 1.00 | 1.00 | 2.00 |
| barrio* | 8322 | 241.54 | 128.85 | 1.00 | 251.00 | 436.00 |
| longitud | 8322 | -76.53 | 0.02 | -76.59 | -76.53 | -76.46 |
| latitud | 8322 | 3.42 | 0.04 | 3.33 | 3.42 | 3.50 |
Fuente: Elaboración Propia.
Tabla 18. Variables Recomendadas.
| Componente | Descripción | Finalidad |
|---|---|---|
| Estrato (Análisis de Componentes Principales) | Aporta el nivel socioeconómico del inmueble dentro de la estructura multivariada. | Reducir la dimensionalidad de las variables cuantitativas e identificar las principales estructuras de variación del mercado inmobiliario. |
| Precio (Análisis de Componentes Principales) | Representa la dimensión monetaria y ayuda a identificar componentes asociados con la variación del precio. | Reducir la dimensionalidad de las variables cuantitativas e identificar las principales estructuras de variación del mercado inmobiliario. |
| Área construida (Análisis de Componentes Principales) | Representa el tamaño físico y ayuda a identificar componentes de amplitud de la oferta. | Reducir la dimensionalidad de las variables cuantitativas e identificar las principales estructuras de variación del mercado inmobiliario. |
| Baños (Análisis de Componentes Principales) | Representa la dotación funcional de la propiedad. | Reducir la dimensionalidad de las variables cuantitativas e identificar las principales estructuras de variación del mercado inmobiliario. |
| Habitaciones (Análisis de Componentes Principales) | Representa la capacidad habitacional de la propiedad. | Reducir la dimensionalidad de las variables cuantitativas e identificar las principales estructuras de variación del mercado inmobiliario. |
| Estrato (Análisis de Conglomerados) | Permite diferenciar segmentos de oferta según nivel socioeconómico. | Identificar grupos homogéneos de inmuebles y caracterizar segmentos diferenciados de la oferta inmobiliaria. |
| Precio (Análisis de Conglomerados) | Permite separar segmentos por nivel de precio. | Identificar grupos homogéneos de inmuebles y caracterizar segmentos diferenciados de la oferta inmobiliaria. |
| Área construida (Análisis de Conglomerados) | Permite agrupar propiedades según tamaño construido. | Identificar grupos homogéneos de inmuebles y caracterizar segmentos diferenciados de la oferta inmobiliaria. |
| Baños (Análisis de Conglomerados) | Permite diferenciar segmentos por dotación interna. | Identificar grupos homogéneos de inmuebles y caracterizar segmentos diferenciados de la oferta inmobiliaria. |
| Habitaciones (Análisis de Conglomerados) | Permite diferenciar segmentos por capacidad residencial. | Identificar grupos homogéneos de inmuebles y caracterizar segmentos diferenciados de la oferta inmobiliaria. |
| Tipo de vivienda (Análisis de Correspondencia) | Permite examinar la distribución de las clases de vivienda. | Identificar asociaciones entre categorías y representar gráficamente los patrones de relación existentes entre las variables cualitativas. |
| Zona (Análisis de Correspondencia) | Permite identificar asociaciones entre tipología y sector de la ciudad. | Identificar asociaciones entre categorías y representar gráficamente los patrones de relación existentes entre las variables cualitativas. |
| Barrio (Análisis de Correspondencia) | Permite reconocer patrones territoriales y especialización de la oferta por barrio. | Identificar asociaciones entre categorías y representar gráficamente los patrones de relación existentes entre las variables cualitativas. |
Fuente: Elaboración Propia.
Tabla 19. Modelos aplicables a las variables seleccionadas.
| Componente | Variables recomendadas | Descripción | Finalidad |
|---|---|---|---|
| Análisis de Componentes Principales (ACP) | estrato, preciom, areaconst, banios, habitaciones | Variables cuantitativas recomendadas para reducir la dimensionalidad y visualizar la estructura multivariada del mercado inmobiliario. | Identificar características asociadas con la variación de los precios y de la oferta inmobiliaria. |
| Análisis de Conglomerados | estrato, preciom, areaconst, banios, habitaciones | Variables utilizadas para agrupar propiedades en segmentos homogéneos según sus características y estrato socioeconómico. | Comprender las dinámicas de la oferta mediante la identificación de segmentos homogéneos de propiedades. |
| Análisis de Correspondencia | tipo, zona, barrio | Variables categóricas recomendadas para examinar asociaciones entre tipo de vivienda, zona y barrio. | Reconocer patrones de comportamiento y asociaciones territoriales de la oferta inmobiliaria. |
Fuente: Elaboración Propia.
Con el propósito de identificar las dimensiones que explican la mayor parte de la variabilidad presente en la oferta inmobiliaria, se aplicó un Análisis de Componentes Principales (ACP) sobre las variables estrato, precio, área construida, baños y habitaciones. Esta técnica permitió sintetizar la información contenida en dichas variables y reducir la complejidad del conjunto de datos. Asimismo, facilitó la identificación de los factores más influyentes en la caracterización de las viviendas y en la explicación de las diferencias observadas en el mercado inmobiliario analizado.
En el anexo 3, se presentan las siguientes tablas para apoyar los resultados del ACP:
La gráfica 4 muestra cuánto de la variabilidad existente en las cinco variables originales es capaz de recoger cada componente principal.
Las variables utilizadas fueron:
El CP1 explica aproximadamente el 58,66 % de la variabilidad total, mientras que el CP2 explica el 23,77 %. En conjunto, los dos primeros componentes representan aproximadamente el 82,43 % de la variabilidad observada, superando el umbral del 80 % establecido como criterio de retención.
Esto es importante porque significa que podemos pasar de cinco variables originales a solamente dos dimensiones sintéticas, perdiendo relativamente poca información.
El CP1 concentra la mayor cantidad de información, por lo que constituye la dimensión más importante. El CP2 aporta una segunda dimensión que complementa la información del primero.
Desde la perspectiva del mercado inmobiliario, esto permite simplificar la caracterización de las viviendas. En lugar de analizar simultáneamente cinco variables, podemos estudiar dos dimensiones principales que resumen buena parte de las diferencias entre los inmuebles.
Esto resulta particularmente útil posteriormente para:
En la representación gráfica, la línea roja horizontal representa el 80% de varianza acumulada. La curva acumulada supera esa referencia en el segundo componente, justificando la retención de CP1 y CP2.
Gráfica 4. Varianza explicado por los componentes principales.
Fuente: Elaboración Propia.
La gráfica 5 representa cada vivienda como un punto dentro del plano definido por los dos componentes retenidos.
Aquí cada punto representa una propiedad inmobiliaria. Y la lógica indica que cuanto más cerca estén dos viviendas dentro del plano factorial, más parecidos son sus perfiles multivariados respecto de las variables utilizadas en el ACP.
Por el contrario, viviendas muy alejadas entre sí presentan características diferentes en términos de precio, área, baños, habitaciones y estrato.
Allí se aprecia una concentración importante de viviendas alrededor de la zona central del gráfico, aunque también existe una dispersión considerable hacia los diferentes extremos.
Esto indica que existe un núcleo importante de propiedades con características relativamente similares, pero también aparecen viviendas con perfiles diferenciados.
La dispersión hacia valores positivos del CP1 puede asociarse, de acuerdo con las cargas observadas, con viviendas que presentan conjuntamente mayores niveles en las variables que caracterizan este componente.
Por su parte, el CP2 permite diferenciar principalmente viviendas asociadas con la relación entre estrato y número de habitaciones.
En síntsis, las viviendas que aparecen agrupadas representan propiedades que se parecen entre sí. Las que aparecen alejadas constituyen perfiles inmobiliarios más particulares.
Esto es especialmente valioso para una posterior segmentación mediante análisis de conglomerados, porque el ACP proporciona un espacio reducido en el cual resulta más sencillo identificar grupos de viviendas con características semejantes.
Gráfica 5. Estructura de las viviendas en el plano del ACP.
Fuente: Elaboración Propia.
La gráfica 6 es probablemente la más importante para interpretar qué significa cada componente.
Las variables con mayores cargas positivas en CP1 son: banios(0,52), preciom (0,51) y areaconst (0,49). Esto muestra que CP1 está asociado simultáneamente con: mayor número de baños; mayor precio; y mayor área construida. Esto resulta bastante coherente desde el punto de vista económico: las propiedades con mayor superficie y mayor dotación suelen ubicarse también en segmentos de mayor valor. Por tanto, podemos interpretar CP1 como una dimensión relacionada con el nivel físico-económico de la vivienda.
En el segundo componente aparecen dos variables especialmente importantes: estrato (-0,67), habitacines (0,65),preciom (-0,28).
Aquí aparece una relación bastante interesante. El estrato presenta una carga negativa elevada, mientras que habitaciones presenta una carga positiva elevada. Esto significa que CP2 está capturando principalmente un contraste entre estas dos características. Es importante no interpretar el signo negativo del estrato como algo “malo”. En ACP, el signo de un componente es arbitrario: si se multiplicara todo el componente por -1, las relaciones estadísticas serían exactamente las mismas.
Lo importante es la relación relativa entre las variables. Por tanto, CP2 puede interpretarse como una dimensión asociada con el perfil residencial de la vivienda, particularmente con la relación entre nivel socioeconómico/estrato y capacidad habitacional.
La presencia de preciom con una carga negativa menor (-0,28) indica que también participa en esta dimensión, aunque con una importancia bastante menor que estrato y habitaciones.
Gráfica 6. Cargas de las variables en CP1 y CP2.
Fuente: Elaboración Propia.
Tabla 20. Resumen del Análisis de Componentes Principales.
| Componente | Variable | Carga | Contribución (%) | Varianza explicada (%) |
|---|---|---|---|---|
| CP1 | banios | 0.52 | 26.93 | 58.66 |
| CP1 | preciom | 0.51 | 25.69 | 58.66 |
| CP1 | areaconst | 0.49 | 24.41 | 58.66 |
| CP2 | estrato | -0.67 | 45.49 | 23.77 |
| CP2 | habitaciones | 0.65 | 42.75 | 23.77 |
| CP2 | preciom | -0.28 | 7.89 | 23.77 |
Fuente: Elaboración Propia.
El resultado del ACP lo podemos sintetizar de la siguiente manera:
CP1 → “Dimensión físico-económica” y representa principalmente el tamaño, la dotación y el nivel económico de la propiedad.
CP2 → “Dimensión de perfil residencial” Diferencia las viviendas principalmente por la relación entre estrato y capacidad habitacional.
Esta interpretación es mucho más útil que decir simplemente “CP1 explica 58,66 %” y “CP2 explica 23,77 %”, porque permite darle significado económico a los componentes.
Una vez reducida la dimensionalidad de la base vivienda_limpia mediante el Análisis de Componentes Principales (ACP), se procedió a aplicar un Análisis de Conglomerados con el propósito de identificar grupos homogéneos de viviendas que compartieran características similares. Esta técnica permitió segmentar el mercado inmobiliario a partir de patrones presentes en los datos, facilitando la caracterización de perfiles de inmuebles y la identificación de segmentos relevantes para la toma de decisiones y el análisis estratégico del mercado.
La evaluación de soluciones entre 2 y 8 conglomerados mediante el índice de Calinski-Harabasz muestra que la solución con k = 2 obtiene el mayor valor del indicador:
El índice de Calinski-Harabasz busca un equilibrio entre alta separación entre los grupos y alta homogeneidad dentro de cada grupo. Por tanto, el máximo observado en k = 2 indica que esta alternativa ofrece la mejor estructura de segmentación entre las soluciones evaluadas.
Tabla 21. índice de Calinski-Harabasz.
| Número de grupos (k) | Suma intragrupos | Suma entre grupos | Proporción separada (%) | Índice Calinski-Harabasz |
|---|---|---|---|---|
| 2 | 17837.66 | 16456.80 | 47.99 | 7675.93 |
| 3 | 13168.96 | 21125.51 | 61.60 | 6672.63 |
| 4 | 9662.54 | 24631.92 | 71.82 | 7068.13 |
| 5 | 7544.22 | 26750.24 | 78.00 | 7372.59 |
| 6 | 6313.27 | 27981.20 | 81.59 | 7371.51 |
| 7 | 5510.57 | 28783.89 | 83.93 | 7238.75 |
| 8 | 4834.98 | 29459.48 | 85.90 | 7236.72 |
El gráfico # confirma visualmente la decisión anterior. El índice alcanza su máximo en k = 2 y posteriormente disminuye considerablemente al pasar a tres conglomerados.
Es particularmente importante observar que, aunque el indicador vuelve a aumentar para k = 4, 5 y 6, estos valores permanecen por debajo del obtenido con dos grupos.
Gráfica 7. Selección del número de conglomerados.
La representación de los conglomerados sobre el espacio definido por los dos primeros componentes principales muestra una separación bastante evidente.
El Conglomerado 2 se concentra principalmente hacia los valores negativos o cercanos a cero de CP1, mientras que el Conglomerado 1 se desplaza hacia valores positivos de CP1.
Esto es coherente con los resultados del ACP, donde el primer componente está fuertemente relacionado con variables como precio, área construida y baños, que son precisamente algunas de las variables que presentan mayores diferencias entre los dos conglomerados.
También se observa cierta dispersión y solapamiento alrededor de la zona central del gráfico. Esto es normal y significa que no todas las propiedades pueden separarse de manera absolutamente nítida; existen inmuebles con características intermedias.
Gráfica 8. Segmentos inmobiliarios en el espacio del ACP.
La distribución de las propiedades entre los dos segmentos muestra una diferencia importante:
Gráfica 9. Distribución de las propiedades entre los dos segmentos.
El Conglomerado 2 concentra aproximadamente dos terceras partes de la oferta analizada, mientras que el Conglomerado 1 representa aproximadamente una tercera parte.
Esto indica que el mercado no está dividido en dos segmentos de igual tamaño. Existe un segmento claramente dominante en términos de número de propiedades.
A partir de todos los resultados, se pueden denominar los grupos de una manera más comprensible:
Presenta valores promedio superiores en todas las variables cuantitativas analizadas:
Presenta valores considerablemente inferiores:
Es, por tanto, el segmento mayoritario de la oferta analizada, con propiedades de menor escala y menor valor relativo frente al primer conglomerado.
Tabla 22. Medias de las variables por conglomerado..
| Conglomerado | Estrato promedio | Precio promedio | Área construida promedio | Baños promedio | Habitaciones promedio |
|---|---|---|---|---|---|
| Conglomerado 1 | 5.28 | 764.29 | 311.03 | 4.64 | 4.69 |
| Conglomerado 2 | 4.32 | 270.29 | 107.55 | 2.36 | 3.07 |
La coincidencia entre medias y medianas fortalece la interpretación de los segmentos.
Por ejemplo, el precio mediano pasa de 670 en el Conglomerado 1 a 250 en el Conglomerado 2, mientras que el área construida mediana pasa de 280 a 90.
Es decir, la diferencia entre los grupos es estructural, no simplemente consecuencia de unos pocos inmuebles excepcionalmente costosos o grandes.
Tabla 23. Medianas de las variables por conglomerado.
| Conglomerado | Estrato mediano | Precio mediano | Área construida mediana | Baños medianos | Habitaciones medianas |
|---|---|---|---|---|---|
| Conglomerado 1 | 6 | 670 | 280 | 4 | 4 |
| Conglomerado 2 | 4 | 250 | 90 | 2 | 3 |
Este resultado es especialmente interesante porque ambos conglomerados tienen como zona predominante la Zona Sur, pero presentan una composición diferente en cuanto a tipo de vivienda y barrio.
Por tanto, la segmentación no está explicada únicamente por una ubicación geográfica general. Dentro de una misma zona existen perfiles inmobiliarios claramente diferenciados.
Tabla 24. Tamaño y participación de los segmentos inmobiliarios.
| Conglomerado | Tipo predominante | Zona predominante | Barrio predominante |
|---|---|---|---|
| Conglomerado 1 | Casa | Zona Sur | ciudad jardín |
| Conglomerado 2 | Apartamento | Zona Sur | valle del lili |
A partir de las dimensiones identificadas mediante el Análisis de Componentes Principales (ACP), se desarrolló el Análisis de Conglomerados sobre la base vivienda_limpia con el propósito de identificar grupos de viviendas con características similares. Esta técnica complementa el ACP al facilitar la segmentación del mercado inmobiliario según patrones comunes de precio, área, estrato y ubicación. Así, se obtuvo una visión más clara de los perfiles predominantes presentes en la oferta de vivienda analizada.
La gráfica 10 representa las 8.322 propiedades analizadas según su longitud y latitud, diferenciando los dos conglomerados obtenidos en el análisis de segmentación.
Se observa que los dos segmentos presentan una distribución espacial amplia y parcialmente superpuesta. Es decir, el Conglomerado 1 y el Conglomerado 2 no se encuentran confinados a territorios completamente independientes, sino que aparecen simultáneamente en buena parte del espacio geográfico representado.
Sin embargo, también se identifican algunos patrones relevantes:
Este último resultado es importante porque coincide con lo encontrado en la caracterización de los conglomerados: el Conglomerado 1 corresponde principalmente a viviendas de mayor precio, área, estrato y dotación, mientras que el Conglomerado 2 reúne una oferta más numerosa y de menor valor relativo.
Gráfica 10. Distribución geográfica relativa de los segmentos en Cali.
La gráfica 11 proporciona una evidencia estadística mucho más contundente sobre la relación territorial entre zona y barrio.
Los resultados reportados son:
El contraste permite plantear las siguientes hipótesis:
H₀: la zona y el barrio son estadísticamente independientes.
H₁: existe una asociación estadísticamente significativa entre la zona y el barrio.
Dado que el valor p es extremadamente pequeño, se rechaza H₀. Por tanto, existe evidencia estadística muy fuerte de que la distribución de los barrios está relacionada con las zonas.
Además, el V de Cramer = 0,939 indica una asociación muy fuerte, cercana al máximo posible de 1.
Interpretación del mapa de correspondencias - Correspondencia Zona Barrio
La lógica del gráfico es que las categorías que aparecen próximas entre sí presentan perfiles de asociación similares, mientras que las categorías alejadas representan perfiles diferentes.
Se observa, por ejemplo, una proximidad muy marcada entre Zona Oeste y Los Cristales, lo que indica que este barrio presenta un perfil particularmente asociado con esa zona dentro de las categorías analizadas.
También se observa que:
Es importante interpretar con cautela la posición cercana al origen: no significa necesariamente que una zona no tenga barrios asociados, sino que su perfil contribuye menos a diferenciar las dimensiones principales del análisis.
Importancia de las dimensiones
La Dimensión 1 explica el 27,3 % de la inercia, mientras que la Dimensión 2 explica el 26,4%.
En conjunto, las dos dimensiones representan aproximadamente: 53,7 % de la inercia total.
Por tanto, el gráfico permite visualizar una proporción importante de la asociación existente entre zona y barrio, aunque no representa la totalidad de la información contenida en la tabla de contingencia.
Esto es importante metodológicamente: las posiciones observadas en el gráfico deben interpretarse como una representación resumida de la asociación, no como una descripción completa de todas las relaciones existentes.
Gráfica 11. Correspondencia: Zona y Barrio.
La prueba permite hacer el contraste de hipótesis como la medida utilizada para determinar la intensidad de la asociación.
Hipótesis generales del análisis
Para cada una de las tres relaciones se plantean las mismas hipótesis:
H₀ (hipótesis nula): las dos variables categóricas son independientes; es decir, no existe una asociación estadísticamente significativa entre ellas.
H₁ (hipótesis alternativa): las dos variables categóricas no son independientes; existe una asociación estadísticamente significativa entre ellas.
El nivel de significancia adoptado es α = 0,05. Por tanto:
Si p < 0,05, se rechaza H₀.
Si p ≥ 0,05, no se rechaza H₀.
El V de Cramer permite complementar la significancia estadística midiendo la intensidad de la asociación entre las variables. Es importante distinguir ambas cosas: una asociación puede ser estadísticamente significativa, pero tener una intensidad relativamente baja.
1. Relación entre tipo de vivienda y zona.
Hipótesis:
Resultado: se rechaza H₀ al 5 %, con V de Cramer = 0,288.
Interpretación
El resultado indica que existe evidencia estadística suficiente para afirmar que el tipo de vivienda no se distribuye de manera independiente entre las diferentes zonas de la ciudad.
Sin embargo, el valor de V = 0,288 indica que la intensidad de esta relación es débil. Esto significa que, aunque la zona está relacionada con el tipo de vivienda, la ubicación por sí sola no explica una proporción especialmente grande de las diferencias observadas en la tipología inmobiliaria.
En términos del mercado inmobiliario, esto sugiere que la composición de la oferta habitacional presenta algunas diferencias territoriales, pero dichas diferencias también están condicionadas por otros factores.
📌 Conclusión: existe asociación estadísticamente significativa, pero de intensidad débil.
2. Relación entre tipo de vivienda y barrio.
Hipótesis:
Resultado: se rechaza H₀ al 5 %, con V de Cramer = 0,305.
Interpretación
En este caso también se encuentra evidencia estadística de una relación entre las variables. El resultado indica que la distribución de los tipos de vivienda varía significativamente entre los barrios.
El V de Cramer = 0,305 representa una asociación de intensidad **moderada*. Comparativamente, esta relación es ligeramente más fuerte que la observada entre tipo de vivienda y zona.
Esto resulta interesante para el análisis del mercado inmobiliario, porque indica que el nivel de desagregación territorial importa. Mientras que una clasificación amplia por zonas presenta una asociación débil, al analizar unidades territoriales más específicas como los barrios se obtiene una relación algo más marcada con la tipología de vivienda.
En otras palabras, determinados barrios tienden a especializarse o concentrar determinados tipos de vivienda.
📌 Conclusión: existe asociación estadísticamente significativa y de intensidad moderada.
3. Relación entre zona y barrio.
Hipótesis:
Resultado: se rechaza H₀ al 5 %, con V de Cramer = 0,506.
Interpretación.
Esta es la relación que presenta la mayor intensidad de asociación de las tres.
El V de Cramer = 0,506 evidencia una asociación alta entre la zona y el barrio. Este resultado es coherente con la propia estructura territorial de la ciudad: los barrios no se distribuyen aleatoriamente entre las zonas, sino que determinados barrios están claramente vinculados con determinadas zonas geográficas.
Esto también ayuda a interpretar el mapa de correspondencias que obtuviste. Las categorías que aparecen próximas en el plano factorial representan perfiles que presentan una relación relativamente mayor dentro de la estructura de asociación.
Por tanto, esta relación muestra que la dimensión territorial constituye un elemento estructurante del mercado inmobiliario analizado.
📌 Conclusión: existe una asociación estadísticamente significativa y de intensidad alta.
En el anexo 4, el código con el cual se hicieron las pruebas y se muestra la síntesis de los resultados, para orientar mejor las decisiones.
Los resultados obtenidos evidencian que existe una relación estadísticamente significativa entre las variables analizadas, ya que en todos los casos se rechazó la hipótesis de independencia al nivel de significancia del 5 %. Sin embargo, la intensidad de dicha relación varía entre los pares de variables. En particular, la asociación entre tipo de vivienda y zona es débil (V = 0.288), lo que indica que, aunque ambas variables están relacionadas, el tipo de inmueble no depende fuertemente de la zona donde se ubica. Por su parte, la relación entre tipo de vivienda y barrio presenta una intensidad moderada (V = 0.305), sugiriendo que algunos barrios tienden a concentrar determinados tipos de inmuebles con mayor frecuencia. Finalmente, la asociación entre zona y barrio es alta (V = 0.506), evidenciando una fuerte correspondencia entre ambas variables, lo cual es coherente dado que los barrios forman parte de zonas específicas de la ciudad. En conjunto, estos resultados permiten concluir que la ubicación geográfica desempeña un papel importante en la caracterización de la oferta inmobiliaria, siendo la relación entre zona y barrio la más determinante dentro de las analizadas.
Al integrar los resultados, se observa que el mercado inmobiliario analizado presenta una estructura que puede entenderse a partir de tres dimensiones complementarias.
Primera dimensión: características físico-económicas. El ACP muestra que variables como precio, área y dotación residencial constituyen una de las principales fuentes de diferenciación de las propiedades.
Segunda dimensión: perfil residencial. El segundo componente permite distinguir propiedades de acuerdo con la relación entre nivel socioeconómico y capacidad habitacional.
Tercera dimensión: localización territorial. Las pruebas de asociación muestran que la ubicación también contribuye a diferenciar la oferta, particularmente a través de la relación entre barrios y zonas.
Estas tres dimensiones no deben interpretarse de manera aislada. Por el contrario, los resultados sugieren que el mercado inmobiliario se estructura mediante la interacción entre valor económico, características físicas, perfil residencial y localización.
Un hallazgo particularmente relevante es que la dimensión territorial no sustituye a las características económicas y físicas. El hecho de que ambos conglomerados tengan presencia predominante en la Zona Sur demuestra que una misma zona puede contener propiedades pertenecientes a segmentos económicos y residenciales diferentes.
Por ello, la segmentación obtenida mediante ACP y conglomerados aporta una lectura más detallada que una clasificación basada únicamente en la ubicación geográfica.
Los resultados permitieron identificar dos mercados claramente diferenciados.
El Conglomerado 1, aunque representa solamente una tercera parte de las propiedades, concentra una oferta de mayor valor y dotación. Este segmento puede estar asociado con compradores que buscan mayor superficie, mayor capacidad habitacional y características residenciales superiores.
El Conglomerado 2, por representar cerca de dos terceras partes de la oferta, constituye el segmento de mayor volumen. Sus menores precios, áreas y niveles de dotación sugieren un mercado potencialmente más amplio en términos de cantidad de propiedades disponibles.
Esto tiene una implicación importante: el segmento más numeroso no necesariamente es el segmento de mayor valor económico individual. El Conglomerado 1 tiene menos propiedades, pero cada inmueble presenta características de mayor valor relativo.
En consecuencia, las estrategias comerciales, de valoración y de planificación inmobiliaria deberían diferenciar entre volumen de mercado y valor unitario de las propiedades.
1. Diseñar estrategias diferenciadas para los dos segmentos.
No resulta conveniente aplicar una única estrategia comercial a toda la oferta. Se recomienda desarrollar estrategias específicas para:
Esto permitiría ajustar precios, productos, financiación y estrategias de comercialización al perfil de cada segmento.
2. Incorporar el barrio como variable estratégica.
Dado que la relación entre tipo de vivienda y barrio es mayor que la relación entre tipo de vivienda y zona, se recomienda que los análisis inmobiliarios futuros trabajen con un nivel territorial más desagregado.
El barrio puede proporcionar información más precisa para identificar patrones de oferta que una clasificación general por zona.
3. No utilizar la zona como único criterio de segmentación.
Los resultados demuestran que una misma zona puede contener propiedades con perfiles considerablemente diferentes. Por ello, las decisiones de valoración, comercialización o planificación deberían combinar:
ubicación + precio + área + estrato + dotación + tipo de vivienda.
4. Priorizar el segmento mayoritario sin ignorar el segmento de alto valor.
El Conglomerado 2, con el 66,9 % de las propiedades, debería recibir especial atención cuando el objetivo sea analizar el comportamiento general de la oferta.
Sin embargo, el Conglomerado 1 no debe considerarse marginal, pues concentra propiedades de mayor valor y características superiores. Puede representar un segmento estratégico desde la perspectiva de rentabilidad por inmueble.
5. Utilizar la segmentación para valoración inmobiliaria.
Los dos conglomerados pueden incorporarse como una variable explicativa en futuros modelos de valoración.
Por ejemplo, podría evaluarse si pertenecer al Conglomerado 1 o al Conglomerado 2 tiene un efecto significativo sobre el precio después de controlar por área, ubicación, tipo de vivienda y otras características.
Esto permitiría pasar de una descripción del mercado a un modelo cuantitativo de valoración inmobiliaria.
6. Complementar el análisis con información temporal.
Los resultados corresponden a la estructura observada en la base analizada. Una recomendación importante es repetir la segmentación con información de diferentes períodos para determinar si:
Esto permitiría evolucionar desde una segmentación estática hacia un análisis de la dinámica del mercado inmobiliario.
El Análisis de Componentes Principales permitió reducir las cinco variables originales —estrato, precio, área construida, número de baños y número de habitaciones— a dos componentes principales que concentran la mayor parte de la información contenida en la estructura multivariada del mercado inmobiliario. Los dos componentes retenidos superan el criterio del 80 % de varianza acumulada, lo que evidencia que la reducción dimensional conserva una proporción elevada de la información original. El primer componente representa fundamentalmente una dimensión físico-económica de la vivienda, determinada por el número de baños, el precio y el área construida. En este componente, las propiedades con mayores dimensiones y dotación tienden a asociarse con mayores niveles de precio, reflejando una relación coherente entre las características físicas del inmueble y su valoración económica. El segundo componente representa una dimensión relacionada con el perfil residencial de las propiedades, en la cual adquieren especial importancia el estrato y el número de habitaciones. La relación entre estas variables permite diferenciar perfiles de vivienda que no necesariamente se explican únicamente por su precio o tamaño, sino por las características socioeconómicas y de capacidad habitacional.
En términos del mercado inmobiliario urbano de Cali, el resultado del ACP evidencia que la oferta puede comprenderse a partir de dos dimensiones fundamentales: una asociada con la escala y valoración económica de la vivienda y otra relacionada con su perfil residencial y socioeconómico. Esta reducción facilitó la identificación de patrones, la segmentación de la oferta y la construcción de perfiles homogéneos de propiedades.
Desde una perspectiva de Ciencia de Datos, el ACP constituye además una etapa estratégica para los análisis posteriores, particularmente para el análisis de conglomerados, ya que permite trabajar con un conjunto reducido de dimensiones que conserva gran parte de la variabilidad original y facilita la identificación de segmentos diferenciados dentro del mercado inmobiliario.
Los resultados muestran que la oferta inmobiliaria analizada no constituye un mercado homogéneo, sino que puede organizarse de manera consistente en dos segmentos claramente diferenciados.
La principal dimensión de diferenciación está asociada al nivel de valor y dotación de las viviendas: el Conglomerado 1 reúne propiedades de mayor precio, mayor área, mayor estrato y mayor número de baños y habitaciones, mientras que el Conglomerado 2 concentra propiedades de menor precio y menor escala, y además constituye la mayor parte de la oferta.
Un hallazgo especialmente relevante es que ambos segmentos tienen como zona predominante la Zona Sur, pero se diferencian por el tipo de vivienda y por los barrios predominantes. Esto sugiere que la ubicación territorial general no es suficiente para explicar la segmentación del mercado; dentro de una misma zona coexisten ofertas inmobiliarias con perfiles económicos y residenciales diferentes.
En términos de mercado, la segmentación permite distinguir, por un lado, una oferta residencial de mayor valor, representada principalmente por casas en sectores como Ciudad Jardín, y, por otro, una oferta de mayor volumen, asociada principalmente a apartamentos y representada por sectores como Valle del Lili.
Por tanto, la decisión final es trabajar con dos segmentos inmobiliarios, ya que esta solución ofrece el mejor equilibrio entre calidad estadística, interpretabilidad y utilidad para comprender la estructura de la oferta inmobiliaria de Cali.
En conjunto, los resultados del Análisis de Correspondencias permiten concluir que las variables territoriales y tipológicas del mercado inmobiliario no son independientes. En las tres relaciones analizadas se rechaza la hipótesis nula de independencia al nivel de significancia del 5 %, aunque la intensidad de las asociaciones es diferente.
La asociación más débil se presenta entre tipo de vivienda y zona (V = 0,288), mientras que la relación entre tipo de vivienda y barrio (V = 0,305) alcanza una intensidad moderada. La asociación más importante corresponde a zona y barrio (V = 0,506), lo que evidencia una marcada estructura territorial de la oferta inmobiliaria.
Desde la perspectiva del mercado inmobiliario, estos resultados sugieren que la ubicación geográfica constituye un elemento relevante para comprender la composición y distribución de la oferta. En particular, el barrio parece proporcionar una diferenciación territorial más específica que la clasificación general por zonas. Esto respalda el uso del Análisis de Correspondencias como herramienta exploratoria para identificar patrones de especialización territorial, proximidad entre categorías y perfiles diferenciados de la oferta inmobiliaria.
Un punto metodológico importante: rechazar H₀ demuestra asociación, no causalidad. Por tanto, los resultados permiten afirmar que las variables están relacionadas, pero no que una de ellas sea necesariamente la causa de la otra.
En síntesis, los resultados evidencian que la oferta inmobiliaria urbana analizada presenta una estructura heterogénea y multidimensional, en la que interactúan características económicas, físicas, residenciales y territoriales. El Análisis de Componentes Principales permitió resumir las cinco variables originales en dos dimensiones interpretables: una dimensión físico-económica, asociada principalmente con el tamaño, la dotación y el nivel de valor de las propiedades, y una dimensión de perfil residencial, relacionada fundamentalmente con el estrato y la capacidad habitacional. Los dos componentes retenidos concentran el 85,09 % de la varianza acumulada, por lo que constituyen una representación adecuada de la estructura multivariada de la oferta.
Sobre estas dimensiones fue posible identificar dos segmentos inmobiliarios claramente diferenciados. El Conglomerado 1, de menor participación en la oferta, reúne propiedades de mayor estrato, precio, área construida, número de baños y habitaciones, configurando un segmento de mayor valor y dotación. Por su parte, el Conglomerado 2, que concentra aproximadamente el 66,9 % de las propiedades, representa el segmento mayoritario y está conformado por inmuebles de menor escala y menor valor relativo. Esta diferenciación confirma que el mercado analizado no constituye una oferta homogénea y que existen perfiles inmobiliarios con características económicas y residenciales claramente diferenciadas.
Los resultados también muestran que la segmentación no puede explicarse exclusivamente desde una perspectiva territorial. Aunque ambos conglomerados presentan como zona predominante la Zona Sur, sus perfiles se diferencian en términos del tipo de vivienda y de los barrios predominantes. Además, la distribución espacial de los conglomerados evidencia una importante superposición territorial. Por tanto, pertenecer a una determinada zona no implica que las propiedades presenten necesariamente el mismo perfil económico o residencial.
Por otra parte, el Análisis de Correspondencias confirma que existe una relación estadísticamente significativa entre las variables territoriales y tipológicas estudiadas. La relación entre tipo de vivienda y zona presenta una intensidad débil (V = 0,288), mientras que tipo de vivienda y barrio alcanza una intensidad moderada (V = 0,305). La asociación más fuerte corresponde a zona y barrio, con un V de Cramer = 0,506, lo que evidencia una marcada estructura territorial de la oferta inmobiliaria. Estos resultados respaldan la importancia del territorio para comprender la composición del mercado, aunque, metodológicamente, debe recordarse que una asociación estadística no implica una relación causal.
En consecuencia, la principal conclusión para la toma de decisiones es que el mercado inmobiliario de Cali no debe analizarse como un conjunto homogéneo ni únicamente desde la ubicación geográfica. Una caracterización adecuada requiere integrar simultáneamente las dimensiones económica, física, residencial y territorial. Esta perspectiva permite identificar segmentos de mercado con mayor precisión y constituye una base útil para orientar procesos de valoración inmobiliaria, estrategias de comercialización, identificación de mercados objetivo y planificación territorial.
[1] R. A. Johnson y D. W. Wichern, Applied Multivariate Statistical Analysis, 6th ed. Upper Saddle River, NJ, USA: Pearson Education, 2007.
[2] J. F. Hair Jr., W. C. Black, B. J. Babin y R. E. Anderson, Multivariate Data Analysis, 8th ed. Andover, UK: Cengage Learning, 2019.
[3] W. G. Zikmund, B. J. Babin, J. C. Carr y M. Griffin, Business Research Methods, 9th ed. Mason, OH, USA: South-Western Cengage Learning, 2013.
[4] R. J. Shiller, Irrational Exuberance, 3rd ed. Princeton, NJ, USA: Princeton University Press, 2015.
[5] I. T. Jolliffe y J. Cadima, “Principal Component Analysis: A Review and Recent Developments,” Philosophical Transactions of the Royal Society A, vol. 374, no. 2065, pp. 1-16, 2016.
[6] B. S. Everitt, S. Landau, M. Leese y D. Stahl, Cluster Analysis, 5th ed. Chichester, UK: John Wiley & Sons, 2011.
[7] M. Greenacre, Correspondence Analysis in Practice, 3rd ed. Boca Raton, FL, USA: CRC Press, 2017.
[8] C. O. Wilke, Fundamentals of Data Visualization: A Primer on Making Informative and Compelling Figures. Sebastopol, CA, USA: O’Reilly Media, 2019.
# ==============================================================================
# UNIVERSIDAD PONTIFICIA JAVERIANA CALI
# Maestria en Ciencia de Datos
# Actividad 1: Evaluacion de la oferta inmobiliaria urbana
#
# SCRIPT AJUSTADO Y CONSOLIDADO
# Objetivos:
# 1. Cargar la base vivienda sin modificarla.
# 2. Validar y visualizar datos faltantes.
# 3. Detectar y visualizar valores atipicos.
# 4. Excluir piso y parqueaderos de la base analitica.
# 5. Imputar faltantes y atipicos mediante KNN mixto.
# 6. Crear vivienda_limpia con cero NA.
# 7. Mostrar contrastes antes/despues en el panel Plots.
# 8. Resumir variables recomendadas para ACP, conglomerados y
# correspondencia.
#
# Compatible con R 4.5.x.
# Las graficas NO se exportan. Se muestran en el panel Plots de RStudio.
# ==============================================================================
# ==============================================================================
# 0. CONFIGURACION GENERAL
# ==============================================================================
options(scipen = 999, digits = 5)
set.seed(2026)
# Repositorio CRAN utilizado solo si falta una dependencia.
options(repos = c(CRAN = "https://cloud.r-project.org"))
# Paquetes requeridos.
paquetes_requeridos <- c("ggplot2")
for (paquete in paquetes_requeridos) {
if (!requireNamespace(paquete, quietly = TRUE)) {
install.packages(paquete, dependencies = TRUE)
}
if (!requireNamespace(paquete, quietly = TRUE)) {
stop(
paste0("No fue posible instalar o cargar el paquete ", paquete, "."),
call. = FALSE
)
}
}
# Carpeta para tablas, auditorias y bases. Las graficas no se guardan.
carpeta_salida <- file.path(getwd(), "Resultados_Limpieza_Vivienda")
if (!dir.exists(carpeta_salida)) {
dir.create(carpeta_salida, recursive = TRUE, showWarnings = FALSE)
}
if (!dir.exists(carpeta_salida)) {
stop("No fue posible crear la carpeta de resultados.", call. = FALSE)
}
# Paleta pastel comun.
colores_pastel <- c(
Antes = "#FFCAD4",
Despues = "#B7E4C7",
Azul = "#A9DEF9",
Lila = "#CDB4DB",
Amarillo = "#FFE5A5",
Gris = "#D8E2DC"
)
# Tema comun para evitar traslapes.
tema_pastel <- ggplot2::theme_minimal(base_size = 11) +
ggplot2::theme(
plot.title = ggplot2::element_text(
face = "bold", size = 14, colour = "#443A4C", hjust = 0.5
),
plot.subtitle = ggplot2::element_text(
size = 9.5, colour = "#6B596F", hjust = 0.5,
margin = ggplot2::margin(b = 10)
),
plot.caption = ggplot2::element_text(
size = 8.5, colour = "#765B62", hjust = 0.5,
margin = ggplot2::margin(t = 8)
),
axis.text = ggplot2::element_text(colour = "#4D4044"),
axis.title = ggplot2::element_text(colour = "#4D4044", face = "bold"),
panel.grid.minor = ggplot2::element_blank(),
legend.position = "bottom",
legend.title = ggplot2::element_blank(),
plot.margin = ggplot2::margin(12, 28, 12, 12)
)
# ==============================================================================
# 1. CARGAR LA BASE VIVIENDA
# ==============================================================================
# Si vivienda ya existe, se conserva. Si no existe, se carga desde
# paqueteMODELOS. La instalacion desde GitHub solo se intenta si el paquete falta.
if (!exists("vivienda", envir = .GlobalEnv, inherits = FALSE)) {
if (!requireNamespace("paqueteMODELOS", quietly = TRUE)) {
if (!requireNamespace("remotes", quietly = TRUE)) {
install.packages("remotes", dependencies = TRUE)
}
if (!requireNamespace("remotes", quietly = TRUE)) {
stop("No fue posible instalar remotes.", call. = FALSE)
}
remotes::install_github(
repo = "dgonxalex80/paqueteMODELOS",
dependencies = TRUE,
upgrade = "never",
force = FALSE,
build_vignettes = FALSE
)
}
if (!requireNamespace("paqueteMODELOS", quietly = TRUE)) {
stop("paqueteMODELOS no esta disponible.", call. = FALSE)
}
data(
list = "vivienda",
package = "paqueteMODELOS",
envir = .GlobalEnv
)
}
if (!exists("vivienda", envir = .GlobalEnv, inherits = FALSE)) {
stop("No fue posible cargar la base vivienda.", call. = FALSE)
}
vivienda <- as.data.frame(
get("vivienda", envir = .GlobalEnv, inherits = FALSE),
stringsAsFactors = FALSE,
check.names = FALSE
)
# Validar estructura minima.
variables_esperadas <- c(
"id", "zona", "piso", "estrato", "preciom", "areaconst",
"parqueaderos", "banios", "habitaciones", "tipo", "barrio",
"longitud", "latitud"
)
variables_ausentes <- setdiff(variables_esperadas, names(vivienda))
if (length(variables_ausentes) > 0L) {
stop(
paste0(
"La base vivienda no contiene estas variables: ",
paste(variables_ausentes, collapse = ", "), "."
),
call. = FALSE
)
}
if (nrow(vivienda) == 0L) {
stop("La base vivienda no contiene registros.", call. = FALSE)
}
# Copia de control. vivienda no se modifica despues de esta linea.
vivienda_original_control <- vivienda
cat("\nBASE VIVIENDA CARGADA\n")
cat("Filas:", nrow(vivienda), "| Variables:", ncol(vivienda), "\n")
print(names(vivienda))
# ==============================================================================
# 2. VALIDACION Y GRAFICA DE DATOS FALTANTES ORIGINALES
# ==============================================================================
resumen_nulos_original <- data.frame(
variable = names(vivienda),
cantidad_nulos = vapply(vivienda, function(x) sum(is.na(x)), integer(1)),
stringsAsFactors = FALSE
)
resumen_nulos_original$porcentaje_nulos <-
100 * resumen_nulos_original$cantidad_nulos / nrow(vivienda)
resumen_nulos_original
# write.csv(
# resumen_nulos_original,
# file.path(carpeta_salida, "01_resumen_nulos_original.csv"),
# row.names = FALSE,
# fileEncoding = "UTF-8"
# )
orden_nulos <- resumen_nulos_original$variable[
order(resumen_nulos_original$cantidad_nulos, decreasing = FALSE)
]
resumen_nulos_original$variable <- factor(
resumen_nulos_original$variable,
levels = orden_nulos
)
resumen_nulos_original$estado <- ifelse(
resumen_nulos_original$cantidad_nulos > 0,
"Con datos faltantes",
"Sin datos faltantes"
)
total_nulos_original <- sum(resumen_nulos_original$cantidad_nulos)
porcentaje_global_nulos <-
100 * total_nulos_original / (nrow(vivienda) * ncol(vivienda))
grafico_nulos_original <- ggplot2::ggplot(
resumen_nulos_original,
ggplot2::aes(x = variable, y = cantidad_nulos, fill = estado)
) +
ggplot2::geom_col(
width = 0.68, alpha = 0.88, colour = "#5A5266", linewidth = 0.25
) +
ggplot2::geom_text(
ggplot2::aes(
label = paste0(cantidad_nulos, " (", round(porcentaje_nulos, 2), " %)")
),
hjust = -0.12, size = 3.1, colour = "#4D4044"
) +
ggplot2::coord_flip(clip = "off") +
ggplot2::scale_fill_manual(
values = c(
"Con datos faltantes" = colores_pastel[["Antes"]],
"Sin datos faltantes" = colores_pastel[["Gris"]]
)
) +
ggplot2::scale_y_continuous(
expand = ggplot2::expansion(mult = c(0, 0.22))
) +
ggplot2::labs(
title = "Frecuencia de datos faltantes por variable",
subtitle = paste0(
"Base vivienda: ", nrow(vivienda), " registros y ", ncol(vivienda),
" variables"
),
caption = paste0(
"Total de datos faltantes: ", total_nulos_original,
" | Porcentaje global: ", round(porcentaje_global_nulos, 3), " %"
),
x = NULL,
y = "Numero de valores faltantes",
fill = NULL
) +
tema_pastel +
ggplot2::theme(panel.grid.major.y = ggplot2::element_blank())
print(grafico_nulos_original)
# ==============================================================================
# 3. CREAR COPIA DE TRABAJO
# ==============================================================================
datos_trabajo <- as.data.frame(
vivienda,
stringsAsFactors = FALSE,
check.names = FALSE
)
datos_trabajo$fila_original <- seq_len(nrow(datos_trabajo))
# Piso y parqueaderos se excluyen de la base analitica, pero vivienda permanece
# intacta.
datos_trabajo <- datos_trabajo[
,
!names(datos_trabajo) %in% c("piso", "parqueaderos"),
drop = FALSE
]
# Normalizar vacios de variables de texto.
variables_texto <- names(datos_trabajo)[
vapply(
datos_trabajo,
function(x) is.character(x) || is.factor(x),
logical(1)
)
]
for (variable in variables_texto) {
datos_trabajo[[variable]] <- as.character(datos_trabajo[[variable]])
es_vacio <- !is.na(datos_trabajo[[variable]]) &
trimws(datos_trabajo[[variable]]) == ""
datos_trabajo[[variable]][es_vacio] <- NA_character_
}
# Garantizar clases numericas esperadas.
variables_numericas_esperadas <- intersect(
c(
"id", "estrato", "preciom", "areaconst", "banios",
"habitaciones", "longitud", "latitud"
),
names(datos_trabajo)
)
for (variable in variables_numericas_esperadas) {
datos_trabajo[[variable]] <- suppressWarnings(
as.numeric(as.character(datos_trabajo[[variable]]))
)
}
# Copia comparable antes de convertir atipicos en NA.
datos_antes_tratamiento <- datos_trabajo
# ==============================================================================
# 4. DETECTAR Y VISUALIZAR VALORES ATIPICOS
# ==============================================================================
variables_atipicos <- intersect(
c("preciom", "areaconst", "banios", "habitaciones"),
names(datos_trabajo)
)
resumen_atipicos <- data.frame(
variable = character(0),
cantidad_atipicos = integer(0),
porcentaje_atipicos = numeric(0),
limite_inferior = numeric(0),
limite_superior = numeric(0),
stringsAsFactors = FALSE
)
auditoria_atipicos <- data.frame(
fila_original = integer(0),
variable = character(0),
valor_original = numeric(0),
limite_inferior = numeric(0),
limite_superior = numeric(0),
stringsAsFactors = FALSE
)
for (variable in variables_atipicos) {
x <- datos_trabajo[[variable]]
x_valido <- x[is.finite(x)]
if (length(x_valido) < 4L) {
limite_inferior <- NA_real_
limite_superior <- NA_real_
posiciones_atipicas <- integer(0)
} else {
q1 <- as.numeric(stats::quantile(x_valido, 0.25, names = FALSE, type = 7))
q3 <- as.numeric(stats::quantile(x_valido, 0.75, names = FALSE, type = 7))
riq <- q3 - q1
if (!is.finite(riq) || riq == 0) {
limite_inferior <- NA_real_
limite_superior <- NA_real_
posiciones_atipicas <- integer(0)
} else {
limite_inferior <- q1 - 1.5 * riq
limite_superior <- q3 + 1.5 * riq
posiciones_atipicas <- which(
is.finite(x) & (x < limite_inferior | x > limite_superior)
)
}
}
resumen_atipicos <- rbind(
resumen_atipicos,
data.frame(
variable = variable,
cantidad_atipicos = length(posiciones_atipicas),
porcentaje_atipicos = 100 * length(posiciones_atipicas) / nrow(datos_trabajo),
limite_inferior = limite_inferior,
limite_superior = limite_superior,
stringsAsFactors = FALSE
)
)
if (length(posiciones_atipicas) > 0L) {
auditoria_atipicos <- rbind(
auditoria_atipicos,
data.frame(
fila_original = datos_trabajo$fila_original[posiciones_atipicas],
variable = variable,
valor_original = x[posiciones_atipicas],
limite_inferior = limite_inferior,
limite_superior = limite_superior,
stringsAsFactors = FALSE
)
)
}
}
# write.csv(
# resumen_atipicos,
# file.path(carpeta_salida, "02_resumen_atipicos.csv"),
# row.names = FALSE,
# fileEncoding = "UTF-8"
# )
# write.csv(
# auditoria_atipicos,
# file.path(carpeta_salida, "03_auditoria_atipicos.csv"),
# row.names = FALSE,
# fileEncoding = "UTF-8"
# )
# Base larga de variables originales para boxplots.
datos_boxplot_atipicos <- do.call(
rbind,
lapply(
variables_atipicos,
function(variable) {
data.frame(
variable = variable,
valor = datos_antes_tratamiento[[variable]],
stringsAsFactors = FALSE
)
}
)
)
datos_boxplot_atipicos <- datos_boxplot_atipicos[
is.finite(datos_boxplot_atipicos$valor),
,
drop = FALSE
]
# Texto de anotacion por panel.
anotaciones_atipicos <- resumen_atipicos
anotaciones_atipicos$etiqueta <- paste0(
"Atipicos: ", anotaciones_atipicos$cantidad_atipicos,
" (", round(anotaciones_atipicos$porcentaje_atipicos, 2), " %)"
)
grafico_atipicos <- ggplot2::ggplot(
datos_boxplot_atipicos,
ggplot2::aes(x = variable, y = valor, fill = variable)
) +
ggplot2::geom_boxplot(
alpha = 0.78,
width = 0.55,
outlier.alpha = 0.30,
outlier.size = 0.70,
colour = "#5A5266",
linewidth = 0.35
) +
ggplot2::facet_wrap(~variable, scales = "free_y", ncol = 2) +
ggplot2::geom_text(
data = anotaciones_atipicos,
ggplot2::aes(x = variable, y = Inf, label = etiqueta),
inherit.aes = FALSE,
vjust = 1.4,
size = 3.0,
colour = "#765B62"
) +
ggplot2::scale_fill_manual(
values = stats::setNames(
c("#A9DEF9", "#FFCAD4", "#CDB4DB", "#B7E4C7")[
seq_along(variables_atipicos)
],
variables_atipicos
)
) +
ggplot2::labs(
title = "Deteccion de valores atipicos por variable",
subtitle = "Criterio: valores fuera de Q1 - 1,5 x RIQ y Q3 + 1,5 x RIQ",
caption = paste0(
"Total de valores atipicos detectados: ", nrow(auditoria_atipicos),
". Cada panel utiliza una escala propia."
),
x = NULL,
y = "Valor observado",
fill = NULL
) +
tema_pastel +
ggplot2::theme(
axis.text.x = ggplot2::element_blank(),
axis.ticks.x = ggplot2::element_blank(),
strip.background = ggplot2::element_rect(
fill = "#EDE7F2", colour = "#CDB4DB", linewidth = 0.35
),
strip.text = ggplot2::element_text(face = "bold", colour = "#443A4C"),
legend.position = "none"
)
print(grafico_atipicos)
# Convertir atipicos en NA solamente en datos_trabajo.
if (nrow(auditoria_atipicos) > 0L) {
for (i in seq_len(nrow(auditoria_atipicos))) {
posicion <- match(
auditoria_atipicos$fila_original[i],
datos_trabajo$fila_original
)
if (!is.na(posicion)) {
datos_trabajo[posicion, auditoria_atipicos$variable[i]] <- NA
}
}
}
# ==============================================================================
# 5. IMPUTACION KNN MIXTA
# ==============================================================================
# id no participa en KNN. Los demas campos se imputan con vecinos semejantes.
variables_imputables <- setdiff(
names(datos_trabajo),
c("id", "fila_original")
)
variables_numericas_knn <- variables_imputables[
vapply(
datos_trabajo[, variables_imputables, drop = FALSE],
is.numeric,
logical(1)
)
]
variables_categoricas_knn <- setdiff(
variables_imputables,
variables_numericas_knn
)
variables_discretas <- intersect(
c("estrato", "banios", "habitaciones"),
variables_numericas_knn
)
# Matriz auxiliar para distancias. Las numericas se escalan robustamente.
datos_distancia <- datos_trabajo[, variables_imputables, drop = FALSE]
parametros_escalado <- list()
for (variable in variables_numericas_knn) {
x <- datos_distancia[[variable]]
centro <- stats::median(x, na.rm = TRUE)
escala <- stats::IQR(x, na.rm = TRUE)
if (!is.finite(escala) || escala == 0) {
escala <- stats::sd(x, na.rm = TRUE)
}
if (!is.finite(escala) || escala == 0) {
escala <- 1
}
parametros_escalado[[variable]] <- c(centro = centro, escala = escala)
datos_distancia[[variable]] <- (x - centro) / escala
}
# Moda ponderada para objetivos categoricos.
moda_ponderada <- function(valores, pesos) {
validos <- !is.na(valores) & is.finite(pesos)
valores <- as.character(valores[validos])
pesos <- pesos[validos]
if (length(valores) == 0L) {
return(NA_character_)
}
suma_pesos <- tapply(pesos, valores, sum)
candidatos <- names(suma_pesos)[suma_pesos == max(suma_pesos)]
sort(candidatos)[1]
}
# Distancia mixta entre una fila objetivo y candidatos.
calcular_distancia_mixta <- function(
fila_objetivo,
candidatos,
variable_objetivo,
datos_auxiliares) {
predictores <- setdiff(names(datos_auxiliares), variable_objetivo)
suma_distancia <- numeric(length(candidatos))
numero_comparaciones <- integer(length(candidatos))
for (predictor in predictores) {
valor_objetivo <- datos_auxiliares[[predictor]][fila_objetivo]
valores_candidatos <- datos_auxiliares[[predictor]][candidatos]
if (is.na(valor_objetivo)) {
next
}
disponibles <- !is.na(valores_candidatos)
if (!any(disponibles)) {
next
}
if (is.numeric(datos_auxiliares[[predictor]])) {
diferencias <- abs(valores_candidatos[disponibles] - valor_objetivo)
# Evita que una diferencia extrema monopolice la distancia.
diferencias <- pmin(diferencias, 4)
} else {
diferencias <- as.numeric(
as.character(valores_candidatos[disponibles]) !=
as.character(valor_objetivo)
)
}
suma_distancia[disponibles] <-
suma_distancia[disponibles] + diferencias
numero_comparaciones[disponibles] <-
numero_comparaciones[disponibles] + 1L
}
distancias <- rep(Inf, length(candidatos))
utilizables <- numero_comparaciones >= 2L
distancias[utilizables] <-
suma_distancia[utilizables] / numero_comparaciones[utilizables]
distancias
}
# Auditoria de todas las imputaciones.
auditoria_imputacion <- data.frame(
fila_original = integer(0),
variable = character(0),
origen = character(0),
metodo = character(0),
valor_original = character(0),
valor_imputado = character(0),
vecinos_utilizados = integer(0),
stringsAsFactors = FALSE
)
k_vecinos <- 5L
for (variable in variables_imputables) {
filas_pendientes <- which(is.na(datos_trabajo[[variable]]))
if (length(filas_pendientes) == 0L) {
next
}
cat("Imputando", variable, ":", length(filas_pendientes), "valores\n")
for (fila in filas_pendientes) {
candidatos <- which(
!is.na(datos_trabajo[[variable]]) &
seq_len(nrow(datos_trabajo)) != fila
)
if (length(candidatos) == 0L) {
stop(
paste0("No existen candidatos para imputar ", variable, "."),
call. = FALSE
)
}
distancias <- calcular_distancia_mixta(
fila_objetivo = fila,
candidatos = candidatos,
variable_objetivo = variable,
datos_auxiliares = datos_distancia
)
posiciones_validas <- which(is.finite(distancias))
# Respaldo determinista si una fila no tiene al menos dos predictores
# comparables. El caso queda identificado en la auditoria.
if (length(posiciones_validas) == 0L) {
if (variable %in% variables_numericas_knn) {
valor_imputado <- stats::median(
datos_trabajo[[variable]], na.rm = TRUE
)
if (variable %in% variables_discretas) {
valor_imputado <- round(valor_imputado)
}
metodo <- "Respaldo: mediana"
} else {
frecuencias <- table(datos_trabajo[[variable]], useNA = "no")
valor_imputado <- names(frecuencias)[which.max(frecuencias)]
metodo <- "Respaldo: moda"
}
vecinos_usados <- 0L
} else {
orden <- posiciones_validas[
order(distancias[posiciones_validas], na.last = NA)
]
seleccion <- head(orden, k_vecinos)
indices_vecinos <- candidatos[seleccion]
distancias_vecinos <- distancias[seleccion]
pesos <- 1 / pmax(distancias_vecinos, 1e-8)
valores_vecinos <- datos_trabajo[[variable]][indices_vecinos]
if (variable %in% variables_numericas_knn) {
valor_imputado <- stats::weighted.mean(
as.numeric(valores_vecinos), pesos, na.rm = TRUE
)
if (variable %in% variables_discretas) {
valor_imputado <- round(valor_imputado)
}
} else {
valor_imputado <- moda_ponderada(valores_vecinos, pesos)
}
metodo <- "KNN"
vecinos_usados <- length(indices_vecinos)
}
fila_original_actual <- datos_trabajo$fila_original[fila]
posicion_atipico <- which(
auditoria_atipicos$fila_original == fila_original_actual &
auditoria_atipicos$variable == variable
)
era_atipico <- length(posicion_atipico) > 0L
origen <- if (era_atipico) "Valor atipico" else "Faltante original"
valor_original <- if (era_atipico) {
as.character(auditoria_atipicos$valor_original[posicion_atipico[1]])
} else {
NA_character_
}
datos_trabajo[[variable]][fila] <- valor_imputado
# Actualizar la base auxiliar para imputaciones posteriores.
if (variable %in% variables_numericas_knn) {
centro <- parametros_escalado[[variable]]["centro"]
escala <- parametros_escalado[[variable]]["escala"]
datos_distancia[[variable]][fila] <-
(as.numeric(valor_imputado) - centro) / escala
} else {
datos_distancia[[variable]][fila] <- as.character(valor_imputado)
}
auditoria_imputacion <- rbind(
auditoria_imputacion,
data.frame(
fila_original = fila_original_actual,
variable = variable,
origen = origen,
metodo = metodo,
valor_original = valor_original,
valor_imputado = as.character(valor_imputado),
vecinos_utilizados = vecinos_usados,
stringsAsFactors = FALSE
)
)
}
}
# id: identificador tecnico, no se imputa mediante KNN.
filas_id_faltante <- which(is.na(datos_trabajo$id))
if (length(filas_id_faltante) > 0L) {
id_validos <- datos_trabajo$id[is.finite(datos_trabajo$id)]
desde_id <- if (length(id_validos) > 0L) max(id_validos) + 1 else 1
nuevos_id <- seq.int(desde_id, length.out = length(filas_id_faltante))
datos_trabajo$id[filas_id_faltante] <- nuevos_id
auditoria_imputacion <- rbind(
auditoria_imputacion,
data.frame(
fila_original = datos_trabajo$fila_original[filas_id_faltante],
variable = "id",
origen = "Faltante original",
metodo = "Identificador tecnico secuencial",
valor_original = NA_character_,
valor_imputado = as.character(nuevos_id),
vecinos_utilizados = 0L,
stringsAsFactors = FALSE
)
)
}
# auditoria_imputacion
# ==============================================================================
# 6. CREAR Y VALIDAR vivienda_limpia
# ==============================================================================
columnas_finales <- setdiff(names(datos_trabajo), "fila_original")
faltantes_post_imputacion <- colSums(
is.na(datos_trabajo[, columnas_finales, drop = FALSE])
)
if (sum(faltantes_post_imputacion) > 0L) {
detalle <- paste0(
names(faltantes_post_imputacion)[faltantes_post_imputacion > 0],
" = ",
faltantes_post_imputacion[faltantes_post_imputacion > 0],
collapse = "; "
)
stop(
paste0("La imputacion no termino. Faltantes pendientes: ", detalle, "."),
call. = FALSE
)
}
vivienda_limpia <- datos_trabajo[, columnas_finales, drop = FALSE]
rownames(vivienda_limpia) <- NULL
assign("vivienda_limpia", vivienda_limpia, envir = .GlobalEnv)
# Controles no negociables.
stopifnot(
identical(vivienda, vivienda_original_control),
sum(is.na(vivienda_limpia)) == 0L,
!("piso" %in% names(vivienda_limpia)),
!("parqueaderos" %in% names(vivienda_limpia))
)
# write.csv(
# auditoria_imputacion,
# file.path(carpeta_salida, "04_auditoria_imputacion.csv"),
# row.names = FALSE,
# fileEncoding = "UTF-8"
# )
# write.csv(
# vivienda_limpia,
# file.path(carpeta_salida, "vivienda_limpia.csv"),
# row.names = FALSE,
# fileEncoding = "UTF-8"
# )
# saveRDS(vivienda_limpia, file.path(carpeta_salida, "vivienda_limpia.rds"))
# ==============================================================================
# 7. GRAFICA DE NULOS ANTES Y DESPUES
# ==============================================================================
variables_finales <- names(vivienda_limpia)
nulos_antes <- vapply(
vivienda[, variables_finales, drop = FALSE],
function(x) sum(is.na(x)),
integer(1)
)
nulos_despues <- vapply(
vivienda_limpia[, variables_finales, drop = FALSE],
function(x) sum(is.na(x)),
integer(1)
)
tabla_nulos_comparacion <- data.frame(
variable = variables_finales,
antes = as.integer(nulos_antes),
despues = as.integer(nulos_despues),
imputados = as.integer(nulos_antes - nulos_despues),
stringsAsFactors = FALSE
)
# write.csv(
# tabla_nulos_comparacion,
# file.path(carpeta_salida, "05_nulos_antes_despues.csv"),
# row.names = FALSE,
# fileEncoding = "UTF-8"
# )
datos_nulos_comparacion <- rbind(
data.frame(
variable = variables_finales,
momento = "Antes",
cantidad = as.integer(nulos_antes),
stringsAsFactors = FALSE
),
data.frame(
variable = variables_finales,
momento = "Despues",
cantidad = as.integer(nulos_despues),
stringsAsFactors = FALSE
)
)
orden_variables <- tabla_nulos_comparacion$variable[
order(tabla_nulos_comparacion$antes, decreasing = FALSE)
]
datos_nulos_comparacion$variable <- factor(
datos_nulos_comparacion$variable,
levels = orden_variables
)
datos_nulos_comparacion$momento <- factor(
datos_nulos_comparacion$momento,
levels = c("Antes", "Despues")
)
grafico_nulos_antes_despues <- ggplot2::ggplot(
datos_nulos_comparacion,
ggplot2::aes(x = variable, y = cantidad, fill = momento)
) +
ggplot2::geom_col(
position = ggplot2::position_dodge(width = 0.72),
width = 0.64,
alpha = 0.88,
colour = "#5A5266",
linewidth = 0.25
) +
ggplot2::geom_text(
ggplot2::aes(label = cantidad),
position = ggplot2::position_dodge(width = 0.72),
hjust = -0.25,
size = 3.3,
colour = "#4D4044"
) +
ggplot2::coord_flip(clip = "off") +
ggplot2::scale_fill_manual(
values = c(
"Antes" = colores_pastel[["Antes"]],
"Despues" = colores_pastel[["Despues"]]
)
) +
ggplot2::scale_y_continuous(
expand = ggplot2::expansion(mult = c(0, 0.22))
) +
ggplot2::labs(
title = "Datos faltantes antes y despues de la limpieza",
subtitle = paste0(
"Se comparan las variables de vivienda_limpia con sus columnas ",
"correspondientes en vivienda"
),
caption = paste0(
"Total antes: ", sum(nulos_antes),
" | Total despues: ", sum(nulos_despues),
" | Faltantes originales imputados: ", sum(nulos_antes - nulos_despues)
),
x = NULL,
y = "Numero de valores faltantes",
fill = NULL
) +
tema_pastel +
ggplot2::theme(panel.grid.major.y = ggplot2::element_blank())
print(grafico_nulos_antes_despues)
# ==============================================================================
# 8. CONTRASTE DE VARIABLES IMPUTADAS: ANTES Y DESPUES
# ==============================================================================
variables_tratadas <- unique(auditoria_imputacion$variable)
variables_tratadas <- intersect(
variables_tratadas,
intersect(names(vivienda), names(vivienda_limpia))
)
variables_tratadas_numericas <- variables_tratadas[
vapply(
vivienda_limpia[, variables_tratadas, drop = FALSE],
is.numeric,
logical(1)
)
]
variables_tratadas_numericas <- setdiff(
variables_tratadas_numericas,
"id"
)
variables_tratadas_categoricas <- setdiff(
variables_tratadas,
c(variables_tratadas_numericas, "id")
)
# Base larga numerica totalmente controlada.
if (length(variables_tratadas_numericas) > 0L) {
lista_numerica <- lapply(
variables_tratadas_numericas,
function(variable) {
antes <- suppressWarnings(as.numeric(as.character(vivienda[[variable]])))
despues <- suppressWarnings(
as.numeric(as.character(vivienda_limpia[[variable]]))
)
rbind(
data.frame(
variable = variable,
momento = "Antes",
valor = antes,
stringsAsFactors = FALSE
),
data.frame(
variable = variable,
momento = "Despues",
valor = despues,
stringsAsFactors = FALSE
)
)
}
)
datos_contraste_numerico <- do.call(rbind, lista_numerica)
datos_contraste_numerico <- as.data.frame(
datos_contraste_numerico,
stringsAsFactors = FALSE
)
datos_contraste_numerico$valor <- as.numeric(datos_contraste_numerico$valor)
datos_contraste_numerico <- datos_contraste_numerico[
is.finite(datos_contraste_numerico$valor),
,
drop = FALSE
]
datos_contraste_numerico$momento <- factor(
datos_contraste_numerico$momento,
levels = c("Antes", "Despues")
)
datos_contraste_numerico$variable <- factor(
datos_contraste_numerico$variable,
levels = variables_tratadas_numericas
)
grafico_boxplots_imputacion <- ggplot2::ggplot(
datos_contraste_numerico,
ggplot2::aes(x = momento, y = valor, fill = momento)
) +
ggplot2::geom_boxplot(
alpha = 0.72,
width = 0.56,
outlier.alpha = 0.20,
outlier.size = 0.60,
colour = "#5A5266",
linewidth = 0.32
) +
ggplot2::stat_summary(
fun = mean,
geom = "point",
shape = 23,
size = 2.4,
fill = "white",
colour = "#333333"
) +
ggplot2::facet_wrap(~variable, scales = "free_y", ncol = 3) +
ggplot2::scale_fill_manual(
values = c(
"Antes" = colores_pastel[["Antes"]],
"Despues" = colores_pastel[["Despues"]]
)
) +
ggplot2::labs(
title = "Variables numericas antes y despues de la limpieza",
subtitle = paste0(
"Cada panel utiliza una escala propia. El rombo blanco representa ",
"la media."
),
caption = paste0(
"Variables tratadas: ",
paste(variables_tratadas_numericas, collapse = ", ")
),
x = NULL,
y = "Valor observado",
fill = NULL
) +
tema_pastel +
ggplot2::theme(
strip.background = ggplot2::element_rect(
fill = "#EDE7F2", colour = "#CDB4DB", linewidth = 0.35
),
strip.text = ggplot2::element_text(face = "bold", colour = "#443A4C"),
panel.grid.major.x = ggplot2::element_blank()
)
print(grafico_boxplots_imputacion)
# Densidad solo para variables con al menos dos valores distintos por momento.
validar_densidad <- function(variable) {
subconjunto <- datos_contraste_numerico[
datos_contraste_numerico$variable == variable,
,
drop = FALSE
]
antes <- unique(subconjunto$valor[subconjunto$momento == "Antes"])
despues <- unique(subconjunto$valor[subconjunto$momento == "Despues"])
length(antes) >= 2L && length(despues) >= 2L
}
variables_densidad <- variables_tratadas_numericas[
vapply(variables_tratadas_numericas, validar_densidad, logical(1))
]
if (length(variables_densidad) > 0L) {
datos_densidad <- datos_contraste_numerico[
datos_contraste_numerico$variable %in% variables_densidad,
,
drop = FALSE
]
grafico_densidades_imputacion <- ggplot2::ggplot(
datos_densidad,
ggplot2::aes(x = valor, fill = momento, colour = momento)
) +
ggplot2::geom_density(alpha = 0.28, linewidth = 0.75, adjust = 1) +
ggplot2::facet_wrap(~variable, scales = "free", ncol = 3) +
ggplot2::scale_fill_manual(
values = c(
"Antes" = colores_pastel[["Antes"]],
"Despues" = colores_pastel[["Despues"]]
)
) +
ggplot2::scale_colour_manual(
values = c("Antes" = "#B56576", "Despues" = "#4F8A6A")
) +
ggplot2::labs(
title = "Distribuciones antes y despues de la limpieza",
subtitle = paste0(
"La superposicion permite revisar los cambios producidos por la ",
"imputacion."
),
x = "Valor observado",
y = "Densidad",
fill = NULL,
colour = NULL
) +
tema_pastel +
ggplot2::theme(
strip.background = ggplot2::element_rect(
fill = "#EDE7F2", colour = "#CDB4DB", linewidth = 0.35
),
strip.text = ggplot2::element_text(
face = "bold", colour = "#443A4C"
)
)
print(grafico_densidades_imputacion)
}
}
# Contraste categorico, cuando existan variables categoricas imputadas.
if (length(variables_tratadas_categoricas) > 0L) {
lista_categorica <- lapply(
variables_tratadas_categoricas,
function(variable) {
antes <- as.character(vivienda[[variable]])
despues <- as.character(vivienda_limpia[[variable]])
tabla_antes <- as.data.frame(table(antes, useNA = "no"))
names(tabla_antes) <- c("categoria", "frecuencia")
tabla_antes$momento <- "Antes"
tabla_antes$variable <- variable
tabla_despues <- as.data.frame(table(despues, useNA = "no"))
names(tabla_despues) <- c("categoria", "frecuencia")
tabla_despues$momento <- "Despues"
tabla_despues$variable <- variable
combinado <- rbind(tabla_antes, tabla_despues)
combinado$porcentaje <- ave(
combinado$frecuencia,
combinado$momento,
FUN = function(x) 100 * x / sum(x)
)
totales <- aggregate(porcentaje ~ categoria, combinado, sum)
principales <- head(
totales$categoria[order(totales$porcentaje, decreasing = TRUE)],
15
)
combinado[combinado$categoria %in% principales, , drop = FALSE]
}
)
datos_contraste_categorico <- do.call(rbind, lista_categorica)
datos_contraste_categorico$momento <- factor(
datos_contraste_categorico$momento,
levels = c("Antes", "Despues")
)
grafico_categoricas_imputacion <- ggplot2::ggplot(
datos_contraste_categorico,
ggplot2::aes(x = porcentaje, y = categoria, fill = momento)
) +
ggplot2::geom_col(
position = ggplot2::position_dodge(width = 0.72),
width = 0.64,
alpha = 0.86,
colour = "#5A5266",
linewidth = 0.20
) +
ggplot2::facet_wrap(~variable, scales = "free_y", ncol = 1) +
ggplot2::scale_fill_manual(
values = c(
"Antes" = colores_pastel[["Antes"]],
"Despues" = colores_pastel[["Despues"]]
)
) +
ggplot2::labs(
title = "Variables categoricas antes y despues de la limpieza",
subtitle = "Se muestran como maximo las 15 categorias principales",
x = "Participacion dentro de la variable (%)",
y = NULL,
fill = NULL
) +
tema_pastel +
ggplot2::theme(panel.grid.major.y = ggplot2::element_blank())
print(grafico_categoricas_imputacion)
}
# ==============================================================================
# 9. VARIABLES RECOMENDADAS PARA LOS MODELOS
# ==============================================================================
variables_acp <- intersect(
c("estrato", "preciom", "areaconst", "banios", "habitaciones"),
names(vivienda_limpia)
)
variables_conglomerados <- variables_acp
variables_correspondencia <- intersect(
c("tipo", "zona", "barrio"),
names(vivienda_limpia)
)
resumen_variables_modelos <- data.frame(
modelo = c(
rep("Analisis de Componentes Principales", length(variables_acp)),
rep("Analisis de Conglomerados", length(variables_conglomerados)),
rep("Analisis de Correspondencia", length(variables_correspondencia))
),
variable = c(
variables_acp,
variables_conglomerados,
variables_correspondencia
),
enfoque = c(
# ACP
ifelse(
variables_acp == "estrato",
"Aporta el nivel socioeconomico del inmueble dentro de la estructura multivariada.",
ifelse(
variables_acp == "preciom",
"Representa la dimension monetaria y ayuda a identificar componentes asociados con la variacion del precio.",
ifelse(
variables_acp == "areaconst",
"Representa el tamano fisico y ayuda a identificar componentes de amplitud de la oferta.",
ifelse(
variables_acp == "banios",
"Representa la dotacion funcional de la propiedad.",
"Representa la capacidad habitacional de la propiedad."
)
)
)
),
# Conglomerados
ifelse(
variables_conglomerados == "estrato",
"Permite diferenciar segmentos de oferta segun nivel socioeconomico.",
ifelse(
variables_conglomerados == "preciom",
"Permite separar segmentos por nivel de precio.",
ifelse(
variables_conglomerados == "areaconst",
"Permite agrupar propiedades segun tamano construido.",
ifelse(
variables_conglomerados == "banios",
"Permite diferenciar segmentos por dotacion interna.",
"Permite diferenciar segmentos por capacidad residencial."
)
)
)
),
# Correspondencia
ifelse(
variables_correspondencia == "tipo",
"Permite examinar la distribucion de las clases de vivienda.",
ifelse(
variables_correspondencia == "zona",
"Permite identificar asociaciones entre tipologia y sector de la ciudad.",
"Permite reconocer patrones territoriales y especializacion de la oferta por barrio."
)
)
),
stringsAsFactors = FALSE
)
resumen_variables_modelos
# write.csv(
# resumen_variables_modelos,
# file.path(carpeta_salida, "06_variables_recomendadas_modelos.csv"),
# row.names = FALSE,
# fileEncoding = "UTF-8"
# )
cat("\nVARIABLES RECOMENDADAS PARA ACP\n")
print(variables_acp)
cat(paste0(
"Objetivo: reducir la dimensionalidad y visualizar la estructura de las ",
"variables para identificar caracteristicas asociadas con la variacion de ",
"precios y de la oferta.\n"
))
cat("\nVARIABLES RECOMENDADAS PARA CONGLOMERADOS\n")
print(variables_conglomerados)
cat(paste0(
"Objetivo: agrupar propiedades en segmentos homogeneos para comprender ",
"dinamicas de oferta por caracteristicas y estrato socioeconomico.\n"
))
cat("\nVARIABLES RECOMENDADAS PARA CORRESPONDENCIA\n")
print(variables_correspondencia)
cat(paste0(
"Objetivo: examinar asociaciones entre tipo, zona y barrio para reconocer ",
"patrones de comportamiento de la oferta inmobiliaria.\n"
))
# ==============================================================================
# 10. RESUMEN Y VERIFICACIONES FINALES
# ==============================================================================
resumen_imputaciones <- as.data.frame(
table(
auditoria_imputacion$variable,
auditoria_imputacion$origen,
auditoria_imputacion$metodo
),
stringsAsFactors = FALSE
)
names(resumen_imputaciones) <- c("variable", "origen", "metodo", "cantidad")
resumen_imputaciones <- resumen_imputaciones[
resumen_imputaciones$cantidad > 0,
,
drop = FALSE
]
write.csv(
resumen_imputaciones,
file.path(carpeta_salida, "07_resumen_imputaciones.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
capture.output(
sessionInfo(),
file = file.path(carpeta_salida, "sessionInfo_limpieza.txt")
)
cat("\n============================================================\n")
cat("PROCESO FINALIZADO\n")
cat("============================================================\n")
cat("vivienda permanecio intacta:",
identical(vivienda, vivienda_original_control), "\n")
cat("Dimensiones de vivienda:", paste(dim(vivienda), collapse = " x "), "\n")
cat("Dimensiones de vivienda_limpia:",
paste(dim(vivienda_limpia), collapse = " x "), "\n")
cat("Faltantes finales:", sum(is.na(vivienda_limpia)), "\n")
cat("piso excluida:", !("piso" %in% names(vivienda_limpia)), "\n")
cat("parqueaderos excluida:",
!("parqueaderos" %in% names(vivienda_limpia)), "\n")
cat("Atipicos tratados:", nrow(auditoria_atipicos), "\n")
cat("Valores imputados:", nrow(auditoria_imputacion), "\n")
cat("Archivos de resultados en:", carpeta_salida, "\n")
cat("\nGraficos disponibles en el historial del panel Plots:\n")
cat("- grafico_nulos_original\n")
cat("- grafico_atipicos\n")
cat("- grafico_nulos_antes_despues\n")
if (exists("grafico_boxplots_imputacion")) {
cat("- grafico_boxplots_imputacion\n")
}
if (exists("grafico_densidades_imputacion")) {
cat("- grafico_densidades_imputacion\n")
}
if (exists("grafico_categoricas_imputacion")) {
cat("- grafico_categoricas_imputacion\n")
}
# ==============================================================================
# MODULO DE ANALISIS HOLISTICO DEL MERCADO INMOBILIARIO URBANO
#
# UBICACION: agregar al final del script de limpieza, despues de crear y validar
# vivienda_limpia.
#
# Requisitos:
# - vivienda_limpia debe existir.
# - vivienda_limpia debe tener cero valores faltantes.
# - Debe contener las variables utilizadas por cada modelo.
#
# Graficos: se muestran en el panel Plots. No se exportan a PNG.
# ==============================================================================
# ==============================================================================
# 1. VALIDACIONES Y CONFIGURACION
# ==============================================================================
if (!exists("vivienda_limpia", envir = .GlobalEnv, inherits = FALSE)) {
stop("No existe vivienda_limpia. Ejecute primero la fase de limpieza.",
call. = FALSE)
}
if (!is.data.frame(vivienda_limpia)) {
stop("vivienda_limpia debe ser un data.frame.", call. = FALSE)
}
if (nrow(vivienda_limpia) == 0L) {
stop("vivienda_limpia no contiene registros.", call. = FALSE)
}
if (sum(is.na(vivienda_limpia)) > 0L) {
stop("vivienda_limpia contiene valores faltantes.", call. = FALSE)
}
if (!requireNamespace("ggplot2", quietly = TRUE)) {
install.packages("ggplot2", dependencies = TRUE)
}
if (!requireNamespace("ggplot2", quietly = TRUE)) {
stop("No fue posible instalar o cargar ggplot2.", call. = FALSE)
}
set.seed(2026)
options(scipen = 999, digits = 5)
if (!exists("carpeta_salida")) {
carpeta_salida <- file.path(getwd(), "Resultados_Limpieza_Vivienda")
}
carpeta_modelos <- file.path(carpeta_salida, "Modelos_Estadisticos")
if (!dir.exists(carpeta_modelos)) {
dir.create(carpeta_modelos, recursive = TRUE, showWarnings = FALSE)
}
if (!dir.exists(carpeta_modelos)) {
stop("No fue posible crear la carpeta Modelos_Estadisticos.",
call. = FALSE)
}
colores_pastel_modelos <- c(
"#A9DEF9", "#FFCAD4", "#CDB4DB", "#B7E4C7",
"#FFE5A5", "#BDE0FE", "#FFC8DD", "#CDEAC0"
)
tema_modelos <- ggplot2::theme_minimal(base_size = 11) +
ggplot2::theme(
plot.title = ggplot2::element_text(
face = "bold", size = 14, colour = "#443A4C", hjust = 0.5
),
plot.subtitle = ggplot2::element_text(
size = 9.5, colour = "#6B596F", hjust = 0.5,
margin = ggplot2::margin(b = 9)
),
plot.caption = ggplot2::element_text(
size = 8.5, colour = "#765B62", hjust = 0.5,
margin = ggplot2::margin(t = 8)
),
axis.text = ggplot2::element_text(colour = "#4D4044"),
axis.title = ggplot2::element_text(colour = "#4D4044", face = "bold"),
panel.grid.minor = ggplot2::element_blank(),
legend.position = "bottom",
legend.title = ggplot2::element_blank(),
plot.margin = ggplot2::margin(12, 28, 12, 12)
)
# ==============================================================================
# 2. ANALISIS DE COMPONENTES PRINCIPALES
# ==============================================================================
# Objetivo: reducir dimensionalidad y reconocer las variables asociadas con la
# variacion conjunta de precio, tamano, dotacion y capacidad residencial.
#
# Variables:
# estrato, preciom, areaconst, banios y habitaciones.
# id se excluye por ser identificador. Longitud y latitud se reservan para mapa.
# ==============================================================================
variables_acp <- intersect(
c("estrato", "preciom", "areaconst", "banios", "habitaciones"),
names(vivienda_limpia)
)
if (length(variables_acp) < 2L) {
stop("No existen al menos dos variables disponibles para el ACP.",
call. = FALSE)
}
datos_acp <- as.data.frame(
lapply(
vivienda_limpia[, variables_acp, drop = FALSE],
function(x) suppressWarnings(as.numeric(as.character(x)))
),
check.names = FALSE
)
if (sum(is.na(datos_acp)) > 0L) {
stop("La conversion numerica del ACP produjo valores faltantes.",
call. = FALSE)
}
desviaciones_acp <- vapply(datos_acp, stats::sd, numeric(1))
variables_constantes <- names(desviaciones_acp)[
!is.finite(desviaciones_acp) | desviaciones_acp == 0
]
if (length(variables_constantes) > 0L) {
datos_acp <- datos_acp[
, !names(datos_acp) %in% variables_constantes, drop = FALSE
]
}
if (ncol(datos_acp) < 2L) {
stop("El ACP quedo con menos de dos variables no constantes.",
call. = FALSE)
}
modelo_acp <- stats::prcomp(
datos_acp,
center = TRUE,
scale. = TRUE,
retx = TRUE
)
autovalores_acp <- modelo_acp$sdev^2
porcentaje_varianza_acp <- 100 * autovalores_acp / sum(autovalores_acp)
varianza_acumulada_acp <- cumsum(porcentaje_varianza_acp)
n_componentes <- which(varianza_acumulada_acp >= 80)[1]
if (is.na(n_componentes)) n_componentes <- length(autovalores_acp)
n_componentes <- min(max(2L, n_componentes), ncol(modelo_acp$x))
tabla_varianza_acp <- data.frame(
componente = paste0("CP", seq_along(autovalores_acp)),
autovalor = autovalores_acp,
varianza_porcentaje = porcentaje_varianza_acp,
varianza_acumulada = varianza_acumulada_acp,
retenido = seq_along(autovalores_acp) <= n_componentes,
stringsAsFactors = FALSE
)
cargas_acp <- modelo_acp$rotation
contribuciones_acp <- sweep(
cargas_acp^2, 2, colSums(cargas_acp^2), "/"
) * 100
componentes_dominantes <- do.call(
rbind,
lapply(seq_len(n_componentes), function(j) {
orden <- order(abs(cargas_acp[, j]), decreasing = TRUE)
seleccion <- head(orden, min(3L, length(orden)))
data.frame(
componente = paste0("CP", j),
variable = rownames(cargas_acp)[seleccion],
carga = cargas_acp[seleccion, j],
contribucion_porcentaje = contribuciones_acp[seleccion, j],
varianza_explicada = porcentaje_varianza_acp[j],
stringsAsFactors = FALSE
)
})
)
tabla_varianza_acp
write.csv(
tabla_varianza_acp,
file.path(carpeta_modelos, "01_varianza_acp.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
componentes_dominantes
write.csv(
componentes_dominantes,
file.path(carpeta_modelos, "02_componentes_dominantes.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
# Grafico de varianza individual y acumulada.
grafico_varianza_acp <- ggplot2::ggplot(
tabla_varianza_acp,
ggplot2::aes(x = componente)
) +
ggplot2::geom_col(
ggplot2::aes(y = varianza_porcentaje, fill = retenido),
width = 0.66, alpha = 0.88,
colour = "#5A5266", linewidth = 0.25
) +
ggplot2::geom_line(
ggplot2::aes(y = varianza_acumulada, group = 1),
colour = "#6D597A", linewidth = 0.85
) +
ggplot2::geom_point(
ggplot2::aes(y = varianza_acumulada),
colour = "#6D597A", size = 2.1
) +
ggplot2::geom_hline(
yintercept = 80, colour = "#E76F51",
linetype = "dashed", linewidth = 0.7
) +
ggplot2::geom_text(
ggplot2::aes(
y = varianza_porcentaje,
label = paste0(round(varianza_porcentaje, 1), " %")
),
vjust = -0.35, size = 3.0, colour = "#4D4044"
) +
ggplot2::scale_fill_manual(
values = c(`TRUE` = "#B8C0FF", `FALSE` = "#D8E2DC")
) +
ggplot2::scale_y_continuous(
limits = c(0, 105), breaks = seq(0, 100, 20),
expand = ggplot2::expansion(mult = c(0, 0.03))
) +
ggplot2::labs(
title = "Varianza explicada por los componentes principales",
subtitle = paste0(
"Se retienen ", n_componentes, " componentes con ",
round(varianza_acumulada_acp[n_componentes], 2),
" % de varianza acumulada"
),
caption = "Barras: varianza individual | Linea: acumulada | Referencia: 80 %",
x = "Componente principal",
y = "Varianza explicada (%)",
fill = NULL
) +
tema_modelos +
ggplot2::theme(legend.position = "none")
print(grafico_varianza_acp)
# Plano de propiedades en CP1 y CP2. La muestra se usa solo para visualizar.
set.seed(2026)
filas_muestra_acp <- sample(
seq_len(nrow(modelo_acp$x)),
min(2000L, nrow(modelo_acp$x)),
replace = FALSE
)
datos_individuos_acp <- data.frame(
CP1 = modelo_acp$x[filas_muestra_acp, 1],
CP2 = modelo_acp$x[filas_muestra_acp, 2]
)
grafico_individuos_acp <- ggplot2::ggplot(
datos_individuos_acp,
ggplot2::aes(x = CP1, y = CP2)
) +
ggplot2::geom_point(colour = "#023E8A", alpha = 0.8, size = 1.0) +
ggplot2::geom_hline(
yintercept = 0, linetype = "dashed", colour = "#777777"
) +
ggplot2::geom_vline(
xintercept = 0, linetype = "dashed", colour = "#777777"
) +
ggplot2::labs(
title = "Estructura de las viviendas en el plano del ACP",
subtitle = paste0(
"CP1 = ", round(porcentaje_varianza_acp[1], 1),
" % | CP2 = ", round(porcentaje_varianza_acp[2], 1),
" % | Muestra visual: ", nrow(datos_individuos_acp)
),
caption = "Puntos proximos representan perfiles cuantitativos semejantes.",
x = paste0("CP1 (", round(porcentaje_varianza_acp[1], 1), " %)"),
y = paste0("CP2 (", round(porcentaje_varianza_acp[2], 1), " %)")
) +
tema_modelos
print(grafico_individuos_acp)
# Cargas factoriales de CP1 y CP2.
datos_cargas <- rbind(
data.frame(
variable = rownames(cargas_acp), componente = "CP1",
carga = cargas_acp[, 1], stringsAsFactors = FALSE
),
data.frame(
variable = rownames(cargas_acp), componente = "CP2",
carga = cargas_acp[, 2], stringsAsFactors = FALSE
)
)
datos_cargas$signo <- ifelse(
datos_cargas$carga >= 0, "Positiva", "Negativa"
)
grafico_cargas_acp <- ggplot2::ggplot(
datos_cargas,
ggplot2::aes(x = carga, y = reorder(variable, carga), fill = signo)
) +
ggplot2::geom_col(alpha = 0.85, width = 0.68) +
ggplot2::geom_vline(xintercept = 0, colour = "#555555", linewidth = 0.4) +
ggplot2::facet_wrap(~componente, ncol = 2) +
ggplot2::scale_fill_manual(
values = c("Positiva" = "#A9DEF9", "Negativa" = "#FFB4A2")
) +
ggplot2::labs(
title = "Cargas de las variables en CP1 y CP2",
subtitle = "Las cargas de mayor valor absoluto caracterizan mas cada componente",
x = "Carga factorial", y = NULL, fill = NULL
) +
tema_modelos
print(grafico_cargas_acp)
cat("\nRESULTADOS DEL ACP\n")
cat("Variables:", paste(names(datos_acp), collapse = ", "), "\n")
cat("Componentes retenidos:", n_componentes, "\n")
cat("Varianza acumulada:",
round(varianza_acumulada_acp[n_componentes], 2), "%\n")
print(componentes_dominantes)
# ==============================================================================
# 3. ANALISIS DE CONGLOMERADOS
# ==============================================================================
# Objetivo: agrupar propiedades en segmentos homogeneos.
# Se utilizan los componentes retenidos para reducir redundancia.
# El numero de grupos se selecciona con el indice Calinski-Harabasz.
# ==============================================================================
puntuaciones_cluster <- modelo_acp$x[
, seq_len(n_componentes), drop = FALSE
]
k_maximo <- min(8L, nrow(puntuaciones_cluster) - 1L)
if (k_maximo < 2L) {
stop("No existen suficientes registros para conglomerados.", call. = FALSE)
}
k_candidatos <- 2:k_maximo
resultados_k <- data.frame(
k = integer(0), suma_intra = numeric(0), suma_entre = numeric(0),
proporcion_separada = numeric(0),
indice_calinski_harabasz = numeric(0),
stringsAsFactors = FALSE
)
modelos_k <- vector("list", length(k_candidatos))
names(modelos_k) <- as.character(k_candidatos)
for (k_actual in k_candidatos) {
set.seed(2026 + k_actual)
modelo_actual <- stats::kmeans(
puntuaciones_cluster,
centers = k_actual,
nstart = 50,
iter.max = 100
)
indice_ch <-
(modelo_actual$betweenss / (k_actual - 1)) /
(modelo_actual$tot.withinss /
(nrow(puntuaciones_cluster) - k_actual))
resultados_k <- rbind(
resultados_k,
data.frame(
k = k_actual,
suma_intra = modelo_actual$tot.withinss,
suma_entre = modelo_actual$betweenss,
proporcion_separada =
100 * modelo_actual$betweenss / modelo_actual$totss,
indice_calinski_harabasz = indice_ch,
stringsAsFactors = FALSE
)
)
modelos_k[[as.character(k_actual)]] <- modelo_actual
}
k_optimo <- resultados_k$k[
which.max(resultados_k$indice_calinski_harabasz)
]
modelo_cluster <- modelos_k[[as.character(k_optimo)]]
vivienda_resultados <- vivienda_limpia
vivienda_resultados$conglomerado <- factor(
modelo_cluster$cluster,
levels = seq_len(k_optimo),
labels = paste0("Conglomerado ", seq_len(k_optimo))
)
resultados_k
write.csv(
resultados_k,
file.path(carpeta_modelos, "03_indicadores_conglomerados.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
grafico_seleccion_k <- ggplot2::ggplot(
resultados_k,
ggplot2::aes(x = k, y = indice_calinski_harabasz)
) +
ggplot2::geom_line(colour = "#6D597A", linewidth = 0.85) +
ggplot2::geom_point(
colour = "#6D597A", fill = "#CDB4DB", shape = 21, size = 3.0
) +
ggplot2::geom_vline(
xintercept = k_optimo, colour = "#E76F51",
linetype = "dashed", linewidth = 0.75
) +
ggplot2::scale_x_continuous(breaks = k_candidatos) +
ggplot2::labs(
title = "Seleccion del numero de conglomerados",
subtitle = paste0(
"Mayor indice Calinski-Harabasz con k = ", k_optimo
),
caption = "Valores mayores indican mejor separacion relativa y cohesion interna.",
x = "Numero de conglomerados",
y = "Indice Calinski-Harabasz"
) +
tema_modelos
print(grafico_seleccion_k)
paleta_cluster <- grDevices::colorRampPalette(
colores_pastel_modelos
)(k_optimo)
datos_cluster_grafico <- data.frame(
CP1 = modelo_acp$x[, 1],
CP2 = modelo_acp$x[, 2],
conglomerado = vivienda_resultados$conglomerado
)
set.seed(2026)
filas_muestra_cluster <- sample(
seq_len(nrow(datos_cluster_grafico)),
min(3000L, nrow(datos_cluster_grafico)),
replace = FALSE
)
grafico_conglomerados_acp <- ggplot2::ggplot(
datos_cluster_grafico[filas_muestra_cluster, , drop = FALSE],
ggplot2::aes(x = CP1, y = CP2, colour = conglomerado)
) +
ggplot2::geom_point(alpha = 0.34, size = 1.0) +
ggplot2::scale_colour_manual(values = paleta_cluster) +
ggplot2::labs(
title = "Segmentos inmobiliarios en el espacio del ACP",
subtitle = paste0(
k_optimo, " conglomerados | Muestra visual: ",
length(filas_muestra_cluster), " propiedades"
),
caption = "La clasificacion utiliza todos los componentes retenidos.",
x = paste0("CP1 (", round(porcentaje_varianza_acp[1], 1), " %)"),
y = paste0("CP2 (", round(porcentaje_varianza_acp[2], 1), " %)"),
colour = NULL
) +
tema_modelos
print(grafico_conglomerados_acp)
perfil_medias_cluster <- stats::aggregate(
vivienda_resultados[, names(datos_acp), drop = FALSE],
by = list(conglomerado = vivienda_resultados$conglomerado),
FUN = mean
)
perfil_medianas_cluster <- stats::aggregate(
vivienda_resultados[, names(datos_acp), drop = FALSE],
by = list(conglomerado = vivienda_resultados$conglomerado),
FUN = stats::median
)
tamano_conglomerados <- as.data.frame(
table(vivienda_resultados$conglomerado),
stringsAsFactors = FALSE
)
names(tamano_conglomerados) <- c("conglomerado", "numero_propiedades")
tamano_conglomerados$porcentaje <-
100 * tamano_conglomerados$numero_propiedades /
sum(tamano_conglomerados$numero_propiedades)
moda_segura <- function(x) {
x <- x[!is.na(x)]
if (length(x) == 0L) return(NA_character_)
tabla <- table(x)
names(tabla)[which.max(tabla)]
}
variables_perfil_categorico <- intersect(
c("tipo", "zona", "barrio"), names(vivienda_resultados)
)
perfil_categorico_cluster <- do.call(
rbind,
lapply(levels(vivienda_resultados$conglomerado), function(grupo) {
subconjunto <- vivienda_resultados[
vivienda_resultados$conglomerado == grupo, , drop = FALSE
]
fila <- data.frame(conglomerado = grupo, stringsAsFactors = FALSE)
for (variable in variables_perfil_categorico) {
fila[[variable]] <- moda_segura(subconjunto[[variable]])
}
fila
})
)
tamano_conglomerados
write.csv(
tamano_conglomerados,
file.path(carpeta_modelos, "04_tamano_conglomerados.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
perfil_medias_cluster
write.csv(
perfil_medias_cluster,
file.path(carpeta_modelos, "05_perfil_medias_conglomerados.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
perfil_medianas_cluster
write.csv(
perfil_medianas_cluster,
file.path(carpeta_modelos, "06_perfil_medianas_conglomerados.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
perfil_categorico_cluster
write.csv(
perfil_categorico_cluster,
file.path(carpeta_modelos, "07_perfil_categorico_conglomerados.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
grafico_tamano_cluster <- ggplot2::ggplot(
tamano_conglomerados,
ggplot2::aes(x = conglomerado, y = numero_propiedades, fill = conglomerado)
) +
ggplot2::geom_col(
alpha = 0.88, colour = "#5A5266", linewidth = 0.25
) +
ggplot2::geom_text(
ggplot2::aes(
label = paste0(numero_propiedades, " (", round(porcentaje, 1), " %)")
),
vjust = -0.35, size = 3.3, colour = "#4D4044"
) +
ggplot2::scale_fill_manual(values = paleta_cluster) +
ggplot2::scale_y_continuous(
expand = ggplot2::expansion(mult = c(0, 0.14))
) +
ggplot2::labs(
title = "Tamano y participacion de los segmentos inmobiliarios",
subtitle = paste0("Solucion seleccionada: ", k_optimo, " conglomerados"),
x = "Segmento", y = "Numero de propiedades", fill = NULL
) +
tema_modelos +
ggplot2::theme(
axis.text.x = ggplot2::element_text(angle = 20, hjust = 1),
legend.position = "none"
)
print(grafico_tamano_cluster)
# Mapa relativo sin cartografia base.
if (all(c("longitud", "latitud") %in% names(vivienda_resultados))) {
datos_mapa_cluster <- vivienda_resultados[
is.finite(vivienda_resultados$longitud) &
is.finite(vivienda_resultados$latitud),
c("longitud", "latitud", "conglomerado"),
drop = FALSE
]
if (nrow(datos_mapa_cluster) > 0L) {
grafico_mapa_cluster <- ggplot2::ggplot(
datos_mapa_cluster,
ggplot2::aes(x = longitud, y = latitud, colour = conglomerado)
) +
ggplot2::geom_point(alpha = 0.42, size = 1.0) +
ggplot2::scale_colour_manual(values = paleta_cluster) +
ggplot2::coord_equal() +
ggplot2::labs(
title = "Distribucion geografica relativa de los segmentos",
subtitle = "Ubicacion de las propiedades segun longitud y latitud",
caption = "No incorpora cartografia base ni limites administrativos.",
x = "Longitud", y = "Latitud", colour = NULL
) +
tema_modelos
print(grafico_mapa_cluster)
}
}
proporcion_separada_cluster <-
100 * modelo_cluster$betweenss / modelo_cluster$totss
cat("\nRESULTADOS DE CONGLOMERADOS\n")
cat("Variables de origen:", paste(names(datos_acp), collapse = ", "), "\n")
cat("Componentes utilizados:", n_componentes, "\n")
cat("Numero de conglomerados:", k_optimo, "\n")
cat("Variabilidad separada:",
round(proporcion_separada_cluster, 2), "%\n")
print(tamano_conglomerados)
print(perfil_medias_cluster)
print(perfil_categorico_cluster)
# ==============================================================================
# 4. ANALISIS DE CORRESPONDENCIA
# ==============================================================================
# Objetivo: examinar asociaciones entre tipo, zona y barrio.
# Se utiliza correspondencia simple mediante valores singulares.
# ==============================================================================
agrupar_categorias <- function(x, max_categorias = 15L) {
x <- as.character(x)
frecuencias <- sort(table(x, useNA = "no"), decreasing = TRUE)
principales <- names(head(frecuencias, max_categorias))
ifelse(x %in% principales, x, "Otros")
}
correspondencia_simple <- function(
datos, variable_fila, variable_columna,
max_filas = 15L, max_columnas = 15L) {
if (!all(c(variable_fila, variable_columna) %in% names(datos))) {
stop("Variables no disponibles para correspondencia.", call. = FALSE)
}
fila <- agrupar_categorias(datos[[variable_fila]], max_filas)
columna <- agrupar_categorias(datos[[variable_columna]], max_columnas)
tabla <- table(fila, columna)
tabla <- tabla[rowSums(tabla) > 0, colSums(tabla) > 0, drop = FALSE]
if (nrow(tabla) < 2L || ncol(tabla) < 2L) {
stop(
paste0(
"La tabla ", variable_fila, " x ", variable_columna,
" no tiene dimension suficiente."
),
call. = FALSE
)
}
prueba <- suppressWarnings(stats::chisq.test(tabla, correct = FALSE))
n_total <- sum(tabla)
v_cramer <- sqrt(
as.numeric(prueba$statistic) /
(n_total * min(nrow(tabla) - 1, ncol(tabla) - 1))
)
proporciones <- tabla / n_total
masas_fila <- rowSums(proporciones)
masas_columna <- colSums(proporciones)
residuos <-
diag(1 / sqrt(masas_fila)) %*%
(proporciones - outer(masas_fila, masas_columna)) %*%
diag(1 / sqrt(masas_columna))
descomposicion <- svd(residuos)
autovalores <- descomposicion$d^2
porcentaje_inercia <- 100 * autovalores / sum(autovalores)
numero_dimensiones <- min(
2L, length(descomposicion$d),
nrow(tabla) - 1L, ncol(tabla) - 1L
)
coordenadas_fila <-
diag(1 / sqrt(masas_fila)) %*%
descomposicion$u[, seq_len(numero_dimensiones), drop = FALSE] %*%
diag(
descomposicion$d[seq_len(numero_dimensiones)],
nrow = numero_dimensiones
)
coordenadas_columna <-
diag(1 / sqrt(masas_columna)) %*%
descomposicion$v[, seq_len(numero_dimensiones), drop = FALSE] %*%
diag(
descomposicion$d[seq_len(numero_dimensiones)],
nrow = numero_dimensiones
)
if (numero_dimensiones == 1L) {
coordenadas_fila <- cbind(coordenadas_fila, 0)
coordenadas_columna <- cbind(coordenadas_columna, 0)
porcentaje_inercia <- c(porcentaje_inercia[1], 0)
}
coordenadas <- rbind(
data.frame(
categoria = rownames(tabla),
dimension_1 = coordenadas_fila[, 1],
dimension_2 = coordenadas_fila[, 2],
tipo = variable_fila,
stringsAsFactors = FALSE
),
data.frame(
categoria = colnames(tabla),
dimension_1 = coordenadas_columna[, 1],
dimension_2 = coordenadas_columna[, 2],
tipo = variable_columna,
stringsAsFactors = FALSE
)
)
resumen <- data.frame(
analisis = paste(variable_fila, "x", variable_columna),
chi_cuadrado = as.numeric(prueba$statistic),
grados_libertad = as.numeric(prueba$parameter),
valor_p = as.numeric(prueba$p.value),
v_cramer = v_cramer,
inercia_dimension_1 = porcentaje_inercia[1],
inercia_dimension_2 = porcentaje_inercia[2],
stringsAsFactors = FALSE
)
list(
tabla = tabla,
resumen = resumen,
coordenadas = coordenadas,
porcentaje_inercia = porcentaje_inercia
)
}
variables_correspondencia <- c("tipo", "zona", "barrio")
if (!all(variables_correspondencia %in% names(vivienda_limpia))) {
stop("No estan disponibles tipo, zona y barrio para correspondencia.",
call. = FALSE)
}
pares_correspondencia <- list(
c("tipo", "zona"),
c("tipo", "barrio"),
c("zona", "barrio")
)
resultados_correspondencia <- list()
graficos_correspondencia <- list()
resumen_correspondencias <- data.frame()
for (par_actual in pares_correspondencia) {
nombre <- paste(par_actual, collapse = "_")
resultado <- correspondencia_simple(
vivienda_limpia,
variable_fila = par_actual[1],
variable_columna = par_actual[2],
max_filas = if (par_actual[1] == "barrio") 15L else 20L,
max_columnas = if (par_actual[2] == "barrio") 15L else 20L
)
resultados_correspondencia[[nombre]] <- resultado
resumen_correspondencias <- rbind(
resumen_correspondencias, resultado$resumen
)
grafico_actual <- ggplot2::ggplot(
resultado$coordenadas,
ggplot2::aes(
x = dimension_1, y = dimension_2,
colour = tipo, shape = tipo
)
) +
ggplot2::geom_hline(
yintercept = 0, linetype = "dashed",
colour = "#999999", linewidth = 0.4
) +
ggplot2::geom_vline(
xintercept = 0, linetype = "dashed",
colour = "#999999", linewidth = 0.4
) +
ggplot2::geom_point(size = 2.8, alpha = 0.82) +
ggplot2::geom_text(
ggplot2::aes(label = categoria),
size = 3.0, vjust = -0.7,
check_overlap = TRUE, show.legend = FALSE
) +
ggplot2::scale_colour_manual(values = c("#86BBD8", "#F4A7A1")) +
ggplot2::labs(
title = paste0(
"Correspondencia: ", par_actual[1], " y ", par_actual[2]
),
subtitle = paste0(
"Chi-cuadrado = ", round(resultado$resumen$chi_cuadrado, 2),
" | p = ", format.pval(resultado$resumen$valor_p, digits = 3),
" | V de Cramer = ", round(resultado$resumen$v_cramer, 3)
),
caption = paste0(
"Categorias proximas presentan perfiles semejantes. ",
"'Otros' agrupa categorias poco frecuentes."
),
x = paste0(
"Dimension 1 (", round(resultado$porcentaje_inercia[1], 1), " %)"
),
y = paste0(
"Dimension 2 (", round(resultado$porcentaje_inercia[2], 1), " %)"
),
colour = NULL, shape = NULL
) +
tema_modelos
graficos_correspondencia[[nombre]] <- grafico_actual
print(grafico_actual)
}
resumen_correspondencias
write.csv(
resumen_correspondencias,
file.path(carpeta_modelos, "08_resumen_correspondencias.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
clasificar_cramer <- function(v) {
if (!is.finite(v)) return("no disponible")
if (v < 0.10) return("muy debil")
if (v < 0.30) return("debil")
if (v < 0.50) return("moderada")
"alta"
}
cat("\nRESULTADOS DE CORRESPONDENCIA\n")
cat("Variables: tipo, zona y barrio\n")
print(resumen_correspondencias)
for (i in seq_len(nrow(resumen_correspondencias))) {
fila <- resumen_correspondencias[i, ]
conclusion <- if (fila$valor_p < 0.05) {
"se rechaza la hipotesis de independencia"
} else {
"no se rechaza la hipotesis de independencia"
}
cat(
"-", fila$analisis, ":", conclusion,
"al 5 %. Intensidad", clasificar_cramer(fila$v_cramer),
"(V =", round(fila$v_cramer, 3), ").\n"
)
}
# ==============================================================================
# 5. BASE DE RESULTADOS E INTERPRETACION EJECUTIVA
# ==============================================================================
componentes_retenidos <- as.data.frame(
modelo_acp$x[, seq_len(n_componentes), drop = FALSE]
)
names(componentes_retenidos) <- paste0("CP", seq_len(n_componentes))
base_resultados_modelos <- cbind(
vivienda_resultados,
componentes_retenidos
)
base_resultados_modelos
write.csv(
base_resultados_modelos,
file.path(carpeta_modelos, "09_base_resultados_modelos.csv"),
row.names = FALSE,
fileEncoding = "UTF-8"
)
base_resultados_modelos
saveRDS(
base_resultados_modelos,
file.path(carpeta_modelos, "09_base_resultados_modelos.rds")
)
archivo_interpretacion_modelos <- file.path(
carpeta_modelos,
"10_interpretacion_ejecutiva_modelos.txt"
)
texto_interpretacion <- c(
"ANALISIS HOLISTICO DEL MERCADO INMOBILIARIO URBANO",
"=================================================",
"",
"1. ANALISIS DE COMPONENTES PRINCIPALES",
paste0("Variables: ", paste(names(datos_acp), collapse = ", "), "."),
paste0(
"Se retuvieron ", n_componentes, " componentes que explican ",
round(varianza_acumulada_acp[n_componentes], 2),
" % de la variabilidad cuantitativa."
),
"Las cargas de mayor valor absoluto identifican las variables que mas caracterizan cada componente.",
"El ACP describe asociaciones; no demuestra causalidad sobre el precio.",
"",
"2. ANALISIS DE CONGLOMERADOS",
paste0(
"Se seleccionaron ", k_optimo, " conglomerados. La particion separa ",
round(proporcion_separada_cluster, 2),
" % de la variabilidad total de los componentes retenidos."
),
"Los perfiles numericos, categoricos y geograficos permiten caracterizar los segmentos.",
"Los nombres comerciales de los segmentos deben validarse con conocimiento del negocio.",
"",
"3. ANALISIS DE CORRESPONDENCIA",
"Se evaluaron tipo-zona, tipo-barrio y zona-barrio.",
"El valor p evalua independencia y V de Cramer resume intensidad de asociacion.",
"La proximidad en los mapas es descriptiva y no implica causalidad.",
"",
"4. APLICACION ESTRATEGICA",
"El analisis permite resumir la oferta, segmentar propiedades y reconocer patrones territoriales y tipologicos.",
"Los resultados pueden apoyar priorizacion de inversiones, comercializacion diferenciada y valoracion contextual.",
"Las decisiones financieras deben complementarse con costos, rentabilidad, riesgo y temporalidad, datos no incluidos en esta base."
)
writeLines(texto_interpretacion, archivo_interpretacion_modelos,
useBytes = TRUE)
# ==============================================================================
# 6. VERIFICACIONES FINALES
# ==============================================================================
stopifnot(
sum(is.na(vivienda_limpia)) == 0L,
nrow(base_resultados_modelos) == nrow(vivienda_limpia),
nrow(modelo_acp$x) == nrow(vivienda_limpia),
length(modelo_cluster$cluster) == nrow(vivienda_limpia),
all(c("tipo", "zona", "barrio") %in% names(vivienda_limpia))
)
cat("\n============================================================\n")
cat("ANALISIS HOLISTICO FINALIZADO\n")
cat("============================================================\n")
cat("Base utilizada: vivienda_limpia\n")
cat("Registros:", nrow(vivienda_limpia), "\n")
cat("Variables ACP:", paste(names(datos_acp), collapse = ", "), "\n")
cat("Componentes retenidos:", n_componentes, "\n")
cat("Varianza acumulada:",
round(varianza_acumulada_acp[n_componentes], 2), "%\n")
cat("Conglomerados:", k_optimo, "\n")
cat("Variabilidad separada:",
round(proporcion_separada_cluster, 2), "%\n")
cat("Correspondencias evaluadas:", nrow(resumen_correspondencias), "\n")
cat("Resultados:", carpeta_modelos, "\n")
cat("Interpretacion:", archivo_interpretacion_modelos, "\n")
cat("\nObjetos graficos disponibles en Plots:\n")
cat("- grafico_varianza_acp\n")
cat("- grafico_individuos_acp\n")
cat("- grafico_cargas_acp\n")
cat("- grafico_seleccion_k\n")
cat("- grafico_conglomerados_acp\n")
cat("- grafico_tamano_cluster\n")
if (exists("grafico_mapa_cluster")) cat("- grafico_mapa_cluster\n")
cat("- graficos_correspondencia[[\"tipo_zona\"]]\n")
cat("- graficos_correspondencia[[\"tipo_barrio\"]]\n")
cat("- graficos_correspondencia[[\"zona_barrio\"]]\n")
Tabla 25. Dicionario de Datos de Vivienda.
| Variables | Tipo | Valores nulos | Mínimo | Máximo | Valores únicos |
|---|---|---|---|---|---|
| id | numeric | 3 | 1,00000 | 8.319,0000 | 8.320 |
| zona | character | 3 |
|
|
6 |
| piso | character | 2.638 |
|
|
13 |
| estrato | numeric | 3 | 3,00000 | 6,0000 | 5 |
| preciom | numeric | 2 | 58,00000 | 1.999,0000 | 540 |
| areaconst | numeric | 3 | 30,00000 | 1.745,0000 | 653 |
| parqueaderos | numeric | 1.605 | 1,00000 | 10,0000 | 11 |
| banios | numeric | 3 | 0,00000 | 10,0000 | 12 |
| habitaciones | numeric | 3 | 0,00000 | 10,0000 | 12 |
| tipo | character | 3 |
|
|
3 |
| barrio | character | 3 |
|
|
437 |
| longitud | numeric | 3 | -76,58915 | -76,4630 | 2.929 |
| latitud | numeric | 3 | 3,33300 | 3,4977 | 3.680 |
Tabla 26. Componentes Principales.
| Componente | Autovalor | Varianza explicada (%) | Varianza acumulada (%) | Retenido |
|---|---|---|---|---|
| CP1 | 2.9332 | 58.66 | 58.66 | Sí |
| CP2 | 1.1883 | 23.77 | 82.43 | Sí |
| CP3 | 0.4454 | 8.91 | 91.34 | No |
| CP4 | 0.2417 | 4.83 | 96.17 | No |
| CP5 | 0.1915 | 3.83 | 100.00 | No |
Tabla 26. Componentes Principales y Variables segú su contribución.
| Componente | Variable | Carga | Contribución (%) | Varianza explicada (%) | |
|---|---|---|---|---|---|
| banios | CP1 | banios | 0.52 | 26.93 | 58.66 |
| preciom | CP1 | preciom | 0.51 | 25.69 | 58.66 |
| areaconst | CP1 | areaconst | 0.49 | 24.41 | 58.66 |
| estrato | CP2 | estrato | -0.67 | 45.49 | 23.77 |
| habitaciones | CP2 | habitaciones | 0.65 | 42.75 | 23.77 |
| preciom1 | CP2 | preciom | -0.28 | 7.89 | 23.77 |
clasificar_cramer <- function(v) {
if (!is.finite(v)) return("no disponible")
if (v < 0.10) return("muy debil")
if (v < 0.30) return("debil")
if (v < 0.50) return("moderada")
"alta"
}
cat("\nRESULTADOS DE CORRESPONDENCIA\n")
cat("Variables: tipo, zona y barrio\n")
print(resumen_correspondencias)
for (i in seq_len(nrow(resumen_correspondencias))) {
fila <- resumen_correspondencias[i, ]
conclusion <- if (fila$valor_p < 0.05) {
"se rechaza la hipotesis de independencia"
} else {
"no se rechaza la hipotesis de independencia"
}
cat(
"-", fila$analisis, ":", conclusion,
"al 5 %. Intensidad", clasificar_cramer(fila$v_cramer),
"(V =", round(fila$v_cramer, 3), ").\n"
)
}
Tabla 27. Prueba de Independencia CHI-CUADRADO y V DE CRAMER.
| Relación | Decisión estadística | V de Cramer | Intensidad | Interpretación |
|---|---|---|---|---|
| Tipo × Zona | Se rechaza H₀ | 0.288 | Débil | La tipología de vivienda presenta diferencias según la zona, aunque la asociación es limitada. |
| Tipo × Barrio | Se rechaza H₀ | 0.305 | Moderada | Los barrios presentan una relación más marcada con la composición tipológica de la oferta. |
| Zona × Barrio | Se rechaza H₀ | 0.506 | Alta | Existe una fuerte correspondencia territorial entre barrios y zonas. |