El siguiente informe realiza un analisis descriptivo de la tabla “Viviendas_faltantes” para la empresa B&C, que busca ayudar en la identificación de tendecias y patrones en los datos que puedan servir en la toma de desiciones del negocio. Este documento se divide en las secciones: Introducción, objetivos, metodos, resultados, discusion, conclusiones.
Realizar el analisis descriptivo de la tabla “viviendas_faltantes” suministrada por la empresa B&C.
Identificar tendencias y patrones en los datos que habiliten la toma de desiciones del negocio.
Este informe realiza un analisis de la información suminsitrda por la empresa B&C, para lo cual se realizan los siguientes pasos: 1) instalación de librerias y paquetes requeridos durante el desarrollo del informe en R y cargue de la información a ser analizada “vivienda_faltantes”, 2) exploración y entendimiento del dataframe, 3) preprocesamiento de datos, 4) analisis univariable y 5) analisis de correlacion entre variables precio, area, zonas y tipo.
Se identifican la estructura de la tabla “Vivienda_faltantes” extrayendo las 6 primeras lineas de la misma y todas sus columnas.
head(vivienda_faltantes)
Notando que la tabla se encuentra conformada por 13 columnas: id, zona, piso, estrato, preciom, areaconst, parquea, banios, habitac, tipo, barrio, longitud y latitud. Se requiere entonces conocer que tipo de información se encuentra almacenada en estas columnas, obteniendo entonces la tabla a continuación.
str(vivienda_faltantes,vec.len=2, digits.d=2, give.attr=FALSE)
## spc_tbl_ [8,330 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8330] 8312 8311 ...
## $ zona : chr [1:8330] "Zona Oeste" "Zona Oeste" ...
## $ piso : num [1:8330] 4 1 NA 2 NA ...
## $ estrato : num [1:8330] 6 6 5 3 5 ...
## $ preciom : num [1:8330] 1300 480 1200 220 330 ...
## $ areaconst: num [1:8330] 318 300 ...
## $ parquea : num [1:8330] 2 1 4 1 2 ...
## $ banios : num [1:8330] 4 4 7 2 4 ...
## $ habitac : num [1:8330] 2 4 5 4 3 ...
## $ tipo : chr [1:8330] "Apartamento" "Casa" ...
## $ barrio : chr [1:8330] "arboleda" "normandía" ...
## $ longitud : num [1:8330] -76576 -76571 ...
## $ latitud : num [1:8330] 3454 3454 ...
Como se pudo observar la información se divide en cadenas de texto y numeros de la siguiente forma:
Adicionalmente se identifica que hay 8330 registros, definiendo que cada registro es una fila de la tabla con 13 atributos que lo componen.
Se requiere concer el dataframe por lo cual a continuación se observa un resumen de estadisticas para cada una de las columnas numericas, excluyendo id, latitud y longitud.
summary(vivienda_faltantes[,c(3,4,5,6,7,8,9)])
## piso estrato preciom areaconst
## Min. : 1.000 Min. :3.000 Min. : 58.0 Min. : 30
## 1st Qu.: 2.000 1st Qu.:4.000 1st Qu.: 220.0 1st Qu.: 80
## Median : 3.000 Median :5.000 Median : 330.0 Median : 123
## Mean : 3.772 Mean :4.634 Mean : 434.2 Mean : 175
## 3rd Qu.: 5.000 3rd Qu.:5.000 3rd Qu.: 540.0 3rd Qu.: 229
## Max. :12.000 Max. :6.000 Max. :1999.0 Max. :1745
## NA's :2641 NA's :3 NA's :2 NA's :3
## parquea banios habitac
## Min. : 1.000 Min. : 0.000 Min. : 0.000
## 1st Qu.: 1.000 1st Qu.: 2.000 1st Qu.: 3.000
## Median : 2.000 Median : 3.000 Median : 3.000
## Mean : 1.836 Mean : 3.112 Mean : 3.605
## 3rd Qu.: 2.000 3rd Qu.: 4.000 3rd Qu.: 4.000
## Max. :10.000 Max. :10.000 Max. :10.000
## NA's :1606 NA's :3 NA's :3
require(psych)
## Loading required package: psych
##
## Attaching package: 'psych'
## The following objects are masked from 'package:ggplot2':
##
## %+%, alpha
describe(vivienda_faltantes[,c(3,4,5,6,7,8,9)])
cv_preciom <-100*sd(vivienda_faltantes$preciom, na.rm=TRUE)/mean(vivienda_faltantes$preciom, na.rm=TRUE)
cat("El coeficiente de variacion del precio es",round(cv_preciom, digits=0))
cv_areaconst <- 100*sd(vivienda_faltantes$areaconst, na.rm=TRUE)/mean(vivienda_faltantes$areaconst, na.rm=TRUE)
cat(" y El coeficiente de variacion del area es",round(cv_areaconst, digits=0))
## El coeficiente de variacion del precio es 76 y El coeficiente de variacion del area es 82
Del resumen anterior tenemos los siguientes resultados:
Durante esta revisión se identifican varios valores nulos en las columnas, por lo cual se preprocesara esta información. En la siguiente matriz se puede visualizar los valores nulos por columnas, identificando que hay lineas/registros con todas las columnas vacias, las cuales pueden ser removidas sin generar afectacion en el analisis, para esto se genera un nuevo dataframe llamada “df”.
md.pattern(vivienda_faltantes, plot=TRUE, rotate.names=TRUE)
## preciom id zona estrato areaconst banios habitac tipo barrio longitud
## 4812 1 1 1 1 1 1 1 1 1 1
## 1912 1 1 1 1 1 1 1 1 1 1
## 877 1 1 1 1 1 1 1 1 1 1
## 726 1 1 1 1 1 1 1 1 1 1
## 1 1 0 0 0 0 0 0 0 0 0
## 2 0 0 0 0 0 0 0 0 0 0
## 2 3 3 3 3 3 3 3 3 3
## latitud parquea piso
## 4812 1 1 1 0
## 1912 1 1 0 1
## 877 1 0 1 1
## 726 1 0 0 2
## 1 0 0 0 12
## 2 0 0 0 13
## 3 1606 2641 4279
df <- vivienda_faltantes[rowSums(is.na(vivienda_faltantes)) != ncol(vivienda_faltantes), ]
Al revisar el nuevo dataframe (df) observamos que existe una fila con dato en una sola columna, debido a que porcentualmente no se espera una alteracion importante en el analisis, esta fila tambien se decide retirar.
md.pattern(df, plot=TRUE, rotate.names=TRUE)
## preciom id zona estrato areaconst banios habitac tipo barrio longitud
## 4812 1 1 1 1 1 1 1 1 1 1
## 1912 1 1 1 1 1 1 1 1 1 1
## 877 1 1 1 1 1 1 1 1 1 1
## 726 1 1 1 1 1 1 1 1 1 1
## 1 1 0 0 0 0 0 0 0 0 0
## 0 1 1 1 1 1 1 1 1 1
## latitud parquea piso
## 4812 1 1 1 0
## 1912 1 1 0 1
## 877 1 0 1 1
## 726 1 0 0 2
## 1 0 0 0 12
## 1 1604 2639 4253
df <- df[-8320,]
md.pattern(df, plot=TRUE, rotate.names=TRUE)
## id zona estrato preciom areaconst banios habitac tipo barrio longitud
## 4812 1 1 1 1 1 1 1 1 1 1
## 1912 1 1 1 1 1 1 1 1 1 1
## 877 1 1 1 1 1 1 1 1 1 1
## 726 1 1 1 1 1 1 1 1 1 1
## 0 0 0 0 0 0 0 0 0 0
## latitud parquea piso
## 4812 1 1 1 0
## 1912 1 1 0 1
## 877 1 0 1 1
## 726 1 0 0 2
## 0 1603 2638 4241
En el siguiente grafico se puede identificar de manera porcentual cuantos valores nulos cada columna del df posee, encontrando que solo parqueaderos y piso poseen información nula/NA.
#install.packages("naniar")
vis_miss(df)
Debido a que tanto parqueaderos como piso tienen un porcentual alto de registros faltantes, 19% y 32% respectivamente, y se desconoce el motivo, se decide continuar con estos valores nulos y no reemplazarlos ya que alterarian fuertemente los analisis a ejecutar (reemplazar por promedio/media/cero u otro valor modificaria los estadisticos ya revisados previamente).
Durante la revisión de datos se identifica que los siguientes atributos: zona/piso/estrato/parquea/banios/habitac/tipo/barrio toman valores categoricos, y el numero de categorias para cada uno se describe a continuación.
sapply(vivienda_faltantes[,c(2:4,7:11)], function(x) n_distinct(x))
## zona piso estrato parquea banios habitac tipo barrio
## 6 13 5 11 12 12 7 437
Teniendo esto como base, analizaremos estas columnas a continuación identificando las categorias y el conteo de datos asociado.
sort(table(df$zona), decreasing = TRUE)
print("Zonas")
sort(table(df$piso), decreasing = TRUE)
print("Piso")
sort(table(df$estrato), decreasing = TRUE)
print("Estrato")
sort(table(df$parquea), decreasing = TRUE)
print("Parqueaderos")
sort(table(df$banios), decreasing = TRUE)
print("Baños")
sort(table(df$habitac), decreasing = TRUE)
print("Habitaciones")
sort(table(df$tipo), decreasing = TRUE)
print("Tipos de vivienda")
##
## Zona Sur Zona Norte Zona Oeste Zona Oriente Zona Centro
## 4726 1922 1204 351 124
## [1] "Zonas"
##
## 2 3 1 4 5 6 8 7 9 10 11 12
## 1450 1097 861 607 568 245 211 207 146 130 84 83
## [1] "Piso"
##
## 5 4 6 3
## 2751 2131 1992 1453
## [1] "Estrato"
##
## 1 2 3 4 5 6 7 8 10 9
## 3156 2478 521 386 68 68 18 17 8 4
## [1] "Parqueaderos"
##
## 2 3 4 5 1 6 7 8 0 9 10
## 2946 1994 1460 891 497 315 107 48 45 15 9
## [1] "Baños"
##
## 3 4 2 5 6 7 8 9 0 1 10
## 4101 1731 927 680 318 173 138 83 66 59 51
## [1] "Habitaciones"
##
## Apartamento Casa APARTAMENTO casa apto CASA
## 5032 3195 61 14 13 12
## [1] "Tipos de vivienda"
barplot(table(df$zona), ylim=c(0,5000), ylab="# viviendas", col=rainbow(5))
barplot(table(df$piso), ylim=c(0,1500), ylab="# viviendas", xlab="Piso de la vivienda", col=rainbow(12))
estratovivienda <- sort(table(df$estrato), decreasing = TRUE)
pie(estratovivienda)
barplot(table(df$parquea), ylim=c(0,3500), ylab="# viviendas", xlab="Parqueaderos por vivienda", col=rainbow(10))
barplot(table(df$banios), ylim=c(0,3500), ylab="# viviendas", xlab="Banios por vivienda", col=rainbow(11))
Del analisis previo de categorias se resalta que:
De esta revisión se identifica que la columna “tipo” presenta 7 categorias sin embargo como se puede observar se podrian subdividir en unicamente dos, Apartamento (Apartamento, APARTAMENTO, apto) y Casa (Casa, casa, CASA). Con el objetivo de realizar un mejor manejo de la información estos 7 campos se homologaran en Apartamento o Casa.
df$tipo[df$tipo=="casa"] <-"Casa"
df$tipo[df$tipo=="CASA"] <-"Casa"
df$tipo[df$tipo=="APARTAMENTO"] <-"Apartamento"
df$tipo[df$tipo=="apto"] <-"Apartamento"
tipovivienda <- sort(table(df$tipo), decreasing = TRUE)
sort(table(df$tipo), decreasing = TRUE)
##
## Apartamento Casa
## 5106 3221
Posterior al análisis individual de las variables, se evalua la interrelacion entre los atributos Precio, Area, tipo y zona, adicionalmente se genera un atributo calculado nuevo el cual se le da el nombre de “precioxm2” con el objetivo de relacionar el precio y area de cada vivienda.
#install.packages("table1")
dfprecio_area_tipo <- na.omit(df[,c(2, 5,6,10)])
dfprecio_area_tipo$precioxm2 <- with(dfprecio_area_tipo, preciom/areaconst)
summary(dfprecio_area_tipo$precioxm2)
cv_precioxm2 <-100*sd(dfprecio_area_tipo$precioxm2, na.rm=TRUE)/mean(dfprecio_area_tipo$precioxm2, na.rm=TRUE)
cat("El coeficiente de variacion del precio es",round(cv_precioxm2, digits=0))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.1461 1.9167 2.6431 2.7230 3.3810 9.4681
## El coeficiente de variacion del precio es 40
El nuevo atributo tiene un coeficiente de variacion del 40% por lo cual se indica heterogeneidad, tambien se encuentra que el precio por metro cuadrado esta entre 0.1461 y 9.4681 Millones/m2, el valor promedio es de 2.723 millones/m2 y el 75% de las viviendas presentan una relacion de precio/m2 igual o inferior a 3.38 Millones/m2.
A continuación se identifica que las casas tienden a tener en promedio un mayor precio de venta y mayores areas, sin embargo el precio promedio por metro cuadrado es menor al de los apartamentos.
table1(~ preciom + areaconst +precioxm2 | tipo, data=dfprecio_area_tipo)
| Apartamento (N=5106) |
Casa (N=3221) |
Overall (N=8327) |
|
|---|---|---|---|
| preciom | |||
| Mean (SD) | 368 (290) | 540 (358) | 434 (329) |
| Median [Min, Max] | 280 [58.0, 1950] | 430 [77.0, 2000] | 330 [58.0, 2000] |
| areaconst | |||
| Mean (SD) | 113 (69.6) | 273 (171) | 175 (143) |
| Median [Min, Max] | 90.0 [35.0, 932] | 240 [30.0, 1750] | 123 [30.0, 1750] |
| precioxm2 | |||
| Mean (SD) | 3.10 (0.985) | 2.12 (0.953) | 2.72 (1.08) |
| Median [Min, Max] | 3.00 [0.281, 9.47] | 1.92 [0.146, 8.05] | 2.64 [0.146, 9.47] |
A continuación se identifica a la zona Oeste como el area con el mayor precio promedio de vivienda apesar de que el area promedio de las zonas Centro y Oriente son cercanas. Esto se ratifica con un mayor precio por metro cuadrado en la Zona oeste frente a las otras.
table1(~ preciom + areaconst +precioxm2 | zona, data=dfprecio_area_tipo)
| Zona Centro (N=124) |
Zona Norte (N=1922) |
Zona Oeste (N=1204) |
Zona Oriente (N=351) |
Zona Sur (N=4726) |
Overall (N=8327) |
|
|---|---|---|---|---|---|---|
| preciom | ||||||
| Mean (SD) | 310 (162) | 346 (241) | 679 (393) | 229 (122) | 427 (323) | 434 (329) |
| Median [Min, Max] | 297 [100, 1100] | 300 [65.0, 1940] | 580 [85.0, 2000] | 210 [58.0, 1350] | 320 [75.0, 1900] | 330 [58.0, 2000] |
| areaconst | ||||||
| Mean (SD) | 194 (110) | 161 (138) | 197 (122) | 192 (157) | 173 (149) | 175 (143) |
| Median [Min, Max] | 160 [52.0, 750] | 107 [30.0, 1440] | 166 [44.0, 1200] | 160 [40.0, 1750] | 113 [40.0, 1600] | 123 [30.0, 1750] |
| precioxm2 | ||||||
| Mean (SD) | 1.75 (0.731) | 2.45 (0.988) | 3.65 (1.23) | 1.44 (0.673) | 2.72 (0.916) | 2.72 (1.08) |
| Median [Min, Max] | 1.53 [0.813, 5.07] | 2.23 [0.257, 9.47] | 3.71 [0.768, 8.30] | 1.32 [0.146, 6.37] | 2.69 [0.281, 8.05] | 2.64 [0.146, 9.47] |
Correlacionando los atributos Zona, tipo, preciom, areaconst y precioxm2 se encuentra que:
table1(~ preciom + areaconst + precioxm2| zona + tipo, data=dfprecio_area_tipo)
Zona Centro |
Zona Norte |
Zona Oeste |
Zona Oriente |
Zona Sur |
Overall |
|||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Apartamento (N=24) |
Casa (N=100) |
Apartamento (N=1199) |
Casa (N=723) |
Apartamento (N=1035) |
Casa (N=169) |
Apartamento (N=62) |
Casa (N=289) |
Apartamento (N=2786) |
Casa (N=1940) |
Apartamento (N=5106) |
Casa (N=3221) |
|
| preciom | ||||||||||||
| Mean (SD) | 187 (90.8) | 339 (162) | 285 (200) | 446 (268) | 669 (391) | 736 (398) | 153 (165) | 245 (104) | 297 (192) | 612 (378) | 368 (290) | 540 (358) |
| Median [Min, Max] | 153 [100, 400] | 310 [148, 1100] | 250 [65.0, 1580] | 390 [89.0, 1940] | 570 [85.0, 1950] | 680 [135, 2000] | 115 [58.0, 1350] | 235 [80.0, 750] | 245 [75.0, 1750] | 480 [77.0, 1900] | 280 [58.0, 1950] | 430 [77.0, 2000] |
| areaconst | ||||||||||||
| Mean (SD) | 95.1 (30.7) | 218 (109) | 98.7 (56.4) | 265 (167) | 173 (89.6) | 343 (181) | 94.2 (64.8) | 213 (163) | 97.5 (52.6) | 282 (173) | 113 (69.6) | 273 (171) |
| Median [Min, Max] | 93.0 [52.0, 155] | 200 [74.0, 750] | 83.0 [35.0, 660] | 240 [30.0, 1440] | 150 [44.0, 550] | 300 [55.0, 1200] | 63.0 [50.0, 320] | 179 [40.0, 1750] | 85.0 [40.0, 932] | 247 [47.0, 1600] | 90.0 [35.0, 932] | 240 [30.0, 1750] |
| precioxm2 | ||||||||||||
| Mean (SD) | 1.95 (0.578) | 1.70 (0.758) | 2.81 (0.939) | 1.85 (0.744) | 3.85 (1.10) | 2.39 (1.24) | 1.70 (0.821) | 1.39 (0.625) | 2.99 (0.784) | 2.34 (0.954) | 3.10 (0.985) | 2.12 (0.953) |
| Median [Min, Max] | 1.84 [1.16, 3.65] | 1.49 [0.813, 5.07] | 2.67 [0.775, 9.47] | 1.67 [0.257, 7.00] | 3.84 [1.10, 8.30] | 2.07 [0.768, 7.80] | 1.58 [0.625, 6.37] | 1.26 [0.146, 4.86] | 2.90 [0.281, 6.41] | 2.17 [0.376, 8.05] | 3.00 [0.281, 9.47] | 1.92 [0.146, 8.05] |
A continuación se observa un grafico donde se realiza regresion lineal a las variables precio y area construida en funcion de la zona. En este se ratifica que la zona oeste tiene una tendencia con una pendiente mas alta lo cual significa que su precio crece con el area a una tasa mayor que el de las otras zonas y por el contrario la zona oriente es la de enor crecimiento.
ggplot(dfprecio_area_tipo, aes(x=areaconst, y=preciom, color=zona)) +
geom_point()+geom_smooth(method=lm)
## `geom_smooth()` using formula = 'y ~ x'
El precio y el area de las viviendas presentan heterogeneidad y esto se debe a que existe variabilidad de estos en funcion del tipo de vivienda, casa/apartamento, y la zona en la cual se encuentra ubicada.
Se identifica que el 75% de las viviendas analizadas presentan: 1 o 2 parqueaderos, 4 o menos baños y 4 o menos habitaciones. indicanto.
Las variables: piso, precio, area, parqueaderos, baños, habitaciones, presentan una curtosis leptocurtica (picos altos) y presentan una asimetria postiva, es decir tienen una mayor tendencia en general a estar cercanos al valor más bajo. Queriendo explicar que las viviendas en su mayoria estaran en los pisos más bajos (5 o menos 3Q), areas pequeñas (229m2 o menos 3Q), un numero bajo de parqueaderos (1o 2), baños (0 a 4, 3Q) y habitaciones (0 a 4, 3Q).
Se debe realizar un analisis posterior más detallado o evaluar con la empresa B& los valores nulos de las variables piso y parqueaderos, ya que su porcentaje son considerablemente altos y pueden afectar la toma de desiciones del negocio.
La zona sur de Cali es el area con mayor numero de viviendas y la zona centro el de meno número.
Si se desea buscar una vivienda con un alto precio por metro cuadrado la zona con mayor proporción y promedio de estos datos se encuentra en la Zona Oeste, por el contrario la zona con menor precio por metro cuadrado es la zona Oriente.
En general para todas las zonas los apartamentos poseen la relación precio por metro cuadrado más alta en promedio, a pesar de que en promedio tienen areas menores comparadas con las casas.
Cada zona de la ciudad aparenta tener una tendencia de relación precio por metro cuadrado distintiva, siendo para la zona oeste la que mayor crecimiento en funcion del area tiene.
La zona centro tiene el conteo de apartamentos más bajos de la ciudad, mientras que la zona sur tiene un amyor crecimiento en el conteo de estos.