¿Cómo se carga la base de datos desde un archivo CSV en R?
# Respuesta:
library(readr)
Inmuebles_Disponibles_Para_La_Venta_20250513<-
read_csv("C:/Users/Sebas/Downloads/Inmuebles_Disponibles_Para_La_Venta_20250513.csv")
A. Analisis Inicial y Limpieza
¿Cuántos registros y columnas tiene el dataset?
dim(Inmuebles_Disponibles_Para_La_Venta_20250513)
## [1] 448 12
¿Qué tipos de datos hay en el dataset (numéricos, categóricos, texto)?
# Mostrar el tipo de cada columna
sapply(Inmuebles_Disponibles_Para_La_Venta_20250513, class)
## Codigo Ciudad Departamento
## "numeric" "character" "character"
## Barrio Direccion Area Terreno
## "character" "character" "numeric"
## Area Construida Detalle Disponibilidad Estrato
## "numeric" "character" "character"
## Precio Tipo de Inmueble Datos Adicionales
## "numeric" "character" "character"
¿Qué columnas tienen valores nulos?
# Columnas con al menos un NA
na_cols <- colSums(is.na(Inmuebles_Disponibles_Para_La_Venta_20250513))
na_cols[na_cols > 0]
## Barrio Datos Adicionales
## 389 371
# Total de NA en todo el dataset
sum(is.na(Inmuebles_Disponibles_Para_La_Venta_20250513))
## [1] 760
¿Que porcentaje Representan?
#Renombramos la base
total_na <- sum(is.na(Inmuebles_Disponibles_Para_La_Venta_20250513))
# Con Prod calculamos el producto de todos los valores valores(se multiplican los valores)
total_valores <- prod(dim(Inmuebles_Disponibles_Para_La_Venta_20250513))# filas × columnas
#Sacamos el porcentaje
porcentaje_total_na <- (total_na / total_valores) * 100
porcentaje_total_na
## [1] 14.1369
¿Existen Registros duplicados?
any(duplicated(Inmuebles_Disponibles_Para_La_Venta_20250513))
## [1] FALSE
¿Hay valores atípicos (outliers) en precios o áreas? (Usar boxplots).
# Boxplots para Precios
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(scales) # para formatear ejes con comas o puntos
## Warning: package 'scales' was built under R version 4.4.3
##
## Adjuntando el paquete: 'scales'
## The following object is masked from 'package:readr':
##
## col_factor
ggplot(Inmuebles_Disponibles_Para_La_Venta_20250513, aes(y = Precio)) +
geom_boxplot(fill = "red", color = "darkred") +
labs(title = "Boxplot de Precio", y = "Precio (COP)") +
scale_y_continuous(labels = label_comma(big.mark = ".", decimal.mark = ",")) +
theme_minimal()
#Boxplot para Area Terreno
library(ggplot2)
library(scales)
ggplot(Inmuebles_Disponibles_Para_La_Venta_20250513, aes(y = `Area Terreno`)) +
geom_boxplot(fill = "green", color = "darkgreen") +
labs(title = "Boxplot de Área Terreno", y = "Área Terreno (m²)") +
scale_y_continuous(labels = label_comma(big.mark = ".", decimal.mark = ",")) +
theme_minimal()
library(ggplot2)
library(scales)
ggplot(Inmuebles_Disponibles_Para_La_Venta_20250513, aes(y = `Area Construida`)) +
geom_boxplot(fill = "skyblue", color = "steelblue") +
labs(title = "Boxplot de Área Construida", y = "Área Construida (m²)") +
scale_y_continuous(labels = label_comma(big.mark = ".", decimal.mark = ",")) +
theme_minimal()
¿Existen errores en categorías (ej: “aparatmento” en lugar de “apartamento”)?
#Variables Categoricas
library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
data.frame(
Variable = names(Inmuebles_Disponibles_Para_La_Venta_20250513),
Tipo = sapply(Inmuebles_Disponibles_Para_La_Venta_20250513, class)
) %>%
filter(Tipo %in% c("factor", "character"))
## Variable Tipo
## Ciudad Ciudad character
## Departamento Departamento character
## Barrio Barrio character
## Direccion Direccion character
## Detalle Disponibilidad Detalle Disponibilidad character
## Estrato Estrato character
## Tipo de Inmueble Tipo de Inmueble character
## Datos Adicionales Datos Adicionales character
#Buscamos posibles errores en las variables categoricas mas importantes
# Vector con las columnas a revisar
cols <- c("Ciudad", "Departamento", "Tipo de Inmueble")
for (col in cols) {
cat("---- Valores únicos en columna:", col, "----\n")
print(sort(unique(Inmuebles_Disponibles_Para_La_Venta_20250513[[col]])))
cat("\n")
}
## ---- Valores únicos en columna: Ciudad ----
## [1] "AGUAZUL" "ANGOSTURA"
## [3] "ARMERO" "BARRANQUILLA"
## [5] "BITUIMA" "BOGOTA"
## [7] "BOLIVAR - CAUCA" "BUGA"
## [9] "CALI" "CALIMA EL DARIEN"
## [11] "CARMEN DE BOLIVAR" "CARTAGENA"
## [13] "CAUCASIA" "CHIA"
## [15] "CUCUTA" "CURITI"
## [17] "DAGUA" "EL AGUILA"
## [19] "EL PLAYON" "EL ROSAL"
## [21] "ENVIGADO" "FUNZA"
## [23] "GIRARDOT" "IBAGUE"
## [25] "LA CALERA" "LA DORADA"
## [27] "LA VIRGINIA" "LOS PATIOS"
## [29] "MADRID" "MANIZALES"
## [31] "MARSELLA" "MEDELLIN"
## [33] "MONTERIA" "PEREIRA"
## [35] "PIEDRAS" "PUERTO LOPEZ"
## [37] "RICAURTE" "SAN ANTONIO DEL TEQUENDAMA"
## [39] "SANTANDER DE QUILICHAO" "SOATA"
## [41] "SOGAMOSO" "TARAZA"
## [43] "TENJO" "TIBU"
## [45] "TURBO" "VILLA RICA"
## [47] "VILLAVICENCIO" "YUMBO"
##
## ---- Valores únicos en columna: Departamento ----
## [1] "ANTIOQUIA" "ATLÁNTICO" "BOLÍVAR"
## [4] "BOYACÁ" "CALDAS" "CASANARE"
## [7] "CAUCA" "CÓRDOBA" "CUNDINAMARCA"
## [10] "META" "NORTE DE SANTANDER" "RISARALDA"
## [13] "SANTANDER" "TOLIMA" "VALLE DEL CAUCA"
##
## ---- Valores únicos en columna: Tipo de Inmueble ----
## [1] "APARTAMENTO" "BODEGA" "CASA"
## [4] "CLINICA" "EDIFICIO" "EDIFICIO VIVIENDA"
## [7] "FINCA" "GARAJE" "HOTEL"
## [10] "LOCAL" "LOTE" "LOTE AGRICOLA"
## [13] "LOTE COMERCIAL" "LOTE CON CONSTRUCCION" "LOTE INDUSTRIAL"
## [16] "LOTE MIXTO" "LOTE NO URBANIZABLE" "LOTE VIVIENDA"
## [19] "OFICINA"
B. Analisis Descriptivo
4.Distribuciones
¿Cómo se distribuyen los precios? ¿Es normal o sesgada? (Histograma + skewness).
# Histograma de los precios
options(scipen = 999)
hist(Inmuebles_Disponibles_Para_La_Venta_20250513$Precio,
main = "Distribución de Precios",
xlab = "Precio",
col = "green",
border = "black",
breaks = 30,
xaxt = "n") # Desactiva eje X automático
# Crear ticks automáticos del eje X
ticks <- axTicks(1)
# Agregar eje X con puntos como separadores de miles
axis(1, at = ticks, labels = format(ticks, big.mark = ".", scientific = FALSE))
## Warning in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L, :
## 'big.mark' y 'decimal.mark' son ambos '.', lo cual puede ser confuso
Skewness
# Instalar y cargar la librería e1071 para skewness
#install.packages("e1071")
library(e1071)
## Warning: package 'e1071' was built under R version 4.4.3
skewness(Inmuebles_Disponibles_Para_La_Venta_20250513$Precio, na.rm = TRUE)
## [1] 7.256093
#La cola es mas larga a la derecha(Asimetria positiva)
¿Qué tipo de inmueble es más común? (Gráfico de barras).
# Gráfico de barras del tipo de inmueble
library(ggplot2)
ggplot(Inmuebles_Disponibles_Para_La_Venta_20250513, aes(x = `Tipo de Inmueble`)) +
geom_bar(fill = "red", color = "blue") +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(title = "Frecuencia de Tipos de Inmueble",
x = "Tipo de Inmueble",
y = "Frecuencia")
Calcular media, mediana, desviación estándar, cuartiles y tablas de frecuencias
Media de los Precios
mean(Inmuebles_Disponibles_Para_La_Venta_20250513$Precio, na.rm = TRUE)
## [1] 9372905838386
Mediana de los Precios
median(Inmuebles_Disponibles_Para_La_Venta_20250513$Precio, na.rm = TRUE)
## [1] 165205000000
Desviación estándar de los precios
sd(Inmuebles_Disponibles_Para_La_Venta_20250513$Precio, na.rm = TRUE)
## [1] 38179638410195
Cuartiles de los precios
quantile(Inmuebles_Disponibles_Para_La_Venta_20250513$Precio, na.rm = TRUE)
## 0% 25% 50% 75% 100%
## 0 125725000000 165205000000 1861440000000 452337898200000
Tablas de frecuencia, ordenadas de mayor a menor
Tipo Inmuebles
sort(table(Inmuebles_Disponibles_Para_La_Venta_20250513$`Tipo de Inmueble`), decreasing = TRUE)
##
## LOCAL LOTE VIVIENDA OFICINA
## 304 38 28
## CASA BODEGA FINCA
## 14 8 8
## LOTE CON CONSTRUCCION LOTE MIXTO APARTAMENTO
## 8 6 5
## LOTE AGRICOLA EDIFICIO LOTE
## 5 4 4
## LOTE INDUSTRIAL CLINICA LOTE COMERCIAL
## 4 3 3
## EDIFICIO VIVIENDA GARAJE HOTEL
## 2 2 1
## LOTE NO URBANIZABLE
## 1
Ciudad
sort(table(Inmuebles_Disponibles_Para_La_Venta_20250513$Ciudad), decreasing = TRUE)
##
## VILLAVICENCIO BOGOTA
## 285 34
## BARRANQUILLA MANIZALES
## 14 13
## PEREIRA CALIMA EL DARIEN
## 12 10
## CUCUTA CALI
## 9 7
## MONTERIA BUGA
## 6 5
## MEDELLIN GIRARDOT
## 5 4
## AGUAZUL CARTAGENA
## 3 3
## ARMERO CHIA
## 2 2
## SAN ANTONIO DEL TEQUENDAMA SANTANDER DE QUILICHAO
## 2 2
## ANGOSTURA BITUIMA
## 1 1
## BOLIVAR - CAUCA CARMEN DE BOLIVAR
## 1 1
## CAUCASIA CURITI
## 1 1
## DAGUA EL AGUILA
## 1 1
## EL PLAYON EL ROSAL
## 1 1
## ENVIGADO FUNZA
## 1 1
## IBAGUE LA CALERA
## 1 1
## LA DORADA LA VIRGINIA
## 1 1
## LOS PATIOS MADRID
## 1 1
## MARSELLA PIEDRAS
## 1 1
## PUERTO LOPEZ RICAURTE
## 1 1
## SOATA SOGAMOSO
## 1 1
## TARAZA TENJO
## 1 1
## TIBU TURBO
## 1 1
## VILLA RICA YUMBO
## 1 1
Departamento
sort(table(Inmuebles_Disponibles_Para_La_Venta_20250513$Departamento), decreasing = TRUE)
##
## META CUNDINAMARCA VALLE DEL CAUCA ATLÁNTICO
## 286 49 25 14
## CALDAS RISARALDA NORTE DE SANTANDER ANTIOQUIA
## 14 14 11 10
## CÓRDOBA BOLÍVAR CAUCA TOLIMA
## 6 4 4 4
## CASANARE BOYACÁ SANTANDER
## 3 2 2
Barrio
sort(table(Inmuebles_Disponibles_Para_La_Venta_20250513$Barrio), decreasing = TRUE)
##
## AV 30 DE AGOSTO SINAI
## 10 10
## VEREDA PALERMO JOSE MARIA CABAL
## 10 4
## PRADOS DEL NORTE CENTRO
## 4 3
## BELLAVISTA CIUDADELA CHIPICHAPE
## 1 1
## CONDOMINIO CAMPESTRE MONACO CORREGIMIENTO EL CARMEN
## 1 1
## EL CENTRO EL HOYO
## 1 1
## EL PRADO GUACANDÁ
## 1 1
## LA CALERA PARQUE IND CAUCADESA
## 1 1
## PARQUE INDUSTRIAL CAUCADESA SANTA MATILDE
## 1 1
## SUBA TINTALA
## 1 1
## VEREDA CHAMBIMBAL VEREDA DE CAMBULAR
## 1 1
## VEREDA FONQUETA VILLA DEL SUR
## 1 1
Estrato
sort(table(Inmuebles_Disponibles_Para_La_Venta_20250513$Estrato), decreasing = TRUE)
##
## COMERCIAL RURAL DOS SEIS TRES CUATRO CINCO
## 321 36 32 18 16 13 8
## INDUSTRIAL UNO
## 3 1
¿Cuál es el precio promedio por estrato? ¿Y por ciudad? (Tablas resumen).
Precio promedio por estrato
library(dplyr)
Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
group_by(Estrato) %>%
summarise(Promedio_Precio = mean(Precio, na.rm = TRUE)) %>%
mutate(Promedio_Precio = format(Promedio_Precio, big.mark = ".", scientific = FALSE)) %>%
arrange(Estrato)
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `Promedio_Precio = format(Promedio_Precio, big.mark = ".",
## scientific = FALSE)`.
## Caused by warning in `prettyNum()`:
## ! 'big.mark' y 'decimal.mark' son ambos '.', lo cual puede ser confuso
## # A tibble: 9 × 2
## Estrato Promedio_Precio
## <chr> <chr>
## 1 CINCO " 15.974.667.112.500"
## 2 COMERCIAL " 4.148.108.896.355"
## 3 CUATRO " 7.842.247.833.700"
## 4 DOS " 13.018.464.040.359"
## 5 INDUSTRIAL "122.124.958.169.933"
## 6 RURAL " 30.753.696.738.056"
## 7 SEIS " 7.057.725.237.767"
## 8 TRES " 38.728.254.529.850"
## 9 UNO " 982.368.000.000"
Precio promedio por ciudad
library(dplyr)
Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
group_by(Ciudad) %>%
summarise(Promedio_Precio = mean(Precio, na.rm = TRUE)) %>%
mutate(Promedio_Precio = format(Promedio_Precio, big.mark = ".", scientific = FALSE)) %>%
arrange(desc(Promedio_Precio))
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `Promedio_Precio = format(Promedio_Precio, big.mark = ".",
## scientific = FALSE)`.
## Caused by warning in `prettyNum()`:
## ! 'big.mark' y 'decimal.mark' son ambos '.', lo cual puede ser confuso
## # A tibble: 48 × 2
## Ciudad Promedio_Precio
## <chr> <chr>
## 1 SOGAMOSO "147.133.144.000.000"
## 2 MADRID "116.565.311.500.000"
## 3 EL ROSAL "109.839.864.000.000"
## 4 RICAURTE "104.073.361.725.000"
## 5 BUGA " 96.470.765.841.600"
## 6 VILLA RICA " 70.903.412.109.800"
## 7 PIEDRAS " 68.451.105.930.000"
## 8 CURITI " 55.248.601.890.000"
## 9 BOGOTA " 52.663.773.505.921"
## 10 GIRARDOT " 43.901.185.791.250"
## # ℹ 38 more rows
C. Analisis Espacial(Geografico)
#Dado que no hay coordenadas, Analizar precios por departamento (mapas coropléticos).
#Dado que no hay coordenadas, analizamos por departamento
#Necesitamos un Shapefile para el analisis
library(sf) # para leer y manejar shapefiles
## Warning: package 'sf' was built under R version 4.4.3
## Linking to GEOS 3.13.0, GDAL 3.10.1, PROJ 9.5.1; sf_use_s2() is TRUE
library(dplyr) # para manipular datos
library(ggplot2) # para graficar
library(scales) # para formatear números en los gráficos
#Cargamos el shapefile
departamentos_sf <- st_read("C:/Users/Sebas/Downloads/gadm41_COL_1.json/gadm41_COL_1.json")
## Reading layer `gadm41_COL_1' from data source
## `C:\Users\Sebas\Downloads\gadm41_COL_1.json\gadm41_COL_1.json'
## using driver `GeoJSON'
## Simple feature collection with 33 features and 11 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: -81.8412 ymin: -4.2284 xmax: -66.8377 ymax: 15.9125
## Geodetic CRS: WGS 84
#Calculamos el precio promedio por ciudad
precios_departamento <- Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
group_by(Departamento) %>%
summarise(Promedio_Precio = mean(Precio, na.rm = TRUE))
#El shapefile y la base Imbuebles tienen nombres diferentes para la columna departamento
#Ajustamos lo nombres para que coincidan en ambas bases
# Nombres de departamentos en el shapefile
unique(departamentos_sf$NAME_1)
## [1] "Amazonas" "Antioquia" "Arauca"
## [4] "Atlántico" "BogotáD.C." "Bolívar"
## [7] "Boyacá" "Caldas" "Caquetá"
## [10] "Casanare" "Cauca" "Cesar"
## [13] "Chocó" "Córdoba" "Cundinamarca"
## [16] "Guainía" "Guaviare" "Huila"
## [19] "LaGuajira" "Magdalena" "Meta"
## [22] "Nariño" "NortedeSantander" "Putumayo"
## [25] "Quindío" "Risaralda" "SanAndrésyProvidencia"
## [28] "Santander" "Sucre" "Tolima"
## [31] "ValledelCauca" "Vaupés" "Vichada"
#Nombres de departamentos en la base Inmuebles
unique(precios_departamento$Departamento)
## [1] "ANTIOQUIA" "ATLÁNTICO" "BOLÍVAR"
## [4] "BOYACÁ" "CALDAS" "CASANARE"
## [7] "CAUCA" "CUNDINAMARCA" "CÓRDOBA"
## [10] "META" "NORTE DE SANTANDER" "RISARALDA"
## [13] "SANTANDER" "TOLIMA" "VALLE DEL CAUCA"
#Observamos que hay diferencias en el uso de: Mayusculas, Espacios y Tildes
#Para hacer el join(Unir las bases) correctamente, necesitamos normalizar y limpiar ambos vectores de nombres para que coincidan.
#Pasamos ambas a minusculas
departamentos_sf <- departamentos_sf %>%
mutate(NAME_1 = tolower(NAME_1))
precios_departamento <- precios_departamento %>%
mutate(Departamento = tolower(Departamento))
#Eliminamos las tildes
#install.packages("stringi")
library(stringi)
departamentos_sf <- departamentos_sf %>%
mutate(NAME_1 = stri_trans_general(NAME_1, "Latin-ASCII"))
precios_departamento <- precios_departamento %>%
mutate(Departamento = stri_trans_general(Departamento, "Latin-ASCII"))
#Elimanamos espacios y/o caracteres especiales
departamentos_sf <- departamentos_sf %>%
mutate(NAME_1 = gsub(" ", "", NAME_1)) %>% # eliminar espacios
mutate(NAME_1 = gsub("\\.", "", NAME_1)) # eliminar puntos
precios_departamento <- precios_departamento %>%
mutate(Departamento = gsub(" ", "", Departamento)) %>%
mutate(Departamento = gsub("\\.", "", Departamento))
#Verificamos si coinciden los nombres de los departamentos
unique(departamentos_sf$NAME_1)
## [1] "amazonas" "antioquia" "arauca"
## [4] "atlantico" "bogotadc" "bolivar"
## [7] "boyaca" "caldas" "caqueta"
## [10] "casanare" "cauca" "cesar"
## [13] "choco" "cordoba" "cundinamarca"
## [16] "guainia" "guaviare" "huila"
## [19] "laguajira" "magdalena" "meta"
## [22] "narino" "nortedesantander" "putumayo"
## [25] "quindio" "risaralda" "sanandresyprovidencia"
## [28] "santander" "sucre" "tolima"
## [31] "valledelcauca" "vaupes" "vichada"
unique(precios_departamento$Departamento)
## [1] "antioquia" "atlantico" "bolivar" "boyaca"
## [5] "caldas" "casanare" "cauca" "cundinamarca"
## [9] "cordoba" "meta" "nortedesantander" "risaralda"
## [13] "santander" "tolima" "valledelcauca"
#Ya confirmamos que ambas bases tienen los nombres de los departamentos igual
#Ahora, Unimos las bases
departamentos_mapa <- departamentos_sf %>%
left_join(precios_departamento, by = c("NAME_1" = "Departamento"))
#Creamos un mapa mejor
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.4.3
library(sf)
library(dplyr)
# Definir paleta de colores para los precios
pal <- colorNumeric(palette = "YlOrRd", domain = departamentos_mapa$Promedio_Precio)
# Creamos el mapa
leaflet(departamentos_mapa) %>%
addProviderTiles("CartoDB.Positron") %>%
addPolygons(
fillColor = ~pal(Promedio_Precio),
weight = 1,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.8,
highlight = highlightOptions(
weight = 3,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE
),
label = ~paste0(NAME_1, ": $", format(Promedio_Precio, big.mark = ".", scientific = FALSE)),
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "13px",
direction = "auto"
)
) %>%
addLegend(pal = pal, values = ~Promedio_Precio, opacity = 0.7,
title = "Precio Promedio", position = "bottomright")
## Warning in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L, :
## 'big.mark' y 'decimal.mark' son ambos '.', lo cual puede ser confuso
¿Hay diferencias de precio entre regiones o departamentos? (Boxplot por ciudad).
library(dplyr)
library(scales)
# Calcular resumen estadístico por departamento
resumen_departamento <- Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
group_by(Departamento) %>%
summarise(
N = n(),
Mediana = median(Precio, na.rm = TRUE),
Min = min(Precio, na.rm = TRUE),
Max = max(Precio, na.rm = TRUE)
) %>%
arrange(desc(Mediana))
# Mostrar la tabla con separadores de miles para mejor legibilidad
resumen_departamento %>%
mutate(across(Mediana:Max, ~ comma(.)))
## # A tibble: 15 × 5
## Departamento N Mediana Min Max
## <chr> <int> <chr> <chr> <chr>
## 1 BOYACÁ 2 76,981,516,250,000 6,829,888,500,000 147,133,144,00…
## 2 SANTANDER 2 29,446,428,945,000 3,644,256,000,000 55,248,601,890…
## 3 BOLÍVAR 4 23,355,338,265,000 0 76,590,000,000…
## 4 CUNDINAMARCA 49 14,482,416,000,000 299,400,000,000 328,393,170,35…
## 5 CAUCA 4 10,770,526,430,000 341,715,000,000 70,903,412,109…
## 6 CASANARE 3 8,834,784,000,000 4,298,641,200,000 28,679,755,510…
## 7 VALLE DEL CAUCA 25 8,109,750,100,000 206,080,036,800 452,337,898,20…
## 8 TOLIMA 4 5,555,332,100,000 3,533,589,780,000 68,451,105,930…
## 9 CÓRDOBA 6 5,351,620,000,000 673,191,500,000 14,356,563,410…
## 10 ANTIOQUIA 10 4,356,002,625,000 807,621,000,000 24,581,464,440…
## 11 ATLÁNTICO 14 2,132,057,600,000 1,590,195,200,000 36,673,427,000…
## 12 NORTE DE SANTANDER 11 1,798,350,000,000 1,377,450,000,000 8,980,970,000,…
## 13 RISARALDA 14 693,001,875,000 65,990,400,000 43,343,535,000…
## 14 CALDAS 14 365,760,000,000 335,520,000,000 66,147,000,000…
## 15 META 286 125,725,000,000 69,750,000,000 41,901,550,210…
Boxplot por ciudades
library(dplyr)
library(ggplot2)
library(scales)
# Filtrar ciudades con al menos 10 observaciones
ciudades_con_suficientes_datos <- Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
group_by(Ciudad) %>%
filter(n() >= 10)
# Crear boxplot de precio por ciudad
ggplot(ciudades_con_suficientes_datos, aes(x = reorder(Ciudad, Precio, FUN = median), y = Precio)) +
geom_boxplot(fill = "skyblue", outlier.color = "red", outlier.shape = 1) +
scale_y_continuous(labels = comma) +
labs(title = "Distribución del Precio por Ciudad",
x = "Ciudad",
y = "Precio (COP)") +
coord_flip() +
theme_minimal()
¿Cómo varía el precio por m² en barrios de alto estrato?
# Contamos cuántos registros hay en estratos altos (CINCO y SEIS)
Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
filter(Estrato %in% c("CINCO", "SEIS")) %>%
summarise(
total_registros = n(),
con_area_construida = sum(`Area Construida` > 0, na.rm = TRUE),
con_area_terreno = sum(`Area Terreno` > 0, na.rm = TRUE)
)
## # A tibble: 1 × 3
## total_registros con_area_construida con_area_terreno
## <int> <int> <int>
## 1 26 0 0
No se puede calcular el precio por metro cuadrado en barrios de estrato alto (CINCO y SEIS) porque no hay datos válidos de área construida ni de área terreno; todos los registros tienen estas áreas en cero, lo que impide el análisis.
D. Relaciones entre Variables
¿Qué variables numéricas correlacionan más con el precio? (Matriz de correlación).
# Mostrar los nombres de las columnas numéricas
names(select_if(Inmuebles_Disponibles_Para_La_Venta_20250513, is.numeric))
## [1] "Codigo" "Area Terreno" "Area Construida" "Precio"
# Cargar librerías necesarias
library(dplyr)
library(corrplot)
## Warning: package 'corrplot' was built under R version 4.4.3
## corrplot 0.95 loaded
# Seleccionar las variables numéricas relevantes
df_num <- Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
select(Precio, `Area Terreno`, `Area Construida`) %>%
filter(!is.na(Precio), !is.na(`Area Terreno`), !is.na(`Area Construida`))
# Calcular la matriz de correlación
cor_mat <- cor(df_num, use = "complete.obs")
# Mostrar matriz de correlación en consola
print(cor_mat)
## Precio Area Terreno Area Construida
## Precio 1.0000000 0.4701345 0.5621413
## Area Terreno 0.4701345 1.0000000 0.6840462
## Area Construida 0.5621413 0.6840462 1.0000000
Grafica
# Graficar la matriz de correlación con corrplot
corrplot(cor_mat, method = "color", addCoef.col = "black",
tl.cex = 1, number.cex = 0.8, tl.col = "black",
title = "Matriz de correlación",
mar=c(0,0,1,0))
El área construida influye más que el área de terreno?
Si, la correlación entre precio y área construida es mayor que la correlación entre precio y área terreno
Explicacion:
La correlación entre precio y área construida es fuerte y positiva, lo que indica que a mayor área construida, mayor es el precio del inmueble. Esto es esperado ya que la construcción suele agregar valor directo a la propiedad.
-La correlación entre precio y área del terreno es positiva, pero menor que la de área construida, sugiriendo que aunque el tamaño del terreno influye en el precio, su impacto es menos determinante que el área construida.
-La correlación entre las dos áreas (terreno y construida) también es positiva, lo que refleja que terrenos más grandes tienden a tener construcciones mayores.
¿Cómo se relaciona el precio con el estrato y el tipo de inmueble? (Gráficos de dispersión con facetas).
Primero calculamos las estadisticas clave
library(dplyr)
library(scales) # para la función comma()
resumen <- Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
group_by(Estrato, `Tipo de Inmueble`) %>%
summarise(
n = n(),
Precio_mediana = median(Precio, na.rm = TRUE),
Precio_media = mean(Precio, na.rm = TRUE)
)
## `summarise()` has grouped output by 'Estrato'. You can override using the
## `.groups` argument.
# Con el siguiente codigo muestra con separadores de miles
resumen %>%
mutate(
Precio_mediana = comma(Precio_mediana),
Precio_media = comma(Precio_media)
) %>%
print()
## # A tibble: 50 × 5
## # Groups: Estrato [9]
## Estrato `Tipo de Inmueble` n Precio_mediana Precio_media
## <chr> <chr> <int> <chr> <chr>
## 1 CINCO CASA 5 10,202,150,000,000 16,501,209,060,000
## 2 CINCO CLINICA 1 43,343,535,000,000 43,343,535,000,000
## 3 CINCO LOCAL 1 162,150,000,000 162,150,000,000
## 4 CINCO LOTE VIVIENDA 1 1,785,606,600,000 1,785,606,600,000
## 5 COMERCIAL BODEGA 2 58,282,655,750,000 58,282,655,750,000
## 6 COMERCIAL CASA 2 15,986,362,255,000 15,986,362,255,000
## 7 COMERCIAL CLINICA 2 125,286,522,000,000 125,286,522,000,000
## 8 COMERCIAL EDIFICIO 4 115,376,457,500,000 100,547,179,625,000
## 9 COMERCIAL HOTEL 1 104,073,361,725,000 104,073,361,725,000
## 10 COMERCIAL LOCAL 291 125,725,000,000 358,532,438,711
## # ℹ 40 more rows
Creamos el Gráficos de dispersión con facetas(con los tipo inmuebles mas frecuentes)
library(dplyr)
library(ggplot2)
library(scales)
tipos_interes <- c("LOCAL", "LOTE VIVIENDA", "OFICINA", "CASA")
df_filtrado <- Inmuebles_Disponibles_Para_La_Venta_20250513 %>%
filter(`Tipo de Inmueble` %in% tipos_interes,
!is.na(Precio),
Precio > 0, # elimina precios 0 para escala log
!is.na(Estrato),
Estrato %in% c("UNO", "DOS", "TRES", "CUATRO", "CINCO", "SEIS", "COMERCIAL", "INDUSTRIAL"))
orden_estratos <- c("UNO", "DOS", "TRES", "CUATRO", "CINCO", "SEIS", "COMERCIAL", "INDUSTRIAL")
df_filtrado$Estrato <- factor(df_filtrado$Estrato, levels = orden_estratos)
df_filtrado$`Tipo de Inmueble` <- factor(df_filtrado$`Tipo de Inmueble`, levels = tipos_interes)
ggplot(df_filtrado, aes(x = Estrato, y = Precio, color = `Tipo de Inmueble`)) +
geom_jitter(alpha = 0.6, width = 0.2, size = 1.8) +
scale_y_log10(
labels = label_number(scale_cut = cut_short_scale(), big.mark = ".", decimal.mark = ","),
breaks = scales::trans_breaks("log10", function(x) 10^x),
minor_breaks = NULL
) +
facet_grid(. ~ `Tipo de Inmueble`, scales = "free_x", space = "free_x") +
labs(
title = "Precio vs Estrato según Tipo de Inmueble (escala logarítmica)",
x = "Estrato",
y = "Precio (log escala, abreviado)",
color = "Tipo de Inmueble"
) +
theme_minimal() +
theme(
strip.background = element_rect(fill = "lightgray", color = "black"),
strip.text = element_text(size = 12, face = "bold"),
axis.text.x = element_text(angle = 45, hjust = 1),
panel.spacing.x = unit(1, "lines")
)