Unidad 1. Métodos estadisticos para la toma de desiciones Evaluación de la oferta inmobiliaria urbana
Contexto
La actividad se va a desarrollar en el concepto de Una destacada empresa del sector inmobiliario en una metrópoli está interesada en obtener un conocimiento profundo del mercado de viviendas urbanas para tomar decisiones estratégicas más fundamentadas. La compañía cuenta con una amplia base de datos que incluye información detallada sobre diversas propiedades residenciales disponibles en el mercado. Es necesario llevar a cabo un análisis integral de estos datos para identificar patrones, relaciones y segmentaciones significativas que faciliten la mejora en la toma de decisiones relacionadas con la compra, venta y valoración de propiedades.
Metodología
En el proceso de indentificar la toma de desiciones relacionadas con la valorizacion de las propiedades de finca raiz para compra y venta se van a realizar los siguientes pasos:
Análisis descriptivo de las variables de la base de datos Vivienda suministrada.
Imputación de Datos Faltantes: Se imputaron los datos faltantes utilizando la mediana de cada columna y la mode en los ddatos categoricos.
Eliminación de Variables con Más Faltantes: Se eliminaron las columnas que tienen más del 50% de datos faltantes.
Selección de Columnas Numéricas: Se seleccionaron solo las columnas numéricas para el análisis inicial.
Escalado de Características: Se escalaron las características para que tengan media 0 y desviación estándar 1.
Análisis de Componentes Principales (PCA): Se realizó el PCA.
Análisis de Conglomerados: Se calculó la matriz de distancias y se realizó el clustering jerárquico, generando un dendrograma.
Análisis de Correspondencia : Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.
Visualización de resultados: Presentar gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.
Desarrollo y resultados
# Instalar paquetes
knitr::opts_chunk$set(echo = TRUE)
library(paqueteMODELOS)
## Cargando paquete requerido: boot
## Cargando paquete requerido: broom
## Cargando paquete requerido: GGally
## Cargando paquete requerido: ggplot2
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
## Cargando paquete requerido: gridExtra
## Cargando paquete requerido: knitr
## Cargando paquete requerido: summarytools
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.2
##
## Adjuntando el paquete: 'dplyr'
## The following object is masked from 'package:gridExtra':
##
## combine
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tidyr)
library(textshape)
## Warning: package 'textshape' was built under R version 4.4.2
##
## Adjuntando el paquete: 'textshape'
## The following object is masked from 'package:dplyr':
##
## combine
## The following object is masked from 'package:gridExtra':
##
## combine
library(mice)
## Warning: package 'mice' was built under R version 4.4.2
##
## Adjuntando el paquete: 'mice'
## The following object is masked from 'package:stats':
##
## filter
## The following objects are masked from 'package:base':
##
## cbind, rbind
library(factoextra)
## Warning: package 'factoextra' was built under R version 4.4.2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(FactoMineR)
## Warning: package 'FactoMineR' was built under R version 4.4.2
library(corrr)
## Warning: package 'corrr' was built under R version 4.4.2
library(ca)
## Warning: package 'ca' was built under R version 4.4.2
Cargue de datos
library(paqueteMODELOS)
library(paqueteMODELOS)
data("vivienda")
Análisis descriptivo
data(vivienda)
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<externalptr>
head(vivienda)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… <NA> 3 250 70 1 3 6
## 2 1169 Zona O… <NA> 3 320 120 1 2 3
## 3 1350 Zona O… <NA> 3 350 220 2 2 4
## 4 5992 Zona S… 02 4 400 280 3 5 3
## 5 1212 Zona N… 01 5 260 90 1 2 3
## 6 1724 Zona N… 01 5 240 87 1 3 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
summary(vivienda)
## id zona piso estrato
## Min. : 1 Length:8322 Length:8322 Min. :3.000
## 1st Qu.:2080 Class :character Class :character 1st Qu.:4.000
## Median :4160 Mode :character Mode :character Median :5.000
## Mean :4160 Mean :4.634
## 3rd Qu.:6240 3rd Qu.:5.000
## Max. :8319 Max. :6.000
## NA's :3 NA's :3
## preciom areaconst parqueaderos banios
## Min. : 58.0 Min. : 30.0 Min. : 1.000 Min. : 0.000
## 1st Qu.: 220.0 1st Qu.: 80.0 1st Qu.: 1.000 1st Qu.: 2.000
## Median : 330.0 Median : 123.0 Median : 2.000 Median : 3.000
## Mean : 433.9 Mean : 174.9 Mean : 1.835 Mean : 3.111
## 3rd Qu.: 540.0 3rd Qu.: 229.0 3rd Qu.: 2.000 3rd Qu.: 4.000
## Max. :1999.0 Max. :1745.0 Max. :10.000 Max. :10.000
## NA's :2 NA's :3 NA's :1605 NA's :3
## habitaciones tipo barrio longitud
## Min. : 0.000 Length:8322 Length:8322 Min. :-76.59
## 1st Qu.: 3.000 Class :character Class :character 1st Qu.:-76.54
## Median : 3.000 Mode :character Mode :character Median :-76.53
## Mean : 3.605 Mean :-76.53
## 3rd Qu.: 4.000 3rd Qu.:-76.52
## Max. :10.000 Max. :-76.46
## NA's :3 NA's :3
## latitud
## Min. :3.333
## 1st Qu.:3.381
## Median :3.416
## Mean :3.418
## 3rd Qu.:3.452
## Max. :3.498
## NA's :3
Para el analisis se identifican las variables, y se observa la base de datos tiene la variable piso como númerica, por lo cual, se va a realizar una modificación a númerica
Tabla 1. Descripcion de las variables y los datos faltantes
# Calcula la cantidad de NA's por columna
na_counts <- colSums(is.na(vivienda))
# Filtra SOLO las variables que tienen al menos un NA
variables_con_na <- names(na_counts[na_counts > 0])
# Crea la tabla SOLO con las variables que tienen NA's
tabla_faltantes <- vivienda %>%
select(all_of(variables_con_na)) %>% # Selecciona solo las columnas con NAs
summarise(across(everything(), ~sum(is.na(.)))) %>%
pivot_longer(everything(), names_to = "variable", values_to = "cantidad_faltante") %>%
mutate(porcentaje_faltante = (cantidad_faltante / nrow(vivienda)) * 100) %>% # Calcula el porcentaje
arrange(desc(cantidad_faltante))
print(tabla_faltantes)
## # A tibble: 13 × 3
## variable cantidad_faltante porcentaje_faltante
## <chr> <int> <dbl>
## 1 piso 2638 31.7
## 2 parqueaderos 1605 19.3
## 3 id 3 0.0360
## 4 zona 3 0.0360
## 5 estrato 3 0.0360
## 6 areaconst 3 0.0360
## 7 banios 3 0.0360
## 8 habitaciones 3 0.0360
## 9 tipo 3 0.0360
## 10 barrio 3 0.0360
## 11 longitud 3 0.0360
## 12 latitud 3 0.0360
## 13 preciom 2 0.0240
Descripción de los datos
La base de datos presenta 8,322 registros y 13 columnas. Las variables observadas fueron:
Variables numéricas: piso, estrato, preciom (precio en millones), areaconst (área construida), parqueaderos, banios, habitaciones, longitud, latitud.
Variables categóricas: zona, tipo, barrio.
Datos faltantes: Algunas columnas tienen valores nulos (piso, parqueaderos, etc.), lo que podría afectar los análisis, por eso se toma la desicion de imputar las que tienen menos del 20% de pérdida y de eliminar las que superan esta pedirda. Tambiés se eliminó la variabe id ya que no aporta al analisis.
# 1. Eliminar la variable "piso y ID"
vivienda <- vivienda %>%
select(-piso)
vivienda <- vivienda %>%
select(-id)
# 2. Imputar valores numéricos con la media
vivienda <- vivienda %>%
mutate(across(where(is.numeric), ~ifelse(is.na(.), mean(., na.rm = TRUE), .)))
# Verificar los cambios
summary(vivienda)
## zona estrato preciom areaconst
## Length:8322 Min. :3.000 Min. : 58.0 Min. : 30.0
## Class :character 1st Qu.:4.000 1st Qu.: 220.0 1st Qu.: 80.0
## Mode :character Median :5.000 Median : 330.0 Median : 123.0
## Mean :4.634 Mean : 433.9 Mean : 174.9
## 3rd Qu.:5.000 3rd Qu.: 540.0 3rd Qu.: 229.0
## Max. :6.000 Max. :1999.0 Max. :1745.0
## parqueaderos banios habitaciones tipo
## Min. : 1.000 Min. : 0.000 Min. : 0.000 Length:8322
## 1st Qu.: 1.000 1st Qu.: 2.000 1st Qu.: 3.000 Class :character
## Median : 1.835 Median : 3.000 Median : 3.000 Mode :character
## Mean : 1.835 Mean : 3.111 Mean : 3.605
## 3rd Qu.: 2.000 3rd Qu.: 4.000 3rd Qu.: 4.000
## Max. :10.000 Max. :10.000 Max. :10.000
## barrio longitud latitud
## Length:8322 Min. :-76.59 Min. :3.333
## Class :character 1st Qu.:-76.54 1st Qu.:3.381
## Mode :character Median :-76.53 Median :3.416
## Mean :-76.53 Mean :3.418
## 3rd Qu.:-76.52 3rd Qu.:3.452
## Max. :-76.46 Max. :3.498
# Calcular frecuencias para variables categóricas
table(vivienda$zona)
##
## Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
## 124 1920 1198 351 4726
table(vivienda$tipo)
##
## Apartamento Casa
## 5100 3219
# Histograma de la variable Precio
ggplot(vivienda, aes(x = preciom)) +
geom_histogram(binwidth = 50, fill = "blue", color = "black") +
labs(title = "Distribución de Precios", x = "Precio", y = "Frecuencia")
# Boxplot de la variable Área Construida
ggplot(vivienda, aes(y = areaconst)) +
geom_boxplot(fill = "orange", color = "black") +
labs(title = "Boxplot de Área Construida", y = "Área Construida")
Análisis de componentes principales
str(vivienda)
## spc_tbl_ [8,322 × 11] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<externalptr>
# Convertir variables categóricas en FACTORES
vivienda$zona <- as.factor(vivienda$zona)
vivienda$estrato <- as.factor(vivienda$estrato)
vivienda$tipo <- as.factor(vivienda$tipo)
vivienda$barrio <- as.factor(vivienda$barrio)
vivienda_numeric <- vivienda[sapply(vivienda, is.numeric)]
md.pattern(vivienda_numeric)
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## preciom areaconst parqueaderos banios habitaciones longitud latitud
## 8322 1 1 1 1 1 1 1 0
## 0 0 0 0 0 0 0 0
# Realizar el PCA
pca_result <- prcomp(vivienda_numeric, scale. = TRUE)
# Resumen del PCA
summary(pca_result)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.8047 1.1128 0.9200 0.8525 0.64077 0.57489 0.43646
## Proportion of Variance 0.4653 0.1769 0.1209 0.1038 0.05865 0.04721 0.02721
## Cumulative Proportion 0.4653 0.6422 0.7631 0.8669 0.92557 0.97279 1.00000
# Scree plot
screeplot(pca_result, type = "lines", main = "Scree Plot")
# Biplot
biplot(pca_result, main = "Biplot of PCA")
# Visualización con ggplot2
pca_data <- as.data.frame(pca_result$x)
pca_data$ID <- rownames(pca_data) # Add an ID column for labeling
ggplot(pca_data, aes(x = PC1, y = PC2)) +
geom_point(aes(color = ID), size = 2) +
labs(title = "PCA of Vivienda Dataset", x = "Principal Component 1", y = "Principal Component 2") +
theme_minimal()
prcomp(vivienda_numeric)
## Standard deviations (1, .., p=7):
## [1] 344.38690046 99.06645846 1.38820957 0.79425941 0.74474686
## [6] 0.04204346 0.01577032
##
## Rotation (n x k) = (7 x 7):
## PC1 PC2 PC3 PC4
## preciom 9.499401e-01 3.124218e-01 -0.0004161614 0.0024643321
## areaconst 3.124106e-01 -9.499174e-01 -0.0074257181 0.0003769577
## parqueaderos 1.879510e-03 -7.374523e-04 0.0335527569 -0.7321236699
## banios 2.863544e-03 -2.816101e-03 0.5468928721 -0.5562807713
## habitaciones 1.298375e-03 -6.406422e-03 0.8364968723 0.3930624744
## longitud -1.686869e-05 -2.070588e-05 0.0001855085 0.0011329214
## latitud -1.381126e-05 -2.097684e-05 -0.0001810464 0.0064053169
## PC5 PC6 PC7
## preciom 0.0003867844 3.929456e-06 1.856633e-05
## areaconst -0.0011208300 -1.580882e-05 -9.373124e-06
## parqueaderos 0.6803384489 1.914086e-03 -9.996347e-04
## banios -0.6256211301 6.302431e-03 1.496836e-03
## habitaciones 0.3817260093 -4.001333e-03 -1.178572e-03
## longitud 0.0024257259 8.811462e-02 9.961067e-01
## latitud 0.0039699192 9.960805e-01 -8.812922e-02
# Seleccionar solo las variables numéricas para PCA
vivienda_numeric <- vivienda[, sapply(vivienda, is.numeric)]
# Identificar las filas completas (sin valores faltantes)
filas_completas <- complete.cases(vivienda_numeric)
# Eliminar filas con valores faltantes del dataset original
vivienda <- vivienda[filas_completas, ]
# Realizar PCA
pca_result <- prcomp(vivienda_numeric[filas_completas, ], scale. = TRUE)
# Visualizar los resultados de PCA con fviz_pca_biplot
fviz_pca_biplot(pca_result,
repel = TRUE,
habillage = vivienda$tipo, # Usar la variable 'tipo' para colorear
col.var = "#034A94", # Color de las variables
col.ind = c("#DEDEDE", "#034A94")) # Color de los individuos
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).
Elección de componenetes principales
data("vivienda")
data(vivenda)
## Warning in data(vivenda): data set 'vivenda' not found
# Escalar las columnas numéricas
vivienda_numeric <- scale(vivienda_numeric[, 2:5])
# Realizar el PCA
res.pca <- prcomp(vivienda_numeric)
# Visualizar la varianza explicada
library(factoextra)
fviz_eig(res.pca, addlabels = TRUE)
Se observa como el primer componente explica el 56% de la variabilidad contenida en la base de datos, y entre las cuatro, un porcentaje alto.
fviz_pca_var(res.pca,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#FF7F00", "#034D94"),
repel = TRUE # Avoid text overlapping
)
Al visualizar las variables en el plano de los componentes principales permite identificar el sentido y la caracterización de los componentes asociado al área de construcción, parqueaderos y precio.
datos<- rbind(vivienda_numeric[98,], # ok
vivienda_numeric[12,],
vivienda_numeric[6,],
vivienda_numeric[250,])
datos <- as.data.frame(datos)
rownames(datos) = c("Vivienda 98","Vivienda 12","Vivienda 6","Vivienda 250")
datos
## areaconst parqueaderos banios habitaciones
## Vivienda 98 -0.8110835 0.0000000 -0.77825510 -0.4148373
## Vivienda 12 1.2597393 1.1525734 1.32265485 0.9557075
## Vivienda 6 -0.6151949 -0.8264234 -0.07795178 -0.4148373
## Vivienda 250 0.4551967 1.1525734 0.62235154 -0.4148373
casos1 <- rbind(res.pca$x[98,1:2],res.pca$x[12,1:2]) # CP1
rownames(casos1) = c("98","299")
casos1 <- as.data.frame(casos1)
casos2 <- rbind(res.pca$x[6,1:2], res.pca$x[250,1:2]) # CP2
rownames(casos2) = c("6","190")
casos2 <- as.data.frame(casos2)
fviz_pca_ind(res.pca, col.ind = "#DEDEDE", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
geom_point(data = casos1, aes(x = PC1, y = PC2), color = "red", size = 3) +
geom_point(data = casos2, aes(x = PC1, y = PC2), color = "blue", size = 3)
# Visualizar los resultados de PCA con fviz_pca_biplot
fviz_pca_biplot(pca_result,
repel = TRUE,
habillage = vivienda$tipo, # Usar la variable 'tipo' para colorear
col.var = "#034A94", # Color de las variables
col.ind = c("#DEDEDE", "#034A94")) # Color de los individuos
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).
Analisis de conglomerados
# Análisis de Conglomerados
# Seleccionar variables numéricas relevantes para el análisis de clúster
vivienda_numeric <- vivienda[, c("preciom", "areaconst", "estrato", "habitaciones", "banios")]
# Identificar las filas completas (sin valores faltantes)
filas_completas <- complete.cases(vivienda_numeric)
# Eliminar filas con valores faltantes del dataset original
vivienda <- vivienda[filas_completas, ]
# Estandarizar los datos
vivienda_scaled <- scale(vivienda_numeric[filas_completas, ])
# Método del codo para determinar el número óptimo de clústeres
wss <- (nrow(vivienda_scaled) - 1) * sum(apply(vivienda_scaled, 2, var))
for (i in 2:15) wss[i] <- sum(kmeans(vivienda_scaled, centers = i)$withinss)
## Warning: did not converge in 10 iterations
# Graficar el método del codo
plot(1:15, wss, type = "b", xlab = "Número de Clústeres", ylab = "Suma de Cuadrados Dentro del Clúster", main = "Método del Codo")
# Aplicar k-means con el número óptimo de clústeres (por ejemplo, 4)
set.seed(123)
kmeans_result <- kmeans(vivienda_scaled, centers = 4)
# Añadir los clústeres al dataset original
vivienda$Cluster <- as.factor(kmeans_result$cluster)
# Visualizar los clústeres en un gráfico
ggplot(vivienda, aes(x = areaconst, y = preciom, color = Cluster)) +
geom_point() +
labs(title = "Análisis de Conglomerados de Propiedades Residenciales", x = "Área Construida", y = "Precio")