1 Contexto

Una empresa inmobiliaria líder en una gran ciudad está buscando comprender en profundidad el mercado de viviendas urbanas para tomar decisiones estratégicas más informadas. La empresa posee una base de datos extensa que contiene información detallada sobre diversas propiedades residenciales disponibles en el mercado.

2 Introducción

La presente investigación tiene como objetivo analizar en profundidad el mercado de viviendas urbanas, utilizando una base de datos proporcionada por el paquete paqueteMODELOS. Este análisis permitirá identificar patrones relevantes, relaciones entre variables, y segmentaciones útiles para la toma de decisiones estratégicas por parte de una empresa inmobiliaria. Se utilizarán herramientas estadísticas modernas que incluyen análisis exploratorio, regresión, técnicas de agrupamiento y visualización de datos.

3 Descripción de la base de datos

Después de realizar un proceso de limpieza de datos (ver Anexos), obtenemos una base depurada con las siguientes características:

tabla_tipos <- data.frame(
  Variable = names(vivienda_limpia),
  Tipo = sapply(vivienda_limpia, function(x) paste(class(x), collapse = "/")),
  Descripción = descripciones,
  row.names = NULL,
  stringsAsFactors = FALSE
)

kable(tabla_tipos, 
      align = "lll", booktabs = TRUE) %>%
  kable_styling(full_width = FALSE, 
                bootstrap_options = c("striped", "hover", "condensed", "responsive"))
Variable Tipo Descripción
id character Identificador único del registro
zona character Zona de la ciudad donde se ubica la vivienda
piso numeric Piso en el que se encuentra el apartamento/ Numero de pisos que tiene la casa
estrato ordered/factor Estrato socioeconómico asignado a la vivienda
preciom numeric Precio de la vivienda en millones de pesos
areaconst numeric Área construida en metros cuadrados
parqueaderos numeric Número de parqueaderos disponibles
banios numeric Número de baños
habitaciones numeric Número de habitaciones
tipo character Tipo de vivienda (apartamento, casa, etc.)
barrio character Nombre del barrio donde se encuentra la propiedad
longitud numeric Longitud geográfica de la ubicación
latitud numeric Latitud geográfica de la ubicación

3.1 Resumen estadístico

vivienda_limpia %>%
  select(where(is.numeric), -longitud, -latitud) %>%
  describe() %>%
  kable(caption = "Estadísticos descriptivos de variables numéricas",
        booktabs = TRUE) %>%
  kable_styling(full_width = FALSE,
                bootstrap_options = c("striped", "hover", "condensed", "responsive"))
Estadísticos descriptivos de variables numéricas
vars n mean sd median trimmed mad min max range skew kurtosis se
piso 1 8319 3.535641 2.255105 3 3.173652 1.4826 1 12 11 1.5967990 2.649618 0.0247247
preciom 2 8319 433.904436 328.665025 330 374.478594 207.5640 58 1999 1941 1.8490675 3.671372 3.6034453
areaconst 3 8319 174.934938 142.964126 123 149.152171 84.5082 30 1745 1715 2.6933603 12.913820 1.5674421
parqueaderos 4 8319 1.762471 1.044838 2 1.558810 1.4826 1 10 9 2.5006188 9.981324 0.0114555
banios 5 8319 3.111311 1.428210 3 2.985579 1.4826 0 10 10 0.9252097 1.127110 0.0156587
habitaciones 6 8319 3.605361 1.459537 3 3.410245 1.4826 0 10 10 1.6348042 3.984035 0.0160022

3.2 Caracterización de los datos

Esta base contiene dos tipos de vivienda: el 61,3 % corresponde a apartamentos y el 38,7 % a casas. En su mayoría, las casas cuentan con dos pisos, mientras que la mayor parte de los apartamentos se encuentran ubicados en un cuarto piso.

# Definir paleta de colores
colores_tipo <- c("Casa" = "#1f77b4", "Apartamento" = "#ff7f0e")

# Gráfico de pastel 
tipo_data <- vivienda_limpia %>%
  group_by(tipo) %>%
  summarise(total = n()) %>%
  mutate(porcentaje = total / sum(total) * 100,
         etiqueta = paste0(tipo, " (", round(porcentaje, 1), "%)"))

g1 <- ggplot(tipo_data, aes(x = "", y = total, fill = tipo)) +
  geom_col(width = 1, color = "white") +
  coord_polar(theta = "y") +
  labs(title = "Distribución por tipo de vivienda") +
  theme_void() +
  geom_text(aes(label = etiqueta), position = position_stack(vjust = 0.5)) +
  scale_fill_manual(values = colores_tipo)

# Gráfico de número de pisos por tipo de vivienda
vivienda_limpia$piso <- as.numeric(vivienda_limpia$piso)

g2 <- vivienda_limpia %>%
  filter(!is.na(piso)) %>%
  count(tipo, piso) %>%
  ggplot(aes(x = factor(piso), y = n, fill = tipo)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Cantidad de viviendas por número de pisos y tipo",
       x = "Número de pisos", y = "Cantidad") +
  theme_minimal() +
  scale_fill_manual(values = colores_tipo)

# Mostrar juntos
g1 + g2

La mayoría de las viviendas se encuentran ubicadas en la zona sur de la ciudad, especialmente en los barrios Valle del Lili y Ciudad Jardín, y en su mayoría pertenecen al estrato 5.

# Definir colores
colores_tipo <- c("Casa" = "#1f77b4", "Apartamento" = "#ff7f0e")

# Gráfico 1: Zona por tipo
g_zona <- vivienda_limpia %>%
  count(zona, tipo) %>%
  ggplot(aes(x = zona, y = n, fill = tipo)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Cantidad de viviendas por zona y tipo",
       x = "Zona", y = "Cantidad") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_fill_manual(values = colores_tipo)

# Gráfico 2: Estrato por tipo
g_estrato <- vivienda_limpia %>%
  count(estrato, tipo) %>%
  ggplot(aes(x = factor(estrato), y = n, fill = tipo)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Cantidad de viviendas por estrato y tipo",
       x = "Estrato", y = "Cantidad") +
  theme_minimal() +
  scale_fill_manual(values = colores_tipo)

# Gráfico 3: Top 20 barrios por tipo (ahora vertical)
g_barrio <- vivienda_limpia %>%
  count(barrio, tipo) %>%
  arrange(desc(n)) %>%
  slice_max(n, n = 20) %>%
  ggplot(aes(x = reorder(barrio, -n), y = n, fill = tipo)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Top 20 combinaciones barrio-tipo",
       x = "Barrio", y = "Cantidad") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_fill_manual(values = colores_tipo)

# Mostrar los tres gráficos
(g_zona + g_estrato) / g_barrio

De manera general, los precios de las viviendas oscilan entre los 50 y los 2.000 millones de pesos. Las casas presentan un precio promedio de 540 millones, mientras que los apartamentos tienen una media de 367 millones.

En cuanto al área construida, los apartamentos cuentan con un promedio de 113 m², mientras que las casas alcanzan, en promedio, los 273 m².

# Definir colores por tipo
colores_tipo <- c("Casa" = "#1f77b4", "Apartamento" = "#ff7f0e")

# Calcular medias por tipo
medias <- vivienda_limpia %>%
  group_by(tipo) %>%
  summarise(
    media_precio = mean(preciom, na.rm = TRUE),
    media_area = mean(areaconst, na.rm = TRUE)
  )

# Gráfico de precios
g_precio <- ggplot(vivienda_limpia, aes(x = preciom, fill = tipo)) +
  geom_histogram(bins = 30, color = "white", alpha = 0.7) +
  geom_vline(data = medias, aes(xintercept = media_precio), color = "red", linetype = "dashed") +
  geom_text(
    data = medias,
    aes(x = media_precio, y = Inf,
        label = paste0("Media: ", round(media_precio, 0), " M")),
    inherit.aes = FALSE,
    vjust = 2,
    hjust = 0,
    color = "red",
    size = 3.5
  ) +
  facet_wrap(~ tipo, scales = "free_y") +
  scale_fill_manual(values = colores_tipo) +
  labs(title = "Distribución del precio por tipo de vivienda",
       x = "Precio (millones)", y = "Frecuencia") +
  theme_minimal()

# Gráfico de área construida
g_area <- ggplot(vivienda_limpia, aes(x = areaconst, fill = tipo)) +
  geom_histogram(bins = 30, color = "white", alpha = 0.7) +
  geom_vline(data = medias, aes(xintercept = media_area), color = "red", linetype = "dashed") +
  geom_text(
    data = medias,
    aes(x = media_area, y = Inf,
        label = paste0("Media: ", round(media_area, 0), " m²")),
    inherit.aes = FALSE,
    vjust = 2,
    hjust = 0,
    color = "red",
    size = 3.5
  ) +
  facet_wrap(~ tipo, scales = "free_y") +
  scale_fill_manual(values = colores_tipo) +
  labs(title = "Distribución del área construida por tipo de vivienda",
       x = "Área construida (m²)", y = "Frecuencia") +
  theme_minimal()

# Mostrar ambos gráficos juntos
g_precio / g_area

En promedio, los apartamentos cuentan con un solo parqueadero, mientras que las casas tienen un promedio de dos por vivienda. En cuanto a las habitaciones, los apartamentos disponen en promedio de tres, mientras que las casas tienen cuatro. Por otro lado, el número de baños en los apartamentos es de aproximadamente 2.5, mientras que las casas cuentan con cerca de cuatro.

# Paleta de colores por tipo
colores_tipo <- c("Casa" = "#1f77b4", "Apartamento" = "#ff7f0e")

# Gráfico de parqueaderos
g_parqueaderos <- ggplot(vivienda_limpia, aes(x = parqueaderos, fill = tipo)) +
  geom_histogram(color = "white", binwidth = 1, alpha = 0.7, boundary = 0) +
  geom_vline(data = vivienda_limpia %>% group_by(tipo) %>% summarise(media = mean(parqueaderos, na.rm = TRUE)),
             aes(xintercept = media), color = "red", linetype = "dashed", linewidth = 1) +
  facet_wrap(~ tipo, scales = "free_y") +
  scale_fill_manual(values = colores_tipo) +
  labs(title = "Distribucion de parqueaderos por tipo de vivienda",
       x = "Cantidad de parqueaderos", y = "Frecuencia") +
  theme_minimal()

# Gráfico de habitaciones
g_habitaciones <- ggplot(vivienda_limpia, aes(x = habitaciones, fill = tipo)) +
  geom_histogram(color = "white", binwidth = 1, alpha = 0.7, boundary = 0) +
  geom_vline(data = vivienda_limpia %>% group_by(tipo) %>% summarise(media = mean(habitaciones, na.rm = TRUE)),
             aes(xintercept = media), color = "red", linetype = "dashed", linewidth = 1) +
  facet_wrap(~ tipo, scales = "free_y") +
  scale_fill_manual(values = colores_tipo) +
  labs(title = "Distribucion de habitaciones por tipo de vivienda",
       x = "Cantidad de habitaciones", y = "Frecuencia") +
  theme_minimal()

# Gráfico de baños
g_banios <- ggplot(vivienda_limpia, aes(x = banios, fill = tipo)) +
  geom_histogram(color = "white", binwidth = 1, alpha = 0.7, boundary = 0) +
  geom_vline(data = vivienda_limpia %>% group_by(tipo) %>% summarise(media = mean(banios, na.rm = TRUE)),
             aes(xintercept = media), color = "red", linetype = "dashed", linewidth = 1) +
  facet_wrap(~ tipo, scales = "free_y") +
  scale_fill_manual(values = colores_tipo) +
  labs(title = "Distribucion de banos por tipo de vivienda",
       x = "Cantidad de banos", y = "Frecuencia") +
  theme_minimal()

# Mostrar las tres gráficas apiladas
g_parqueaderos / g_habitaciones / g_banios

4 Análisis de Componentes Principales (ACP)

El Análisis de Componentes Principales (ACP) es una técnica estadística multivariada que permite reducir la dimensionalidad de un conjunto de variables, conservando la mayor cantidad posible de información. En el contexto inmobiliario urbano, donde las viviendas se describen mediante múltiples variables (área, número de baños, parqueaderos, habitaciones, etc.), el ACP facilita la identificación de patrones subyacentes y las relaciones entre dichas variables.

El ACP nos ayuda a visualizar y comprender la estructura del mercado inmobiliario, destacando las características que más contribuyen a la variabilidad de los datos. Gracias a esta reducción, se simplifican análisis posteriores como la segmentación o la construcción de modelos predictivos, aportando información valiosa para la toma de decisiones estratégicas en cuanto a la valoración y posicionamiento de las propiedades en el mercado.

# Seleccionar variables numéricas para ACP
vars_num <- vivienda_limpia %>%
  select(preciom, areaconst, parqueaderos, banios, habitaciones)

# Ejecutar ACP con escalamiento
acp <- prcomp(vars_num, scale. = TRUE)

# Resumen del ACP
summary(acp)
## Importance of components:
##                           PC1    PC2     PC3     PC4     PC5
## Standard deviation     1.7931 0.9233 0.62738 0.58837 0.43866
## Proportion of Variance 0.6431 0.1705 0.07872 0.06923 0.03848
## Cumulative Proportion  0.6431 0.8136 0.89228 0.96152 1.00000
# Gráfico de varianza explicada (scree plot)
fviz_eig(acp, addlabels = TRUE, ylim = c(0, 60))

# Biplot componentes principales 1 y 2
fviz_pca_biplot(acp,
                repel = TRUE,
                col.ind = "blue",  # color puntos (observaciones)
                col.var = "red",   # color variables
                legend.title = "Variables")

# Matriz de correlación para variables numéricas
corrplot(cor(vars_num), method = "circle", type = "upper", tl.cex = 0.8)

El ACP identificó que con solo dos componentes podemos representar más del 80% de toda la información que tienen las seis variables mencionadas. Es decir, en lugar de analizar seis cosas por separado, podemos observar solo dos sin perder lo importante.

Podemos analiszar estos componentes como dos grandes ejes que agrupan las principales diferencias entre las viviendas:

El primer componente (PC1) resume las diferencias entre viviendas que son más grandes, costosas y con más parqueaderos.

El segundo componente (PC2) nos ayuda a distinguir otras características no explicadas por el primero, como posibles diferencias en número de baños o estrato.

Al realizar esta simplificacion podemos visualizar mejor los datos y detectar patrones, como por ejemplo, qué tipos de viviendas son similares entre sí, lo que nos será útil para el siguiente paso: la segmentación o agrupación por similitud.

5 Análisis de Conglomerados (Clustering)

Una vez realizada la reduccion de informacion, prcedemos a identificar los grupos de viviendas que sean similares entre si. para este proceso utilizaremos la tencina de analisis de conglomerados o clustering.

Mediante esra tecnica lograremos agrupar las viviendas en conjuntos o segmentos basados en las caracteristicas mas relevantes como el tamaño, el numero de habitaciones, baños etc. Lo que buscamos es que las viviendas de un mismo grupo sean lo mas homogeneas entre si. Esto es muy útil porque nos permite:

A continuación, se presentan los resultados del análisis, junto con una visualización que permite observar claramente la conformación de los grupos de viviendas.

#preparar datos

# Tomar los dos primeros componentes principales
componentes <- acp$x[, 1:2]  

# calcular distancias y realizar cluster jerarquico

# Calcular matriz de distancias
distancias <- dist(componentes)

# Aplicar agrupamiento jerárquico
hc <- hclust(distancias, method = "ward.D2")

# Visualizar el dendrograma
plot(hc, labels = FALSE, hang = -1, main = "Dendrograma de viviendas")
rect.hclust(hc, k = 3, border = 2:4)  # Puedes ajustar k = número de grupos

# Asignar los grupos al dataset original
grupos <- cutree(hc, k = 3)  # Cambia k si quieres más o menos grupos
vivienda_limpia$grupo <- as.factor(grupos)


#visualizar grupos
fviz_cluster(list(data = componentes, cluster = grupos),
             geom = "point",
             ellipse.type = "convex",
             palette = "jco",
             ggtheme = theme_minimal(),
             main = "Grupos de viviendas según componentes principales")

5.1 Caracteristicas de los grupos

# Asegúrate de tener una columna llamada 'grupo' que identifique a qué cluster pertenece cada vivienda

# Reorganizamos los datos para graficar
datos_box <- vivienda_limpia %>%
  select(grupo, preciom, areaconst, parqueaderos, banios, habitaciones) %>%
  pivot_longer(cols = -grupo, names_to = "variable", values_to = "valor")

# Creamos los boxplots
ggplot(datos_box, aes(x = grupo, y = valor, fill = grupo)) +
  geom_boxplot() +
  facet_wrap(~variable, scales = "free", ncol = 5) +
  theme_minimal() +
  labs(title = "DistribuciOn de variables por grupo de viviendas",
       x = "Grupo",
       y = "Valor") +
  scale_fill_brewer(palette = "Set2")

# Calcular los promedios
medias_grupo <- vivienda_limpia %>%
  group_by(grupo) %>%
  summarise(across(c(preciom, areaconst, parqueaderos, banios, habitaciones), mean))

# Reorganizamos para graficar
medias_long <- pivot_longer(medias_grupo, -grupo, names_to = "variable", values_to = "media")

# Gráfico de barras
ggplot(medias_long, aes(x = variable, y = media, fill = grupo)) +
  geom_col(position = "dodge") +
  theme_minimal() +
  labs(title = "Promedio de caracteristicas por grupo",
       x = "Variable",
       y = "Promedio") +
  scale_fill_brewer(palette = "Dark2")

En los gráficos anteriores podemos observar cómo se agrupan las viviendas de la ciudad según sus características físicas y económicas.

Grupo 1: Representan las viviendas medianamente amplias con caracteristicas estandar tanto en tamanño como numero de habitaciones y baños.

  • Area construida: mediana moderada (~300 m² aprox), con algunos valores atípicos hacia arriba.

  • Parqueaderos: Tiene en promedio mas parqueaderos que los otros grupos.

  • Baños: cerca de 3–4 baños en promedio.

  • Habitaciones: promedio de 4 habitaciones.
  • Precio: se encuentra en un rango intermedio, por encima del grupo 2 pero debajo del grupo 3.

Grupo 2: Viviendas mas pequeñas y economicas con menos comodidades que los otros grupos. pueden ser los apartamentos o unidades residenciales mas basicas.

  • Area construida: más pequeña (mediana <200 m²).

  • Parqueaderos: menor cantidad, pueden no tener parqueaderos o max 1.

  • Baños: cerca de 2–3 baños en promedio.

  • Habitaciones: promedio de 3 habitaciones.
  • Precio: el mas bajo de los tres grupos

Grupo 3 Viviendas de gran tamaño, probablemente de alta gama o de lujo. Ideales para familias numerosas o personas con alto poder adquisitivo.

  • Area construida: claramente más grande (mediana >400 m²).

  • Parqueaderos: Mayor cantidad, en algunos casos hasta 5 por vivienda.

  • Baños: entre 5 y 6 en promedio.

  • Habitaciones: promedio de 5 habitaciones.
  • Precio: el mas alto de los tres grupos y con mayor dispersion.

Este análisis nos permite entender mejor qué tipo de viviendas existen en la ciudad y cómo se relacionan entre sí. Las gráficas permiten ver claramente las diferencias entre los grupos, lo cual es útil para toma de decisiones urbanas, análisis de precios y segmentación del mercado inmobiliario.

6 Análisis de Correspondencia

Esta técnica nos permite explorar y visualizar la relación entre variables categóricas, facilitando la identificación de patrones entre el tipo de vivienda, el estrato y la zona de la ciudad.

Este análisis es útil para comprender cómo están distribuidos los distintos tipos de vivienda y determinar si ciertos tipos se asocian con determinados estratos socioeconómicos o zonas geográficas.

A continuación, se presentan los resultados mediante gráficos, en los cuales las categorías se ubican en un plano: cuanto más cerca se encuentren entre sí, mayor será la relación entre ellas.

# Crear tabla de contingencia tipo vs estrato
tabla <- table(vivienda_limpia$tipo, vivienda_limpia$estrato)

# Eliminar columnas con ceros (si existen)
tabla_filtrada <- tabla[, colSums(tabla) != 0]

# Realiza el análisis de correspondencia
ca_resultado <- ca(tabla_filtrada)

# Coordenadas de filas (tipos de vivienda)
coord_filas <- data.frame(ca_resultado$rowcoord)
coord_filas$tipo <- rownames(coord_filas)

# Coordenadas de columnas (estratos)
coord_columnas <- data.frame(ca_resultado$colcoord)
coord_columnas$estrato <- rownames(coord_columnas)

# Crear los gráficos individualmente
grafico_tipo <- ggplot(coord_filas, aes(x = Dim1, y = tipo)) +
  geom_point(color = "steelblue", size = 4) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray") +
  ggtitle("Tipos de Vivienda (1D)") +
  theme_minimal()

grafico_estrato <- ggplot(coord_columnas, aes(x = Dim1, y = factor(estrato))) +
  geom_point(color = "darkred", size = 4) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray") +
  ggtitle("Estratos (1D)") +
  theme_minimal()

# Mostrar ambos gráficos uno al lado del otro
grafico_tipo + grafico_estrato

Al aplicar el analisis de correspondencia simple, se genera una sola dimension y esto se debe a que utilizamos para este proceso pocas categorias. por lo tanto si queremos realizar un analisis mas profundo deberiamos tener mas variables categoricas para hacerlos.

7 Conclusiones

La base de datos permitio comprender de forma profunda el mecado de viviendas urbanas en la ciudad, identificando patrones claros de oferta y segmentaciones estrategicas.

En primer lugar, tenemos una caracterizacion descriptiva que reelo que la mayor parte del inventario corresponde a apartamentos, con una concentracion geografica significativa en el sur especialmente en barrios ed estrato 5 como valle de lili o ciudad jardin. las casas aunque menos fecuentes se distinguen por mayor tamano, numero de habitciones y precio promedio mas alto que los apartamentos.

porsteriormente en el analisis de componentes prncipales )ACP), SE DEMOSTRO QUE CON SOLO DOS EJES DE INFORMACION ES POSIBLE EXPLICAR EL 80% DE LA VARIABILIDAD DE LAS CARACTERISTICAS FISICAS Y ECONOCMICAS DE LAS PROPIEDADES. EL PROMER componente sisntetiza el tamaño , precio y numero de parqueaderos, mientras que el segudno recoge diferncias complementarias como baño o estratos. esta simplificacion nos ayuda con la segmentacion.

El Análisis de Conglomerados permitió identificar tres segmentos diferenciados:

  1. Viviendas de tamaño y características estándar, con precios intermedios.

  2. Viviendas más pequeñas y económicas, con menos comodidades, típicas de apartamentos básicos.

  3. Viviendas de gran tamaño y alto precio, asociadas a un mercado de lujo.

Finalmente, el Análisis de Correspondencias evidenció asociaciones entre tipo de vivienda, estrato y localización, aunque con una única dimensión significativa debido a la limitada variedad categórica. Esto confirma que para obtener relaciones más complejas sería recomendable ampliar el número de variables categóricas analizadas.

8 Recomendaciones

9 Anexos

A continuacion se mostraran los codigos utilizados previamente para la limoieza e inputacion de datos faltantes y atipicos.

# librerías necesarias

library(paqueteMODELOS)

library(tidyverse)

library(ggplot2)

library(GGally)

library(cluster)

library(corrplot)

library(skimr)

library(dplyr)

library(summarytools)

library(knitr)

library(DT)

library(kableExtra)

library(psych)

library(corrr)

library(ggcorrplot)

library(patchwork)

library(factoextra)

library(tidyr)

library(FactoMineR)

library(ca)


#DESCRIPCION DE DATOS

##Base de datos

# devtools::install_github(“centromagis/paqueteMODELOS”, force = TRUE)

data(“vivienda”)

datatable(head(vivienda, 20),

options = list(pageLength = 5),

caption = “Primeras 20 observaciones de la base de datos de vivienda”)


#DESCRIPCION DE LOS DATOS iniciales

#TABLA

descripciones <- c(

“Identificador único del registro”,

“Zona de la ciudad donde se ubica la vivienda”,

“Piso en el que se encuentra el apartamento/ Numero de pisos que tiene la casa”,

“Estrato socioeconómico asignado a la vivienda”,

“Precio de la vivienda en millones de pesos”,

“Área construida en metros cuadrados”,

“Número de parqueaderos disponibles”,

“Número de baños”,

“Número de habitaciones”,

“Tipo de vivienda (apartamento, casa, etc.)”,

“Nombre del barrio donde se encuentra la propiedad”,

“Longitud geográfica de la ubicación”,

“Latitud geográfica de la ubicación”

)

tabla_tipos <- data.frame(

Variable = names(vivienda),

Tipo = sapply(vivienda, class),

Descripción = descripciones,

row.names = NULL,

stringsAsFactors = FALSE

)

kable(tabla_tipos,

align = “lll”, booktabs = TRUE) %>%

kable_styling(full_width = FALSE,

bootstrap_options = c(“striped”, “hover”, “condensed”, “responsive”))


#Limpieza y preparación de los datos

##Antes de elaborar cualquier informe, es fundamental conocer nuestras variables y realizar una limpieza adecuada de los datos.

# Calcular duplicados

n_duplicados <- sum(duplicated(vivienda))

# Crear tabla con una fila

tabla_duplicados <- data.frame(

Descripción = “Total de registros duplicados en la base de datos”,

Cantidad = n_duplicados

)

# Mostrar tabla

kable(tabla_duplicados,

align = “lr”, booktabs = TRUE) %>%

kable_styling(full_width = FALSE,

bootstrap_options = c(“striped”, “hover”, “condensed”, “responsive”))


#ELIMINAR DUPLICADOS

##Dado que solo tenemos una fila con valores duplicados, procedemos a eliminarla y a verificar nuevamente que no existan duplicados en el conjunto de datos.

vivienda <- vivienda %>% distinct()


##VERIFICACION DE DUPLICADOS

# Calcular duplicados

n_duplicados <- sum(duplicated(vivienda))

# Crear tabla con una fila

tabla_duplicados <- data.frame(

Descripción = “Total de registros duplicados en la base de datos”,

Cantidad = n_duplicados

)

# Mostrar tabla

kable(tabla_duplicados,

align = “lr”, booktabs = TRUE) %>%

kable_styling(full_width = FALSE,

bootstrap_options = c(“striped”, “hover”, “condensed”, “responsive”))


#Revisar valores faltantes

# Calcular los NA por variable

na_totales <- colSums(is.na(vivienda))

# Convertir en data.frame

tabla_na <- data.frame(

Variable = names(na_totales),

`Total NA` = as.numeric(na_totales)

)

# Mostrar tabla

kable(tabla_na,

align = “lr”, booktabs = TRUE) %>%

kable_styling(full_width = FALSE,

bootstrap_options = c(“striped”, “hover”, “condensed”, “responsive”))


#Según la tabla, podemos observar que las variables piso y parqueaderos son las que presentan el mayor número de valores faltantes. Sin embargo, antes de tratarlos, procederemos a eliminar las dos filas donde el ID es NA y, posteriormente, verificaremos nuevamente la cantidad de datos faltantes.

# Eliminar filas con NA en la variable id

vivienda <- vivienda %>%

filter(!is.na(id))

#Calcular los NA por variable

na_totales <- colSums(is.na(vivienda))

# Convertir en data.frame

tabla_na <- data.frame(

Variable = names(na_totales),

`Total NA` = as.numeric(na_totales)

)

# Mostrar tabla

kable(tabla_na,

align = “lr”, booktabs = TRUE) %>%

kable_styling(full_width = FALSE,

bootstrap_options = c(“striped”, “hover”, “condensed”, “responsive”))


##Faltantes en variable Piso

#Para poder tratar estos valores faltantes debemos conocer como se encuentran distribuidos los numeros de pisos entre apartamentos y casas para saber con que variable debemos rellenar esos faltantes.

# Función para calcular la moda

moda <- function(x) {

ux <- unique(x)

ux[which.max(tabulate(match(x, ux)))]

}

# Calcular mediana y moda por tipo

resumen_pisos <- vivienda %>%

filter(!is.na(piso)) %>%

mutate(piso = as.numeric(as.character(piso)),

tipo_grupo = ifelse(tipo == “Casa”, “Casa”, “Apartamentos”)) %>%

group_by(tipo_grupo) %>%

summarise(

mediana = median(piso, na.rm = TRUE),

moda = moda(piso)

)

resumen_pisos


#para poder tratar estos faltantes en el numero de pisos, vamos a utilizar la mediana ya que es mas robusta y distribuye mejor los datos, evitando sesgos hacia el valor mas comun. ideal cuando se van a realizar modelados.

# Calcular la mediana de piso por tipo

mediana_pisos <- vivienda %>%

filter(tipo %in% c(“Casa”, “Apartamento”)) %>%

mutate(piso = as.numeric(as.character(piso))) %>%

group_by(tipo) %>%

summarise(mediana_piso = median(piso, na.rm = TRUE))

# Imputar NA en piso según la mediana

vivienda_limpia <- vivienda %>%

mutate(piso = as.numeric(as.character(piso))) %>%

mutate(piso = ifelse(

is.na(piso) & tipo == “Casa”,

mediana_pisos$mediana_piso[mediana_pisos$tipo == “Casa”],

piso)) %>%

mutate(piso = ifelse(

is.na(piso) & tipo == “Apartamento”,

mediana_pisos$mediana_piso[mediana_pisos$tipo == “Apartamento”],

piso))


#Verificamos que no se presenten valores con NA

# Crear tabla con conteo de NA solo en la variable ‘piso’

tabla_na_piso <- data.frame(

Variable = “piso”,

`Total NA` = sum(is.na(vivienda_limpia$piso))

)

sum(is.na(vivienda_limpia$piso))


#Faltantes en variable parqueaderos

#CALCULO MODA Y MEDIANA

# Función para calcular la moda

get_moda <- function(x) {

ux <- na.omit(unique(x))

ux[which.max(tabulate(match(x, ux)))]

}

# Calcular mediana y moda de parqueaderos por tipo de vivienda

resumen_parqueaderos <- vivienda_limpia %>%

filter(!is.na(parqueaderos)) %>%

mutate(parqueaderos = as.numeric(as.character(parqueaderos)),

tipo_grupo = ifelse(tipo == “Casa”, “Casa”, “Apartamentos”)) %>%

group_by(tipo_grupo) %>%

summarise(

mediana_parqueaderos = median(parqueaderos, na.rm = TRUE),

moda_parqueaderos = get_moda(parqueaderos)

)

resumen_parqueaderos


# Calcular la mediana de parqueaderos por tipo de vivienda

mediana_parqueaderos <- vivienda_limpia %>%

filter(tipo %in% c(“Casa”, “Apartamento”)) %>%

mutate(parqueaderos = as.numeric(as.character(parqueaderos))) %>%

group_by(tipo) %>%

summarise(mediana_parq = median(parqueaderos, na.rm = TRUE))

# Imputar valores NA en parqueaderos según la mediana por tipo

vivienda_limpia <- vivienda_limpia %>%

mutate(parqueaderos = as.numeric(as.character(parqueaderos))) %>%

mutate(parqueaderos = ifelse(

is.na(parqueaderos) & tipo == “Casa”,

mediana_parqueaderos$mediana_parq[mediana_parqueaderos$tipo == “Casa”],

parqueaderos)) %>%

mutate(parqueaderos = ifelse(

is.na(parqueaderos) & tipo == “Apartamento”,

mediana_parqueaderos$mediana_parq[mediana_parqueaderos$tipo == “Apartamento”],

parqueaderos))


#Verificamos que no se presenten valores con NA

# Crear tabla con conteo de NA solo en la variable ‘parqueaderos’

tabla_na_parqueaderos <- data.frame(

Variable = “parqueaderos”,

`Total NA` = sum(is.na(vivienda_limpia$parqueaderos))

)

sum(is.na(vivienda_limpia$parqueaderos))


# Calcular los NA por variable

na_totales <- colSums(is.na(vivienda_limpia))

# Convertir a data frame

tabla_na_total <- data.frame(

Variable = names(na_totales),

`Total NA` = as.numeric(na_totales)

)

colSums(is.na(vivienda_limpia))


#Valores atipicos casas

vivienda_limpia %>%

filter(tipo == “Casa”) %>%

count(piso) %>%

arrange(piso)


#para este punto no tiene sentido que una casa tenga 5, 6, 7 o hasta 10 pisos por lo tanto se calculara la mediana de los pisos sin estos valores y se realizara la imputacion, no se pueden eliminar pues se podrian perder datos importantes

# Calcular la mediana de pisos en casas con valores entre 1 y 3

mediana_pisos_casa_valida <- vivienda_limpia %>%

filter(tipo == “Casa”, piso %in% 1:3) %>%

pull(piso) %>%

median(na.rm = TRUE)

# Reemplazar los valores sospechosos (5,6,7,10) con la mediana

vivienda_limpia <- vivienda_limpia %>%

mutate(piso = ifelse(

tipo == “Casa” & piso %in% c(5, 6, 7, 10),

mediana_pisos_casa_valida,

piso

))

# Ver conteo de pisos en viviendas tipo Casa después de imputación

table(vivienda_limpia$piso[vivienda_limpia$tipo == “Casa”])


#Transformar variables id y estarto en caracter

vivienda_limpia <- vivienda_limpia %>%

mutate(

id = as.character(id),

estrato = factor(as.character(estrato), levels = as.character(1:6), ordered = TRUE)

)


#FIN DE LIMPIEZA